From c86e48dc7d688d97a6ee4697ce01e594fa70d7db Mon Sep 17 00:00:00 2001 From: "/C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=laforge/emailAddress=laforge@netfilter.org" Date: Sat, 16 Apr 2005 13:30:56 +0000 Subject: add pablo's conntrack tool --- src/conntrack.c | 472 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/libct.c | 486 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 958 insertions(+) create mode 100644 src/conntrack.c create mode 100644 src/libct.c (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c new file mode 100644 index 0000000..dfb3849 --- /dev/null +++ b/src/conntrack.c @@ -0,0 +1,472 @@ +/* + * (C) 2005 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Note: + * Yes, portions of this code has been stolen from iptables ;) + * Special thanks to the the Netfilter Core Team. + * Thanks to Javier de Miguel Rodriguez + * for introducing me to advanced firewalling stuff. + * + * --pablo 13/04/2005 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "libctnetlink.h" +#include "libnfnetlink.h" +#include "linux_list.h" +#include "libct_proto.h" + +#define PROGNAME "conntrack" +#define VERSION "0.12" + +#if 0 +#define DEBUGP printf +#else +#define DEBUGP +#endif + +enum action { + CT_LIST_BIT = 0, + CT_LIST = (1 << CT_LIST_BIT), + + CT_CREATE_BIT = 1, + CT_CREATE = (1 << CT_CREATE_BIT), + + CT_DELETE_BIT = 2, + CT_DELETE = (1 << CT_DELETE_BIT), + + CT_GET_BIT = 3, + CT_GET = (1 << CT_GET_BIT), + + CT_FLUSH_BIT = 4, + CT_FLUSH = (1 << CT_FLUSH_BIT), + + CT_EVENT_BIT = 5, + CT_EVENT = (1 << CT_EVENT_BIT) +}; +#define NUMBER_OF_CMD 6 + +enum options { + CT_OPT_ORIG_SRC_BIT = 0, + CT_OPT_ORIG_SRC = (1 << CT_OPT_ORIG_SRC_BIT), + + CT_OPT_ORIG_DST_BIT = 1, + CT_OPT_ORIG_DST = (1 << CT_OPT_ORIG_DST_BIT), + + CT_OPT_ORIG = (CT_OPT_ORIG_SRC | CT_OPT_ORIG_DST), + + CT_OPT_REPL_SRC_BIT = 2, + CT_OPT_REPL_SRC = (1 << CT_OPT_REPL_SRC_BIT), + + CT_OPT_REPL_DST_BIT = 3, + CT_OPT_REPL_DST = (1 << CT_OPT_REPL_DST_BIT), + + CT_OPT_REPL = (CT_OPT_REPL_SRC | CT_OPT_REPL_DST), + + CT_OPT_PROTO_BIT = 4, + CT_OPT_PROTO = (1 << CT_OPT_PROTO_BIT), + + CT_OPT_ID_BIT = 5, + CT_OPT_ID = (1 << CT_OPT_ID_BIT), + + CT_OPT_TIMEOUT_BIT = 6, + CT_OPT_TIMEOUT = (1 << CT_OPT_TIMEOUT_BIT), + + CT_OPT_STATUS_BIT = 7, + CT_OPT_STATUS = (1 << CT_OPT_STATUS_BIT), +}; +#define NUMBER_OF_OPT 8 + +static const char optflags[NUMBER_OF_OPT] += { 's', 'd', 'r', 'q', 'p', 'i', 't', 'u'}; + +static struct option original_opts[] = { + {"dump", 1, 0, 'L'}, + {"create", 1, 0, 'I'}, + {"delete", 1, 0, 'D'}, + {"get", 1, 0, 'G'}, + {"flush", 1, 0, 'F'}, + {"event", 1, 0, 'E'}, + {"orig-src", 1, 0, 's'}, + {"orig-dst", 1, 0, 'd'}, + {"reply-src", 1, 0, 'r'}, + {"reply-dst", 1, 0, 'q'}, + {"protonum", 1, 0, 'p'}, + {"timeout", 1, 0, 't'}, + {"id", 1, 0, 'i'}, + {"status", 1, 0, 'u'}, + {0, 0, 0, 0} +}; + +#define OPTION_OFFSET 256 + +static struct option *opts = original_opts; +static unsigned int global_option_offset = 0; + +/* Table of legal combinations of commands and options. If any of the + * given commands make an option legal, that option is legal (applies to + * CMD_LIST and CMD_ZERO only). + * Key: + * + compulsory + * x illegal + * optional + */ + +static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = +/* Well, it's better than "Re: Linux vs FreeBSD" */ +{ + /* -s -d -r -q -p -i -t -u*/ +/*LIST*/ {'x','x','x','x','x','x','x','x'}, +/*CREATE*/ {'+','+','+','+','+','x','+','+'}, +/*DELETE*/ {' ',' ',' ',' ',' ','+','x','x'}, +/*GET*/ {' ',' ',' ',' ','+','+','x','x'}, +/*FLUSH*/ {'x','x','x','x','x','x','x','x'}, +/*EVENT*/ {'x','x','x','x','x','x','x','x'} +}; + +LIST_HEAD(proto_list); + +char *proto2str[] = { + [IPPROTO_TCP] = "tcp", + [IPPROTO_UDP] = "udp", + [IPPROTO_ICMP] = "icmp", + [IPPROTO_SCTP] = "sctp" +}; + +enum exittype { + OTHER_PROBLEM = 1, + PARAMETER_PROBLEM, + VERSION_PROBLEM +}; + +void +exit_tryhelp(int status) +{ + fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n", + PROGNAME, PROGNAME); + exit(status); +} + +static void +exit_error(enum exittype status, char *msg, ...) +{ + va_list args; + + /* On error paths, make sure that we don't leak the memory + * reserved during options merging */ + if (opts != original_opts) { + free(opts); + opts = original_opts; + global_option_offset = 0; + } + va_start(args, msg); + fprintf(stderr, "%s v%s: ", PROGNAME, VERSION); + vfprintf(stderr, msg, args); + va_end(args); + fprintf(stderr, "\n"); + if (status == PARAMETER_PROBLEM) + exit_tryhelp(status); + exit(status); +} + +static void +generic_opt_check(int command, int options) +{ + int i, j, legal = 0; + + /* Check that commands are valid with options. Complicated by the + * fact that if an option is legal with *any* command given, it is + * legal overall (ie. -z and -l). + */ + for (i = 0; i < NUMBER_OF_OPT; i++) { + legal = 0; /* -1 => illegal, 1 => legal, 0 => undecided. */ + + for (j = 0; j < NUMBER_OF_CMD; j++) { + if (!(command & (1<protonum; + reply.dst.protonum = h->protonum; + opts = merge_options(opts, h->opts, + &h->option_offset); + break; + case 'i': + options |= CT_OPT_ID; + id = atoi(optarg); + break; + case 't': + options |= CT_OPT_TIMEOUT; + if (optarg) + timeout = atol(optarg); + break; + case 'u': { + /* FIXME: NAT stuff, later... */ + if (!optarg) + continue; + + options |= CT_OPT_STATUS; + /* Just insert confirmed conntracks */ + status |= IPS_CONFIRMED; + if (strncmp("SEEN_REPLY", optarg, strlen("SEEN_REPLY")) == 0) + status |= IPS_SEEN_REPLY; + else if (strncmp("ASSURED", optarg, strlen("ASSURED")) == 0) + status |= IPS_ASSURED; + else + exit_error(PARAMETER_PROBLEM, "Invalid status" + "flag: %s\n", optarg); + break; + } + default: + if (h && !h->parse(c - h->option_offset, argv, + &orig, &reply)) + exit_error(PARAMETER_PROBLEM, "parse error\n"); + + /* Unknown argument... */ + if (!h) { + usage(argv[0]); + exit_error(PARAMETER_PROBLEM, "Missing " + "arguments...\n"); + } + break; + } + } + + generic_opt_check(command, options); + + switch(command) { + case CT_LIST: + printf("list\n"); + if (type == 0) + dump_conntrack_table(); + else + dump_expect_list(); + break; + case CT_CREATE: + printf("create\n"); + if (type == 0) + create_conntrack(&orig, &reply, timeout, + &proto, status); + else + not_implemented_yet(); + break; + case CT_DELETE: + printf("delete\n"); + if (type == 0) { + if (options & CT_OPT_ORIG) + delete_conntrack(&orig, CTA_ORIG, id); + else if (options & CT_OPT_REPL) + delete_conntrack(&reply, CTA_RPLY, id); + } else + not_implemented_yet(); + break; + case CT_GET: + printf("get\n"); + if (type == 0) { + if (options & CT_OPT_ORIG) + get_conntrack(&orig, CTA_ORIG, id); + else if (options & CT_OPT_REPL) + get_conntrack(&reply, CTA_RPLY, id); + } else + not_implemented_yet(); + break; + case CT_FLUSH: + not_implemented_yet(); + break; + case CT_EVENT: + printf("event\n"); + if (type == 0) + event_conntrack(); + else + /* and surely it won't ever... */ + not_implemented_yet(); + default: + usage(argv[0]); + break; + } + + if (opts != original_opts) { + free(opts); + opts = original_opts; + global_option_offset = 0; + } +} diff --git a/src/libct.c b/src/libct.c new file mode 100644 index 0000000..3828c0c --- /dev/null +++ b/src/libct.c @@ -0,0 +1,486 @@ +#include +#include +#include +#include +#include +#include +#include +#include "libctnetlink.h" +#include "libnfnetlink.h" +#include "linux_list.h" +#include "libct_proto.h" + +#if 0 +#define DEBUGP printf +#else +#define DEBUGP +#endif + +extern struct list_head proto_list; +extern char *proto2str[]; + +/* Built-in generic proto handler */ + +/* FIXME: This should die... */ +static int parse(char c, char *argv[], + struct ip_conntrack_tuple *orig, + struct ip_conntrack_tuple *reply) { + return 0; +} +/* FIXME: die die too... */ +static void print(struct ip_conntrack_tuple *t) {} + +static struct ctproto_handler generic_handler = { + .name = "generic", + .protonum = 0, + .parse = parse, + .print = print, + .opts = NULL +}; + +static int handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void *arg) +{ + struct nfgenmsg *nfmsg; + struct nfattr *nfa; + int min_len = 0; + struct ctproto_handler *h = NULL; + + DEBUGP("netlink header\n"); + DEBUGP("len: %d type: %d flags: %d seq: %d pid: %d\n", + nlh->nlmsg_len, nlh->nlmsg_type, nlh->nlmsg_flags, + nlh->nlmsg_seq, nlh->nlmsg_pid); + + nfmsg = NLMSG_DATA(nlh); + DEBUGP("nfmsg->nfgen_family: %d\n", nfmsg->nfgen_family); + + min_len = sizeof(struct nfgenmsg); + if (nlh->nlmsg_len < min_len) + return -EINVAL; + + DEBUGP("size:%d\n", nlh->nlmsg_len); + + while (nlh->nlmsg_len > min_len) { + struct nfattr *attr = NFM_NFA(NLMSG_DATA(nlh)); + int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); + + struct ip_conntrack_tuple *orig, *reply; + unsigned long *status, *timeout; + struct cta_proto *proto; + unsigned long *id; + + while (NFA_OK(attr, attrlen)) { + switch(attr->nfa_type) { + case CTA_ORIG: + orig = NFA_DATA(attr); + printf("src=%u.%u.%u.%u dst=%u.%u.%u.%u ", + NIPQUAD(orig->src.ip), + NIPQUAD(orig->dst.ip)); + h = findproto(proto2str[orig->dst.protonum]); + if (h) + h->print(orig); + break; + case CTA_RPLY: + reply = NFA_DATA(attr); + printf("src=%u.%u.%u.%u dst=%u.%u.%u.%u ", + NIPQUAD(reply->src.ip), + NIPQUAD(reply->dst.ip)); + h = findproto(proto2str[reply->dst.protonum]); + if (h) + h->print(reply); + break; + case CTA_STATUS: + status = NFA_DATA(attr); + printf("status:%u ", *status); + break; + case CTA_PROTOINFO: + proto = NFA_DATA(attr); + if (proto2str[proto->num_proto]) + printf("%s %d", proto2str[proto->num_proto], proto->num_proto); + else + printf("unknown %d ", proto->num_proto); + break; + case CTA_TIMEOUT: + timeout = NFA_DATA(attr); + printf("timeout:%lu ", *timeout); + break; +/* case CTA_ID: + id = NFA_DATA(attr); + printf(" id:%lu ", *id); + break;*/ + } + DEBUGP("nfa->nfa_type: %d\n", attr->nfa_type); + DEBUGP("nfa->nfa_len: %d\n", attr->nfa_len); + attr = NFA_NEXT(attr, attrlen); + } + min_len += nlh->nlmsg_len; + nlh = (struct nlmsghdr *) attr; + printf("\n"); + } + DEBUGP("exit from handler\n"); + + return 0; +} + +/* FIXME: use event messages better */ +static char *typemsg2str[] = { + "NEW", + "GET", + "DESTROY" +}; + +static int event_handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, + void *arg) +{ + struct nfgenmsg *nfmsg; + struct nfattr *nfa; + int min_len = 0; + struct ctproto_handler *h = NULL; + int type = NFNL_MSG_TYPE(nlh->nlmsg_type); + + DEBUGP("netlink header\n"); + DEBUGP("len: %d type: %d flags: %d seq: %d pid: %d\n", + nlh->nlmsg_len, nlh->nlmsg_type, nlh->nlmsg_flags, + nlh->nlmsg_seq, nlh->nlmsg_pid); + + nfmsg = NLMSG_DATA(nlh); + DEBUGP("nfmsg->nfgen_family: %d\n", nfmsg->nfgen_family); + + min_len = sizeof(struct nfgenmsg); + if (nlh->nlmsg_len < min_len) + return -EINVAL; + + DEBUGP("size:%d\n", nlh->nlmsg_len); + + printf("type: [%s] ", typemsg2str[type]); + + while (nlh->nlmsg_len > min_len) { + struct nfattr *attr = NFM_NFA(NLMSG_DATA(nlh)); + int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); + + struct ip_conntrack_tuple *orig, *reply; + unsigned long *status, *timeout; + struct cta_proto *proto; + unsigned long *id; + + while (NFA_OK(attr, attrlen)) { + switch(attr->nfa_type) { + case CTA_ORIG: + orig = NFA_DATA(attr); + printf("src=%u.%u.%u.%u dst=%u.%u.%u.%u ", + NIPQUAD(orig->src.ip), + NIPQUAD(orig->dst.ip)); + h = findproto(proto2str[orig->dst.protonum]); + if (h) + h->print(orig); + break; + case CTA_RPLY: + reply = NFA_DATA(attr); + printf("src=%u.%u.%u.%u dst=%u.%u.%u.%u ", + NIPQUAD(reply->src.ip), + NIPQUAD(reply->dst.ip)); + h = findproto(proto2str[reply->dst.protonum]); + if (h) + h->print(reply); + break; + case CTA_STATUS: + status = NFA_DATA(attr); + printf("status:%u ", *status); + break; + case CTA_PROTOINFO: + proto = NFA_DATA(attr); + if (proto2str[proto->num_proto]) + printf("%s %d", proto2str[proto->num_proto], proto->num_proto); + else + printf("unknown %d ", proto->num_proto); + break; + case CTA_TIMEOUT: + timeout = NFA_DATA(attr); + printf("timeout:%lu ", *timeout); + break; +/* case CTA_ID: + id = NFA_DATA(attr); + printf(" id:%lu ", *id); + break;*/ + } + DEBUGP("nfa->nfa_type: %d\n", attr->nfa_type); + DEBUGP("nfa->nfa_len: %d\n", attr->nfa_len); + attr = NFA_NEXT(attr, attrlen); + } + min_len += nlh->nlmsg_len; + nlh = (struct nlmsghdr *) attr; + printf("\n"); + } + DEBUGP("exit from handler\n"); + + return 0; +} + +static int expect_handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void *arg) +{ + struct nfgenmsg *nfmsg; + struct nfattr *nfa; + int min_len = 0; + struct ctproto_handler *h = NULL; + + DEBUGP("netlink header\n"); + DEBUGP("len: %d type: %d flags: %d seq: %d pid: %d\n", + nlh->nlmsg_len, nlh->nlmsg_type, nlh->nlmsg_flags, + nlh->nlmsg_seq, nlh->nlmsg_pid); + + nfmsg = NLMSG_DATA(nlh); + DEBUGP("nfmsg->nfgen_family: %d\n", nfmsg->nfgen_family); + + min_len = sizeof(struct nfgenmsg); + if (nlh->nlmsg_len < min_len) + return -EINVAL; + + DEBUGP("size:%d\n", nlh->nlmsg_len); + + while (nlh->nlmsg_len > min_len) { + struct nfattr *attr = NFM_NFA(NLMSG_DATA(nlh)); + int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); + + struct ip_conntrack_tuple *exp, *mask; + unsigned long *timeout; + + while (NFA_OK(attr, attrlen)) { + switch(attr->nfa_type) { + case CTA_EXP_TUPLE: + exp = NFA_DATA(attr); + printf("src=%u.%u.%u.%u dst=%u.%u.%u.%u ", + NIPQUAD(exp->src.ip), + NIPQUAD(exp->dst.ip)); + h = findproto(proto2str[exp->dst.protonum]); + if (h) + h->print(exp); + break; + case CTA_EXP_MASK: + mask = NFA_DATA(attr); + printf("src=%u.%u.%u.%u dst=%u.%u.%u.%u ", + NIPQUAD(mask->src.ip), + NIPQUAD(mask->dst.ip)); + h = findproto(proto2str[mask->dst.protonum]); + if (h) + h->print(mask); + break; + case CTA_EXP_TIMEOUT: + timeout = NFA_DATA(attr); + printf("timeout:%lu ", *timeout); + break; + } + DEBUGP("nfa->nfa_type: %d\n", attr->nfa_type); + DEBUGP("nfa->nfa_len: %d\n", attr->nfa_len); + attr = NFA_NEXT(attr, attrlen); + } + min_len += nlh->nlmsg_len; + nlh = (struct nlmsghdr *) attr; + printf("\n"); + } + DEBUGP("exit from handler\n"); + + return 0; +} + +void create_conntrack(struct ip_conntrack_tuple *orig, + struct ip_conntrack_tuple *reply, + unsigned long timeout, + union ip_conntrack_proto *proto, + unsigned int status) +{ + struct cta_proto cta; + struct nfattr *cda[CTA_MAX]; + struct ctnl_handle cth; + + cta.num_proto = orig->dst.protonum; + memcpy(&cta.proto, proto, sizeof(*proto)); + if (ctnl_open(&cth, 0) < 0) { + printf("error\n"); + exit(0); + } + + /* FIXME: please unify returns values... */ + if (ctnl_new_conntrack(&cth, orig, reply, timeout, proto, status) < 0) { + printf("error new conntrack\n"); + exit(0); + } + + if (ctnl_close(&cth) < 0) { + printf("error2"); + exit(0); + } +} + +void delete_conntrack(struct ip_conntrack_tuple *tuple, + enum ctattr_type_t t, + unsigned long id) +{ + struct nfattr *cda[CTA_MAX]; + struct ctnl_handle cth; + + if (ctnl_open(&cth, 0) < 0) { + printf("error\n"); + exit(0); + } + + /* FIXME: please unify returns values... */ + if (ctnl_del_conntrack(&cth, tuple, t, id) < 0) { + printf("error del conntrack\n"); + exit(0); + } + + if (ctnl_close(&cth) < 0) { + printf("error2"); + exit(0); + } +} + +/* get_conntrack_handler */ +void get_conntrack(struct ip_conntrack_tuple *tuple, + enum ctattr_type_t t, + unsigned long id) +{ + struct nfattr *cda[CTA_MAX]; + struct ctnl_handle cth; + struct ctnl_msg_handler h = { + .type = 0, + .handler = handler + }; + + if (ctnl_open(&cth, 0) < 0) { + printf("error\n"); + exit(0); + } + + ctnl_register_handler(&cth, &h); + + /* FIXME!!!! get_conntrack_handler returns -100 */ + if (ctnl_get_conntrack(&cth, tuple, t, id) != -100) { + printf("error get conntrack\n"); + exit(0); + } + + if (ctnl_close(&cth) < 0) { + printf("error2"); + exit(0); + } +} + +void dump_conntrack_table() +{ + struct ctnl_handle cth; + struct ctnl_msg_handler h = { + .type = 0, /* Hm... really? */ + .handler = handler + }; + + if (ctnl_open(&cth, 0) < 0) { + printf("error\n"); + exit(0); + } + + ctnl_register_handler(&cth, &h); + + if (ctnl_list_conntrack(&cth, AF_INET) != -100) { + printf("error list\n"); + exit(0); + } + + if (ctnl_close(&cth) < 0) { + printf("error2\n"); + exit(0); + } +} + +void event_conntrack() +{ + struct ctnl_handle cth; + struct ctnl_msg_handler hnew = { + .type = 0, /* new */ + .handler = event_handler + }; + struct ctnl_msg_handler hdestroy = { + .type = 2, /* destroy */ + .handler = event_handler + }; + + if (ctnl_open(&cth, NFGRP_IPV4_CT_TCP) < 0) { + printf("error\n"); + exit(0); + } + + ctnl_register_handler(&cth, &hnew); + ctnl_register_handler(&cth, &hdestroy); + ctnl_event_conntrack(&cth, AF_INET); + + if (ctnl_close(&cth) < 0) { + printf("error2\n"); + exit(0); + } +} + +struct ctproto_handler *findproto(char *name) +{ + void *h = NULL; + struct list_head *i; + struct ctproto_handler *cur = NULL, *handler = NULL; + + list_for_each(i, &proto_list) { + cur = (struct ctproto_handler *) i; + if (strcmp(cur->name, name) == 0) { + handler = cur; + break; + } + } + + if (!handler) { + char path[sizeof("extensions/libct_proto_.so") + + strlen(name)]; + sprintf(path, "extensions/libct_proto_%s.so", name); + if (dlopen(path, RTLD_NOW)) + handler = findproto(name); +/* else + fprintf (stderr, "%s\n", dlerror());*/ + } + + if (!handler) + handler = &generic_handler; + + return handler; +} + +void register_proto(struct ctproto_handler *h) +{ + list_add(&h->head, &proto_list); +} + +void unregister_proto(struct ctproto_handler *h) +{ + list_del(&h->head); +} + +void dump_expect_list() +{ + struct ctnl_handle cth; + struct ctnl_msg_handler h = { + .type = 0, /* Hm... really? */ + .handler = expect_handler + }; + + if (ctnl_open(&cth, 0) < 0) { + printf("error\n"); + exit(0); + } + + ctnl_register_handler(&cth, &h); + + if (ctnl_list_expect(&cth, AF_INET) != -100) { + printf("error list\n"); + exit(0); + } + + if (ctnl_close(&cth) < 0) { + printf("error2\n"); + exit(0); + } +} + -- cgit v1.2.3 From ad65e17d206aaf8b9fed9a32ac3158ced49bee03 Mon Sep 17 00:00:00 2001 From: "/C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=laforge/emailAddress=laforge@netfilter.org" Date: Sat, 16 Apr 2005 13:32:44 +0000 Subject: - add support for new list-conntrack-and-zero-counters flag (-z) - distinguish between real NEW and UPDATE messages in event log - add support to print the conntrack mark --- src/conntrack.c | 43 ++++++++++++++++++++++++------------ src/libct.c | 68 ++++++++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 82 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index dfb3849..d276c17 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -22,6 +22,10 @@ * for introducing me to advanced firewalling stuff. * * --pablo 13/04/2005 + * + * 2005-04-16 Harald Welte : + * Add support for conntrack accounting and conntrack mark + * */ #include #include @@ -37,7 +41,7 @@ #include "libct_proto.h" #define PROGNAME "conntrack" -#define VERSION "0.12" +#define VERSION "0.13" #if 0 #define DEBUGP printf @@ -94,11 +98,14 @@ enum options { CT_OPT_STATUS_BIT = 7, CT_OPT_STATUS = (1 << CT_OPT_STATUS_BIT), + + CT_OPT_ZERO_BIT = 8, + CT_OPT_ZERO = (1 << CT_OPT_ZERO_BIT), }; -#define NUMBER_OF_OPT 8 +#define NUMBER_OF_OPT 9 static const char optflags[NUMBER_OF_OPT] -= { 's', 'd', 'r', 'q', 'p', 'i', 't', 'u'}; += { 's', 'd', 'r', 'q', 'p', 'i', 't', 'u', 'z'}; static struct option original_opts[] = { {"dump", 1, 0, 'L'}, @@ -115,6 +122,7 @@ static struct option original_opts[] = { {"timeout", 1, 0, 't'}, {"id", 1, 0, 'i'}, {"status", 1, 0, 'u'}, + {"zero", 0, 0, 'z'}, {0, 0, 0, 0} }; @@ -135,13 +143,13 @@ static unsigned int global_option_offset = 0; static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = /* Well, it's better than "Re: Linux vs FreeBSD" */ { - /* -s -d -r -q -p -i -t -u*/ -/*LIST*/ {'x','x','x','x','x','x','x','x'}, -/*CREATE*/ {'+','+','+','+','+','x','+','+'}, -/*DELETE*/ {' ',' ',' ',' ',' ','+','x','x'}, -/*GET*/ {' ',' ',' ',' ','+','+','x','x'}, -/*FLUSH*/ {'x','x','x','x','x','x','x','x'}, -/*EVENT*/ {'x','x','x','x','x','x','x','x'} + /* -s -d -r -q -p -i -t -u -z */ +/*LIST*/ {'x','x','x','x','x','x','x','x',' '}, +/*CREATE*/ {'+','+','+','+','+','x','+','+','x'}, +/*DELETE*/ {' ',' ',' ',' ',' ','+','x','x','x'}, +/*GET*/ {' ',' ',' ',' ','+','+','x','x','x'}, +/*FLUSH*/ {'x','x','x','x','x','x','x','x','x'}, +/*EVENT*/ {'x','x','x','x','x','x','x','x','x'} }; LIST_HEAD(proto_list); @@ -293,6 +301,7 @@ printf("-p Layer 4 Protocol\n"); printf("-t Timeout\n"); printf("-i Conntrack ID\n"); printf("-u Status\n"); +printf("-z Zero Counters\n"); } int main(int argc, char *argv[]) @@ -314,7 +323,7 @@ int main(int argc, char *argv[]) reply.dst.dir = IP_CT_DIR_REPLY; while ((c = getopt_long(argc, argv, - "L:I:D:G:E:s:d:r:q:p:i:t:u:", opts, NULL)) != -1) { + "L:I:D:G:E:s:d:r:q:p:i:t:u:z", opts, NULL)) != -1) { switch(c) { case 'L': command |= CT_LIST; @@ -396,6 +405,9 @@ int main(int argc, char *argv[]) "flag: %s\n", optarg); break; } + case 'z': + options |= CT_OPT_ZERO; + break; default: if (h && !h->parse(c - h->option_offset, argv, &orig, &reply)) @@ -416,9 +428,12 @@ int main(int argc, char *argv[]) switch(command) { case CT_LIST: printf("list\n"); - if (type == 0) - dump_conntrack_table(); - else + if (type == 0) { + if (options & CT_OPT_ZERO) + dump_conntrack_table(1); + else + dump_conntrack_table(0); + } else dump_expect_list(); break; case CT_CREATE: diff --git a/src/libct.c b/src/libct.c index 3828c0c..47743d8 100644 --- a/src/libct.c +++ b/src/libct.c @@ -64,9 +64,10 @@ static int handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void *arg) int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); struct ip_conntrack_tuple *orig, *reply; + struct cta_counters *ctr; unsigned long *status, *timeout; struct cta_proto *proto; - unsigned long *id; + unsigned long *id, *mark; while (NFA_OK(attr, attrlen)) { switch(attr->nfa_type) { @@ -90,23 +91,34 @@ static int handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void *arg) break; case CTA_STATUS: status = NFA_DATA(attr); - printf("status:%u ", *status); + printf("status=%u ", *status); break; case CTA_PROTOINFO: proto = NFA_DATA(attr); if (proto2str[proto->num_proto]) - printf("%s %d", proto2str[proto->num_proto], proto->num_proto); + printf("%s %d ", proto2str[proto->num_proto], proto->num_proto); else printf("unknown %d ", proto->num_proto); break; case CTA_TIMEOUT: timeout = NFA_DATA(attr); - printf("timeout:%lu ", *timeout); + printf("timeout=%lu ", *timeout); break; /* case CTA_ID: id = NFA_DATA(attr); printf(" id:%lu ", *id); break;*/ + case CTA_MARK: + mark = NFA_DATA(attr); + printf("mark=%lu ", *mark); + break; + case CTA_COUNTERS: + ctr = NFA_DATA(attr); + printf("orig_packets=%lu orig_bytes=%lu, " + "reply_packets=%lu reply_bytes=%lu ", + ctr->orig.packets, ctr->orig.bytes, + ctr->reply.packets, ctr->reply.bytes); + break; } DEBUGP("nfa->nfa_type: %d\n", attr->nfa_type); DEBUGP("nfa->nfa_len: %d\n", attr->nfa_len); @@ -121,12 +133,20 @@ static int handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void *arg) return 0; } -/* FIXME: use event messages better */ -static char *typemsg2str[] = { - "NEW", - "GET", - "DESTROY" -}; +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 event_handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void *arg) @@ -151,14 +171,15 @@ static int event_handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, DEBUGP("size:%d\n", nlh->nlmsg_len); - printf("type: [%s] ", typemsg2str[type]); + printf("type: [%s] ", typemsg2str(type, nlh->nlmsg_flags)); while (nlh->nlmsg_len > min_len) { struct nfattr *attr = NFM_NFA(NLMSG_DATA(nlh)); int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); struct ip_conntrack_tuple *orig, *reply; - unsigned long *status, *timeout; + struct cta_counters *ctr; + unsigned long *status, *timeout, *mark; struct cta_proto *proto; unsigned long *id; @@ -189,7 +210,7 @@ static int event_handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, case CTA_PROTOINFO: proto = NFA_DATA(attr); if (proto2str[proto->num_proto]) - printf("%s %d", proto2str[proto->num_proto], proto->num_proto); + printf("%s %d ", proto2str[proto->num_proto], proto->num_proto); else printf("unknown %d ", proto->num_proto); break; @@ -201,6 +222,17 @@ static int event_handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, id = NFA_DATA(attr); printf(" id:%lu ", *id); break;*/ + case CTA_MARK: + mark = NFA_DATA(attr); + printf("mark=%lu ", *mark); + break; + case CTA_COUNTERS: + ctr = NFA_DATA(attr); + printf("orig_packets=%lu orig_bytes=%lu, " + "reply_packets=%lu reply_bytes=%lu ", + ctr->orig.packets, ctr->orig.bytes, + ctr->reply.packets, ctr->reply.bytes); + break; } DEBUGP("nfa->nfa_type: %d\n", attr->nfa_type); DEBUGP("nfa->nfa_len: %d\n", attr->nfa_len); @@ -365,8 +397,9 @@ void get_conntrack(struct ip_conntrack_tuple *tuple, } } -void dump_conntrack_table() +void dump_conntrack_table(int zero) { + int ret; struct ctnl_handle cth; struct ctnl_msg_handler h = { .type = 0, /* Hm... really? */ @@ -380,7 +413,12 @@ void dump_conntrack_table() ctnl_register_handler(&cth, &h); - if (ctnl_list_conntrack(&cth, AF_INET) != -100) { + if (zero) { + ret = ctnl_list_conntrack_zero_counters(&cth, AF_INET); + } else + ret = ctnl_list_conntrack(&cth, AF_INET); + + if (ret != -100) { printf("error list\n"); exit(0); } -- cgit v1.2.3 From 21ed4ac1f957f1e4d7be195a98fb235de13ede21 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: Mon, 25 Apr 2005 10:01:10 +0000 Subject: Major resync --- extensions/libct_proto_tcp.c | 64 +++++- extensions/libct_proto_udp.c | 4 +- include/libct_proto.h | 9 +- src/conntrack.c | 365 ++++++++++++++++++++++++------- src/libct.c | 511 ++++++++++++++++++++----------------------- 5 files changed, 587 insertions(+), 366 deletions(-) (limited to 'src') diff --git a/extensions/libct_proto_tcp.c b/extensions/libct_proto_tcp.c index 521a170..3366da4 100644 --- a/extensions/libct_proto_tcp.c +++ b/extensions/libct_proto_tcp.c @@ -11,29 +11,83 @@ static struct option opts[] = { {"orig-port-dst", 1, 0, '2'}, {"reply-port-src", 1, 0, '3'}, {"reply-port-dst", 1, 0, '4'}, + {"state", 1, 0, '5'}, {0, 0, 0, 0} }; +enum tcp_param_flags { + ORIG_SPORT_BIT = 0, + ORIG_SPORT = (1 << ORIG_SPORT_BIT), + + ORIG_DPORT_BIT = 1, + ORIG_DPORT = (1 << ORIG_DPORT_BIT), + + REPL_SPORT_BIT = 2, + REPL_SPORT = (1 << REPL_SPORT_BIT), + + REPL_DPORT_BIT = 3, + REPL_DPORT = (1 << REPL_DPORT_BIT), + + STATE_BIT = 4, + STATE = (1 << STATE_BIT) +}; + +static const char *states[] = { + "NONE", + "SYN_SENT", + "SYN_RECV", + "ESTABLISHED", + "FIN_WAIT", + "CLOSE_WAIT", + "LAST_ACK", + "TIME_WAIT", + "CLOSE", + "LISTEN" +}; + int parse(char c, char *argv[], struct ip_conntrack_tuple *orig, - struct ip_conntrack_tuple *reply) + struct ip_conntrack_tuple *reply, + union ip_conntrack_proto *proto, + unsigned int *flags) { switch(c) { case '1': - if (optarg) + if (optarg) { orig->src.u.tcp.port = htons(atoi(optarg)); + *flags |= ORIG_SPORT; + } break; case '2': - if (optarg) + if (optarg) { orig->dst.u.tcp.port = htons(atoi(optarg)); + *flags |= ORIG_DPORT; + } break; case '3': - if (optarg) + if (optarg) { reply->src.u.tcp.port = htons(atoi(optarg)); + *flags |= REPL_SPORT; + } break; case '4': - if (optarg) + if (optarg) { reply->dst.u.tcp.port = htons(atoi(optarg)); + *flags |= REPL_DPORT; + } + break; + case '5': + if (optarg) { + int i; + for (i=0; i<10; i++) { + if (strcmp(optarg, states[i]) == 0) { + proto->tcp.state = i; + break; + } + } + if (i == 10) + printf("doh?\n"); + } break; } return 1; diff --git a/extensions/libct_proto_udp.c b/extensions/libct_proto_udp.c index 8022913..cf91934 100644 --- a/extensions/libct_proto_udp.c +++ b/extensions/libct_proto_udp.c @@ -16,7 +16,9 @@ static struct option opts[] = { int parse(char c, char *argv[], struct ip_conntrack_tuple *orig, - struct ip_conntrack_tuple *reply) + struct ip_conntrack_tuple *reply, + union ip_conntrack_proto *proto, + unsigned int *flags) { switch(c) { case '1': diff --git a/include/libct_proto.h b/include/libct_proto.h index 410a812..416d916 100644 --- a/include/libct_proto.h +++ b/include/libct_proto.h @@ -10,10 +10,15 @@ struct ctproto_handler { char *name; u_int16_t protonum; - int (*parse)(char c, char *argv[], struct ip_conntrack_tuple *orig, - struct ip_conntrack_tuple *reply); + int (*parse)(char c, char *argv[], + struct ip_conntrack_tuple *orig, + struct ip_conntrack_tuple *reply, + union ip_conntrack_proto *proto, + unsigned int *flags); void (*print)(struct ip_conntrack_tuple *t); + int (*final_check)(unsigned int flags); + struct option *opts; unsigned int option_offset; diff --git a/src/conntrack.c b/src/conntrack.c index d276c17..2c716f7 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -28,11 +28,16 @@ * */ #include +#include +#include #include #include #include #include #include +#include +#include +#include #include #include #include "libctnetlink.h" @@ -41,7 +46,7 @@ #include "libct_proto.h" #define PROGNAME "conntrack" -#define VERSION "0.13" +#define VERSION "0.25" #if 0 #define DEBUGP printf @@ -49,6 +54,10 @@ #define DEBUGP #endif +#ifndef PROC_SYS_MODPROBE +#define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe" +#endif + enum action { CT_LIST_BIT = 0, CT_LIST = (1 << CT_LIST_BIT), @@ -66,9 +75,12 @@ enum action { CT_FLUSH = (1 << CT_FLUSH_BIT), CT_EVENT_BIT = 5, - CT_EVENT = (1 << CT_EVENT_BIT) + CT_EVENT = (1 << CT_EVENT_BIT), + + CT_ACTION_BIT = 6, + CT_ACTION = (1 << CT_ACTION_BIT) }; -#define NUMBER_OF_CMD 6 +#define NUMBER_OF_CMD 7 enum options { CT_OPT_ORIG_SRC_BIT = 0, @@ -101,19 +113,26 @@ enum options { CT_OPT_ZERO_BIT = 8, CT_OPT_ZERO = (1 << CT_OPT_ZERO_BIT), + + CT_OPT_DUMP_MASK_BIT = 9, + CT_OPT_DUMP_MASK = (1 << CT_OPT_DUMP_MASK_BIT), + + CT_OPT_EVENT_MASK_BIT = 10, + CT_OPT_EVENT_MASK = (1 << CT_OPT_EVENT_MASK_BIT), }; -#define NUMBER_OF_OPT 9 +#define NUMBER_OF_OPT 11 static const char optflags[NUMBER_OF_OPT] -= { 's', 'd', 'r', 'q', 'p', 'i', 't', 'u', 'z'}; += { 's', 'd', 'r', 'q', 'p', 'i', 't', 'u', 'z','m','g'}; static struct option original_opts[] = { - {"dump", 1, 0, 'L'}, + {"dump", 2, 0, 'L'}, {"create", 1, 0, 'I'}, {"delete", 1, 0, 'D'}, {"get", 1, 0, 'G'}, {"flush", 1, 0, 'F'}, {"event", 1, 0, 'E'}, + {"action", 1, 0, 'A'}, {"orig-src", 1, 0, 's'}, {"orig-dst", 1, 0, 'd'}, {"reply-src", 1, 0, 'r'}, @@ -123,6 +142,8 @@ static struct option original_opts[] = { {"id", 1, 0, 'i'}, {"status", 1, 0, 'u'}, {"zero", 0, 0, 'z'}, + {"dump-mask", 1, 0, 'm'}, + {"groups", 1, 0, 'g'}, {0, 0, 0, 0} }; @@ -143,13 +164,14 @@ static unsigned int global_option_offset = 0; static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = /* Well, it's better than "Re: Linux vs FreeBSD" */ { - /* -s -d -r -q -p -i -t -u -z */ -/*LIST*/ {'x','x','x','x','x','x','x','x',' '}, -/*CREATE*/ {'+','+','+','+','+','x','+','+','x'}, -/*DELETE*/ {' ',' ',' ',' ',' ','+','x','x','x'}, -/*GET*/ {' ',' ',' ',' ','+','+','x','x','x'}, -/*FLUSH*/ {'x','x','x','x','x','x','x','x','x'}, -/*EVENT*/ {'x','x','x','x','x','x','x','x','x'} + /* -s -d -r -q -p -i -t -u -z -m -g*/ +/*LIST*/ {'x','x','x','x','x','x','x','x',' ','x','x'}, +/*CREATE*/ {'+','+','+','+','+','x','+','+','x','x','x'}, +/*DELETE*/ {' ',' ',' ',' ',' ','+','x','x','x','x','x'}, +/*GET*/ {' ',' ',' ',' ','+','+','x','x','x','x','x'}, +/*FLUSH*/ {'x','x','x','x','x','x','x','x','x','x','x'}, +/*EVENT*/ {'x','x','x','x','x','x','x','x','x','x',' '}, +/*ACTION*/ {'x','x','x','x','x','x','x','x',' ',' ','x'}, }; LIST_HEAD(proto_list); @@ -188,7 +210,7 @@ exit_error(enum exittype status, char *msg, ...) global_option_offset = 0; } va_start(args, msg); - fprintf(stderr, "%s v%s: ", PROGNAME, VERSION); + fprintf(stderr,"%s v%s: ", PROGNAME, VERSION); vfprintf(stderr, msg, args); va_end(args); fprintf(stderr, "\n"); @@ -256,52 +278,191 @@ merge_options(struct option *oldopts, const struct option *newopts, return merge; } +static void dump_tuple(struct ip_conntrack_tuple *tp) +{ + fprintf(stderr, "tuple %p: %u %u.%u.%u.%u:%hu -> %u.%u.%u.%u:%hu\n", + tp, tp->dst.protonum, + NIPQUAD(tp->src.ip), ntohs(tp->src.u.all), + NIPQUAD(tp->dst.ip), ntohs(tp->dst.u.all)); +} + void not_implemented_yet() { exit_error(OTHER_PROBLEM, "Sorry, not implemented yet :(\n"); } -unsigned int check_type() +static int +do_parse_status(const char *str, size_t strlen, unsigned int *status) +{ + if (strncasecmp(str, "ASSURED", strlen) == 0) + *status |= IPS_ASSURED; + else if (strncasecmp(str, "SEEN_REPLY", strlen) == 0) + *status |= IPS_SEEN_REPLY; + else if (strncasecmp(str, "UNSET", strlen) == 0) + *status |= 0; + else + return 0; + return 1; +} + +static void +parse_status(const char *arg, unsigned int *status) +{ + const char *comma; + + while ((comma = strchr(arg, ',')) != NULL) { + if (comma == arg || !do_parse_status(arg, comma-arg, status)) + exit_error(PARAMETER_PROBLEM, "Bad status `%s'", arg); + arg = comma+1; + } + + if (strlen(arg) == 0 || !do_parse_status(arg, strlen(arg), status)) + exit_error(PARAMETER_PROBLEM, "Bad status `%s'", arg); +} + +static int +do_parse_group(const char *str, size_t strlen, unsigned int *group) +{ + if (strncasecmp(str, "ALL", strlen) == 0) + *group |= ~0U; + else if (strncasecmp(str, "TCP", strlen) == 0) + *group |= NFGRP_IPV4_CT_TCP; + else if (strncasecmp(str, "UDP", strlen) == 0) + *group |= NFGRP_IPV4_CT_UDP; + else if (strncasecmp(str, "ICMP", strlen) == 0) + *group |= NFGRP_IPV4_CT_ICMP; + else + return 0; + return 1; +} + +static void +parse_group(const char *arg, unsigned int *group) { - unsigned int type = 0; + const char *comma; + + while ((comma = strchr(arg, ',')) != NULL) { + if (comma == arg || !do_parse_group(arg, comma-arg, group)) + exit_error(PARAMETER_PROBLEM, "Bad status `%s'", arg); + arg = comma+1; + } - if (!optarg) - exit_error(PARAMETER_PROBLEM, "must specified `conntrack' or " - "`expect'\n"); + if (strlen(arg) == 0 || !do_parse_group(arg, strlen(arg), group)) + exit_error(PARAMETER_PROBLEM, "Bad status `%s'", arg); +} + +unsigned int check_type(int argc, char *argv[]) +{ + char *table = NULL; + + /* Nasty bug or feature in getopt_long ? + * It seems that it behaves badly with optional arguments. + * Fortunately, I just stole the fix from iptables ;) */ + if (optarg) + return 0; + else if (optind < argc && argv[optind][0] != '-' + && argv[optind][0] != '!') + table = argv[optind++]; - if (strncmp("conntrack", optarg, 9) == 0) - type = 0; - else if (strncmp("expect", optarg, 6) == 0) - type = 1; - else { - exit_error(PARAMETER_PROBLEM, "unknown type `%s'\n", optarg); + if (!table) + return 0; + + if (strncmp("expect", table, 6) == 0) + return 1; + else if (strncmp("conntrack", table, 9) == 0) + return 0; + else + exit_error(PARAMETER_PROBLEM, "unknown type `%s'\n", table); + + return 0; +} + +static char *get_modprobe(void) +{ + int procfile; + char *ret; + +#define PROCFILE_BUFSIZ 1024 + procfile = open(PROC_SYS_MODPROBE, O_RDONLY); + if (procfile < 0) + return NULL; + + ret = (char *) malloc(PROCFILE_BUFSIZ); + if (ret) { + memset(ret, 0, PROCFILE_BUFSIZ); + switch (read(procfile, ret, PROCFILE_BUFSIZ)) { + case -1: goto fail; + case PROCFILE_BUFSIZ: goto fail; /* Partial read. Weird */ + } + if (ret[strlen(ret)-1]=='\n') + ret[strlen(ret)-1]=0; + close(procfile); + return ret; + } + fail: + free(ret); + close(procfile); + return NULL; +} + +int iptables_insmod(const char *modname, const char *modprobe) +{ + char *buf = NULL; + char *argv[3]; + int status; + + /* If they don't explicitly set it, read out of kernel */ + if (!modprobe) { + buf = get_modprobe(); + if (!buf) + return -1; + modprobe = buf; } - return type; + switch (fork()) { + case 0: + argv[0] = (char *)modprobe; + argv[1] = (char *)modname; + argv[2] = NULL; + execv(argv[0], argv); + + /* not usually reached */ + exit(1); + case -1: + return -1; + + default: /* parent */ + wait(&status); + } + + free(buf); + if (WIFEXITED(status) && WEXITSTATUS(status) == 0) + return 0; + return -1; } void usage(char *prog) { -printf("Tool to manipulate conntrack and expectations. Version %s\n", VERSION); -printf("Usage: %s [commands] [options]\n", prog); -printf("\n"); -printf("Commands:\n"); -printf("-L table List conntrack or expectation table\n"); -printf("-G table [options] Get conntrack or expectation\n"); -printf("-D table [options] Delete conntrack or expectation\n"); -printf("-I table [options] Create a conntrack or expectation\n"); -printf("-E table Show events\n"); -printf("-F table Flush table\n"); -printf("\n"); -printf("Options:\n"); -printf("--orig-src Source address from original direction\n"); -printf("--orig-dst Destination address from original direction\n"); -printf("--reply-src Source addres from reply direction\n"); -printf("--reply-dst Destination address from reply direction\n"); -printf("-p Layer 4 Protocol\n"); -printf("-t Timeout\n"); -printf("-i Conntrack ID\n"); -printf("-u Status\n"); -printf("-z Zero Counters\n"); +fprintf(stderr, "Tool to manipulate conntrack and expectations. Version %s\n", VERSION); +fprintf(stderr, "Usage: %s [commands] [options]\n", prog); +fprintf(stderr, "\n"); +fprintf(stderr, "Commands:\n"); +fprintf(stderr, "-L table List conntrack or expectation table\n"); +fprintf(stderr, "-G table [options] Get conntrack or expectation\n"); +fprintf(stderr, "-D table [options] Delete conntrack or expectation\n"); +fprintf(stderr, "-I table [options] Create a conntrack or expectation\n"); +fprintf(stderr, "-E table Show events\n"); +fprintf(stderr, "-F table Flush table\n"); +fprintf(stderr, "\n"); +fprintf(stderr, "Options:\n"); +fprintf(stderr, "--orig-src Source address from original direction\n"); +fprintf(stderr, "--orig-dst Destination address from original direction\n"); +fprintf(stderr, "--reply-src Source addres from reply direction\n"); +fprintf(stderr, "--reply-dst Destination address from reply direction\n"); +fprintf(stderr, "-p Layer 4 Protocol\n"); +fprintf(stderr, "-t Timeout\n"); +fprintf(stderr, "-i Conntrack ID\n"); +fprintf(stderr, "-u Status\n"); +fprintf(stderr, "-z Zero Counters\n"); } int main(int argc, char *argv[]) @@ -314,7 +475,8 @@ int main(int argc, char *argv[]) unsigned long timeout = 0; unsigned int status = 0; unsigned long id = 0; - unsigned int type = 0; + unsigned int type = 0, mask = 0, extra_flags = 0, event_mask = 0; + int res = 0, retry = 2; memset(&proto, 0, sizeof(union ip_conntrack_proto)); memset(&orig, 0, sizeof(struct ip_conntrack_tuple)); @@ -323,31 +485,42 @@ int main(int argc, char *argv[]) reply.dst.dir = IP_CT_DIR_REPLY; while ((c = getopt_long(argc, argv, - "L:I:D:G:E:s:d:r:q:p:i:t:u:z", opts, NULL)) != -1) { + "L::I::D::G::E::A::s:d:r:q:p:i:t:u:m:g:z", + opts, NULL)) != -1) { switch(c) { case 'L': command |= CT_LIST; - type = check_type(); + type = check_type(argc, argv); break; case 'I': command |= CT_CREATE; - type = check_type(); + type = check_type(argc, argv); break; case 'D': command |= CT_DELETE; - type = check_type(); + type = check_type(argc, argv); break; case 'G': command |= CT_GET; - type = check_type(); + type = check_type(argc, argv); break; case 'F': command |= CT_FLUSH; - type = check_type(); + type = check_type(argc, argv); break; case 'E': command |= CT_EVENT; - type = check_type(); + type = check_type(argc, argv); + break; + case 'A': + command |= CT_ACTION; + type = check_type(argc, argv); + case 'm': + if (!optarg) + continue; + + options |= CT_OPT_DUMP_MASK; + mask = atoi(optarg); break; case 's': options |= CT_OPT_ORIG_SRC; @@ -394,23 +567,22 @@ int main(int argc, char *argv[]) continue; options |= CT_OPT_STATUS; + parse_status(optarg, &status); /* Just insert confirmed conntracks */ status |= IPS_CONFIRMED; - if (strncmp("SEEN_REPLY", optarg, strlen("SEEN_REPLY")) == 0) - status |= IPS_SEEN_REPLY; - else if (strncmp("ASSURED", optarg, strlen("ASSURED")) == 0) - status |= IPS_ASSURED; - else - exit_error(PARAMETER_PROBLEM, "Invalid status" - "flag: %s\n", optarg); break; } + case 'g': + options |= CT_OPT_EVENT_MASK; + parse_group(optarg, &event_mask); + break; case 'z': options |= CT_OPT_ZERO; break; default: - if (h && !h->parse(c - h->option_offset, argv, - &orig, &reply)) + if (h && h->parse && !h->parse(c - h->option_offset, + argv, &orig, &reply, + &proto, &extra_flags)) exit_error(PARAMETER_PROBLEM, "parse error\n"); /* Unknown argument... */ @@ -425,58 +597,84 @@ int main(int argc, char *argv[]) generic_opt_check(command, options); - switch(command) { + while (retry > 0) { + retry--; + switch(command) { case CT_LIST: - printf("list\n"); if (type == 0) { if (options & CT_OPT_ZERO) - dump_conntrack_table(1); + res = dump_conntrack_table(1); else - dump_conntrack_table(0); - } else - dump_expect_list(); + res = dump_conntrack_table(0); + } else + res = dump_expect_list(); break; + case CT_CREATE: - printf("create\n"); + fprintf(stderr, "create\n"); if (type == 0) create_conntrack(&orig, &reply, timeout, &proto, status); else not_implemented_yet(); break; + case CT_DELETE: - printf("delete\n"); + fprintf(stderr, "delete\n"); if (type == 0) { if (options & CT_OPT_ORIG) - delete_conntrack(&orig, CTA_ORIG, id); + res =delete_conntrack(&orig, CTA_ORIG, + id); else if (options & CT_OPT_REPL) - delete_conntrack(&reply, CTA_RPLY, id); + res = delete_conntrack(&reply, CTA_RPLY, + id); } else not_implemented_yet(); break; + case CT_GET: - printf("get\n"); + fprintf(stderr, "get\n"); if (type == 0) { if (options & CT_OPT_ORIG) - get_conntrack(&orig, CTA_ORIG, id); + res = get_conntrack(&orig, CTA_ORIG, + id); else if (options & CT_OPT_REPL) - get_conntrack(&reply, CTA_RPLY, id); + res = get_conntrack(&reply, CTA_RPLY, + id); } else not_implemented_yet(); break; + case CT_FLUSH: not_implemented_yet(); break; + case CT_EVENT: - printf("event\n"); - if (type == 0) - event_conntrack(); - else + if (type == 0) { + if (options & CT_OPT_EVENT_MASK) + res = event_conntrack(event_mask); + else + res = event_conntrack(~0U); + } else /* and surely it won't ever... */ not_implemented_yet(); - default: + + case CT_ACTION: + if (type == 0) + if (options & CT_OPT_DUMP_MASK) + res = set_dump_mask(mask); + break; + + default: usage(argv[0]); break; + } + /* Maybe ip_conntrack_netlink isn't insmod'ed */ + if (res == -1 && retry) + /* Give it a try just once */ + iptables_insmod("ip_conntrack_netlink", NULL); + else + retry--; } if (opts != original_opts) { @@ -484,4 +682,7 @@ int main(int argc, char *argv[]) opts = original_opts; global_option_offset = 0; } + + if (res == -1) + fprintf(stderr, "Operations failed\n"); } diff --git a/src/libct.c b/src/libct.c index 47743d8..143901b 100644 --- a/src/libct.c +++ b/src/libct.c @@ -19,31 +19,20 @@ extern struct list_head proto_list; extern char *proto2str[]; -/* Built-in generic proto handler */ - -/* FIXME: This should die... */ -static int parse(char c, char *argv[], - struct ip_conntrack_tuple *orig, - struct ip_conntrack_tuple *reply) { - return 0; -} -/* FIXME: die die too... */ -static void print(struct ip_conntrack_tuple *t) {} - -static struct ctproto_handler generic_handler = { - .name = "generic", - .protonum = 0, - .parse = parse, - .print = print, - .opts = NULL -}; - static int handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void *arg) { struct nfgenmsg *nfmsg; struct nfattr *nfa; int min_len = 0; struct ctproto_handler *h = NULL; + struct nfattr *attr = NFM_NFA(NLMSG_DATA(nlh)); + int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); + + struct ip_conntrack_tuple *orig, *reply; + struct cta_counters *ctr; + unsigned long *status, *timeout; + struct cta_proto *proto; + unsigned long *id, *mark; DEBUGP("netlink header\n"); DEBUGP("len: %d type: %d flags: %d seq: %d pid: %d\n", @@ -59,76 +48,62 @@ static int handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void *arg) DEBUGP("size:%d\n", nlh->nlmsg_len); - while (nlh->nlmsg_len > min_len) { - struct nfattr *attr = NFM_NFA(NLMSG_DATA(nlh)); - int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); - - struct ip_conntrack_tuple *orig, *reply; - struct cta_counters *ctr; - unsigned long *status, *timeout; - struct cta_proto *proto; - unsigned long *id, *mark; - - while (NFA_OK(attr, attrlen)) { - switch(attr->nfa_type) { - case CTA_ORIG: - orig = NFA_DATA(attr); - printf("src=%u.%u.%u.%u dst=%u.%u.%u.%u ", - NIPQUAD(orig->src.ip), - NIPQUAD(orig->dst.ip)); - h = findproto(proto2str[orig->dst.protonum]); - if (h) - h->print(orig); - break; - case CTA_RPLY: - reply = NFA_DATA(attr); - printf("src=%u.%u.%u.%u dst=%u.%u.%u.%u ", - NIPQUAD(reply->src.ip), - NIPQUAD(reply->dst.ip)); - h = findproto(proto2str[reply->dst.protonum]); - if (h) - h->print(reply); - break; - case CTA_STATUS: - status = NFA_DATA(attr); - printf("status=%u ", *status); - break; - case CTA_PROTOINFO: - proto = NFA_DATA(attr); - if (proto2str[proto->num_proto]) - printf("%s %d ", proto2str[proto->num_proto], proto->num_proto); - else - printf("unknown %d ", proto->num_proto); - break; - case CTA_TIMEOUT: - timeout = NFA_DATA(attr); - printf("timeout=%lu ", *timeout); - break; -/* case CTA_ID: - id = NFA_DATA(attr); - printf(" id:%lu ", *id); - break;*/ - case CTA_MARK: - mark = NFA_DATA(attr); - printf("mark=%lu ", *mark); - break; - case CTA_COUNTERS: - ctr = NFA_DATA(attr); - printf("orig_packets=%lu orig_bytes=%lu, " - "reply_packets=%lu reply_bytes=%lu ", - ctr->orig.packets, ctr->orig.bytes, - ctr->reply.packets, ctr->reply.bytes); - break; - } - DEBUGP("nfa->nfa_type: %d\n", attr->nfa_type); - DEBUGP("nfa->nfa_len: %d\n", attr->nfa_len); - attr = NFA_NEXT(attr, attrlen); + while (NFA_OK(attr, attrlen)) { + switch(attr->nfa_type) { + case CTA_ORIG: + orig = NFA_DATA(attr); + printf("src=%u.%u.%u.%u dst=%u.%u.%u.%u ", + NIPQUAD(orig->src.ip), + NIPQUAD(orig->dst.ip)); + h = findproto(proto2str[orig->dst.protonum]); + if (h && h->print) + h->print(orig); + break; + case CTA_RPLY: + reply = NFA_DATA(attr); + printf("src=%u.%u.%u.%u dst=%u.%u.%u.%u ", + NIPQUAD(reply->src.ip), + NIPQUAD(reply->dst.ip)); + h = findproto(proto2str[reply->dst.protonum]); + if (h && h->print) + h->print(reply); + break; + case CTA_STATUS: + status = NFA_DATA(attr); + printf("status=%u ", *status); + break; + case CTA_PROTOINFO: + proto = NFA_DATA(attr); + if (proto2str[proto->num_proto]) + printf("%s %d ", proto2str[proto->num_proto], proto->num_proto); + else + printf("unknown %d ", proto->num_proto); + break; + case CTA_TIMEOUT: + timeout = NFA_DATA(attr); + printf("timeout=%lu ", *timeout); + break; +/* case CTA_ID: + id = NFA_DATA(attr); + printf(" id:%lu ", *id); + break;*/ + case CTA_MARK: + mark = NFA_DATA(attr); + printf("mark=%lu ", *mark); + break; + case CTA_COUNTERS: + ctr = NFA_DATA(attr); + printf("orig_packets=%lu orig_bytes=%lu, " + "reply_packets=%lu reply_bytes=%lu ", + ctr->orig.packets, ctr->orig.bytes, + ctr->reply.packets, ctr->reply.bytes); + break; } - min_len += nlh->nlmsg_len; - nlh = (struct nlmsghdr *) attr; - printf("\n"); + DEBUGP("nfa->nfa_type: %d\n", attr->nfa_type); + DEBUGP("nfa->nfa_len: %d\n", attr->nfa_len); + attr = NFA_NEXT(attr, attrlen); } - DEBUGP("exit from handler\n"); + printf("\n"); return 0; } @@ -156,6 +131,14 @@ static int event_handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, int min_len = 0; struct ctproto_handler *h = NULL; int type = NFNL_MSG_TYPE(nlh->nlmsg_type); + struct nfattr *attr = NFM_NFA(NLMSG_DATA(nlh)); + int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); + + struct ip_conntrack_tuple *orig, *reply; + struct cta_counters *ctr; + unsigned long *status, *timeout, *mark; + struct cta_proto *proto; + unsigned long *id; DEBUGP("netlink header\n"); DEBUGP("len: %d type: %d flags: %d seq: %d pid: %d\n", @@ -173,76 +156,62 @@ static int event_handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, printf("type: [%s] ", typemsg2str(type, nlh->nlmsg_flags)); - while (nlh->nlmsg_len > min_len) { - struct nfattr *attr = NFM_NFA(NLMSG_DATA(nlh)); - int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); - - struct ip_conntrack_tuple *orig, *reply; - struct cta_counters *ctr; - unsigned long *status, *timeout, *mark; - struct cta_proto *proto; - unsigned long *id; - - while (NFA_OK(attr, attrlen)) { - switch(attr->nfa_type) { - case CTA_ORIG: - orig = NFA_DATA(attr); - printf("src=%u.%u.%u.%u dst=%u.%u.%u.%u ", - NIPQUAD(orig->src.ip), - NIPQUAD(orig->dst.ip)); - h = findproto(proto2str[orig->dst.protonum]); - if (h) - h->print(orig); - break; - case CTA_RPLY: - reply = NFA_DATA(attr); - printf("src=%u.%u.%u.%u dst=%u.%u.%u.%u ", - NIPQUAD(reply->src.ip), - NIPQUAD(reply->dst.ip)); - h = findproto(proto2str[reply->dst.protonum]); - if (h) - h->print(reply); - break; - case CTA_STATUS: - status = NFA_DATA(attr); - printf("status:%u ", *status); - break; - case CTA_PROTOINFO: - proto = NFA_DATA(attr); - if (proto2str[proto->num_proto]) - printf("%s %d ", proto2str[proto->num_proto], proto->num_proto); - else - printf("unknown %d ", proto->num_proto); - break; - case CTA_TIMEOUT: - timeout = NFA_DATA(attr); - printf("timeout:%lu ", *timeout); - break; -/* case CTA_ID: - id = NFA_DATA(attr); - printf(" id:%lu ", *id); - break;*/ - case CTA_MARK: - mark = NFA_DATA(attr); - printf("mark=%lu ", *mark); - break; - case CTA_COUNTERS: - ctr = NFA_DATA(attr); - printf("orig_packets=%lu orig_bytes=%lu, " - "reply_packets=%lu reply_bytes=%lu ", - ctr->orig.packets, ctr->orig.bytes, - ctr->reply.packets, ctr->reply.bytes); - break; - } - DEBUGP("nfa->nfa_type: %d\n", attr->nfa_type); - DEBUGP("nfa->nfa_len: %d\n", attr->nfa_len); - attr = NFA_NEXT(attr, attrlen); + while (NFA_OK(attr, attrlen)) { + switch(attr->nfa_type) { + case CTA_ORIG: + orig = NFA_DATA(attr); + printf("src=%u.%u.%u.%u dst=%u.%u.%u.%u ", + NIPQUAD(orig->src.ip), + NIPQUAD(orig->dst.ip)); + h = findproto(proto2str[orig->dst.protonum]); + if (h && h->print) + h->print(orig); + break; + case CTA_RPLY: + reply = NFA_DATA(attr); + printf("src=%u.%u.%u.%u dst=%u.%u.%u.%u ", + NIPQUAD(reply->src.ip), + NIPQUAD(reply->dst.ip)); + h = findproto(proto2str[reply->dst.protonum]); + if (h && h->print) + h->print(reply); + break; + case CTA_STATUS: + status = NFA_DATA(attr); + printf("status:%u ", *status); + break; + case CTA_PROTOINFO: + proto = NFA_DATA(attr); + if (proto2str[proto->num_proto]) + printf("%s %d ", proto2str[proto->num_proto], proto->num_proto); + else + printf("unknown %d ", proto->num_proto); + break; + case CTA_TIMEOUT: + timeout = NFA_DATA(attr); + printf("timeout:%lu ", *timeout); + break; +/* case CTA_ID: + id = NFA_DATA(attr); + printf(" id:%lu ", *id); + break;*/ + case CTA_MARK: + mark = NFA_DATA(attr); + printf("mark=%lu ", *mark); + break; + case CTA_COUNTERS: + ctr = NFA_DATA(attr); + printf("orig_packets=%lu orig_bytes=%lu, " + "reply_packets=%lu reply_bytes=%lu ", + ctr->orig.packets, ctr->orig.bytes, + ctr->reply.packets, ctr->reply.bytes); + break; } - min_len += nlh->nlmsg_len; - nlh = (struct nlmsghdr *) attr; - printf("\n"); + DEBUGP("nfa->nfa_type: %d\n", attr->nfa_type); + DEBUGP("nfa->nfa_len: %d\n", attr->nfa_len); + attr = NFA_NEXT(attr, attrlen); } - DEBUGP("exit from handler\n"); + printf("\n"); return 0; } @@ -253,6 +222,11 @@ static int expect_handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void * struct nfattr *nfa; int min_len = 0; struct ctproto_handler *h = NULL; + struct nfattr *attr = NFM_NFA(NLMSG_DATA(nlh)); + int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); + + struct ip_conntrack_tuple *exp, *mask; + unsigned long *timeout; DEBUGP("netlink header\n"); DEBUGP("len: %d type: %d flags: %d seq: %d pid: %d\n", @@ -268,56 +242,45 @@ static int expect_handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void * DEBUGP("size:%d\n", nlh->nlmsg_len); - while (nlh->nlmsg_len > min_len) { - struct nfattr *attr = NFM_NFA(NLMSG_DATA(nlh)); - int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); - - struct ip_conntrack_tuple *exp, *mask; - unsigned long *timeout; - - while (NFA_OK(attr, attrlen)) { - switch(attr->nfa_type) { - case CTA_EXP_TUPLE: - exp = NFA_DATA(attr); - printf("src=%u.%u.%u.%u dst=%u.%u.%u.%u ", - NIPQUAD(exp->src.ip), - NIPQUAD(exp->dst.ip)); - h = findproto(proto2str[exp->dst.protonum]); - if (h) - h->print(exp); - break; - case CTA_EXP_MASK: - mask = NFA_DATA(attr); - printf("src=%u.%u.%u.%u dst=%u.%u.%u.%u ", - NIPQUAD(mask->src.ip), - NIPQUAD(mask->dst.ip)); - h = findproto(proto2str[mask->dst.protonum]); - if (h) - h->print(mask); - break; - case CTA_EXP_TIMEOUT: - timeout = NFA_DATA(attr); - printf("timeout:%lu ", *timeout); - break; - } - DEBUGP("nfa->nfa_type: %d\n", attr->nfa_type); - DEBUGP("nfa->nfa_len: %d\n", attr->nfa_len); - attr = NFA_NEXT(attr, attrlen); + while (NFA_OK(attr, attrlen)) { + switch(attr->nfa_type) { + case CTA_EXP_TUPLE: + exp = NFA_DATA(attr); + printf("src=%u.%u.%u.%u dst=%u.%u.%u.%u ", + NIPQUAD(exp->src.ip), + NIPQUAD(exp->dst.ip)); + h = findproto(proto2str[exp->dst.protonum]); + if (h && h->print) + h->print(exp); + break; + case CTA_EXP_MASK: + mask = NFA_DATA(attr); + printf("src=%u.%u.%u.%u dst=%u.%u.%u.%u ", + NIPQUAD(mask->src.ip), + NIPQUAD(mask->dst.ip)); + h = findproto(proto2str[mask->dst.protonum]); + if (h && h->print) + h->print(mask); + break; + case CTA_EXP_TIMEOUT: + timeout = NFA_DATA(attr); + printf("timeout:%lu ", *timeout); + break; } - min_len += nlh->nlmsg_len; - nlh = (struct nlmsghdr *) attr; - printf("\n"); + DEBUGP("nfa->nfa_type: %d\n", attr->nfa_type); + DEBUGP("nfa->nfa_len: %d\n", attr->nfa_len); + attr = NFA_NEXT(attr, attrlen); } - DEBUGP("exit from handler\n"); + printf("\n"); return 0; } -void create_conntrack(struct ip_conntrack_tuple *orig, - struct ip_conntrack_tuple *reply, - unsigned long timeout, - union ip_conntrack_proto *proto, - unsigned int status) +int create_conntrack(struct ip_conntrack_tuple *orig, + struct ip_conntrack_tuple *reply, + unsigned long timeout, + union ip_conntrack_proto *proto, + unsigned int status) { struct cta_proto cta; struct nfattr *cda[CTA_MAX]; @@ -331,45 +294,39 @@ void create_conntrack(struct ip_conntrack_tuple *orig, } /* FIXME: please unify returns values... */ - if (ctnl_new_conntrack(&cth, orig, reply, timeout, proto, status) < 0) { - printf("error new conntrack\n"); - exit(0); - } + if (ctnl_new_conntrack(&cth, orig, reply, timeout, proto, status) < 0) + return -1; - if (ctnl_close(&cth) < 0) { - printf("error2"); - exit(0); - } + if (ctnl_close(&cth) < 0) + return -1; + + return 0; } -void delete_conntrack(struct ip_conntrack_tuple *tuple, - enum ctattr_type_t t, - unsigned long id) +int delete_conntrack(struct ip_conntrack_tuple *tuple, + enum ctattr_type_t t, + unsigned long id) { struct nfattr *cda[CTA_MAX]; struct ctnl_handle cth; - if (ctnl_open(&cth, 0) < 0) { - printf("error\n"); - exit(0); - } + if (ctnl_open(&cth, 0) < 0) + return -1; /* FIXME: please unify returns values... */ - if (ctnl_del_conntrack(&cth, tuple, t, id) < 0) { - printf("error del conntrack\n"); - exit(0); - } + if (ctnl_del_conntrack(&cth, tuple, t, id) < 0) + return -1; - if (ctnl_close(&cth) < 0) { - printf("error2"); - exit(0); - } + if (ctnl_close(&cth) < 0) + return -1; + + return 0; } /* get_conntrack_handler */ -void get_conntrack(struct ip_conntrack_tuple *tuple, - enum ctattr_type_t t, - unsigned long id) +int get_conntrack(struct ip_conntrack_tuple *tuple, + enum ctattr_type_t t, + unsigned long id) { struct nfattr *cda[CTA_MAX]; struct ctnl_handle cth; @@ -378,26 +335,22 @@ void get_conntrack(struct ip_conntrack_tuple *tuple, .handler = handler }; - if (ctnl_open(&cth, 0) < 0) { - printf("error\n"); - exit(0); - } + if (ctnl_open(&cth, 0) < 0) + return -1; ctnl_register_handler(&cth, &h); /* FIXME!!!! get_conntrack_handler returns -100 */ - if (ctnl_get_conntrack(&cth, tuple, t, id) != -100) { - printf("error get conntrack\n"); - exit(0); - } + if (ctnl_get_conntrack(&cth, tuple, t, id) != -100) + return -1; - if (ctnl_close(&cth) < 0) { - printf("error2"); - exit(0); - } + if (ctnl_close(&cth) < 0) + return -1; + + return 0; } -void dump_conntrack_table(int zero) +int dump_conntrack_table(int zero) { int ret; struct ctnl_handle cth; @@ -406,10 +359,8 @@ void dump_conntrack_table(int zero) .handler = handler }; - if (ctnl_open(&cth, 0) < 0) { - printf("error\n"); - exit(0); - } + if (ctnl_open(&cth, 0) < 0) + return -1; ctnl_register_handler(&cth, &h); @@ -418,18 +369,16 @@ void dump_conntrack_table(int zero) } else ret = ctnl_list_conntrack(&cth, AF_INET); - if (ret != -100) { - printf("error list\n"); - exit(0); - } + if (ret != -100) + return -1; - if (ctnl_close(&cth) < 0) { - printf("error2\n"); - exit(0); - } + if (ctnl_close(&cth) < 0) + return -1; + + return 0; } -void event_conntrack() +int event_conntrack(unsigned int event_mask) { struct ctnl_handle cth; struct ctnl_msg_handler hnew = { @@ -441,19 +390,18 @@ void event_conntrack() .handler = event_handler }; - if (ctnl_open(&cth, NFGRP_IPV4_CT_TCP) < 0) { - printf("error\n"); - exit(0); - } + if (ctnl_open(&cth, event_mask) < 0) + return -1; ctnl_register_handler(&cth, &hnew); ctnl_register_handler(&cth, &hdestroy); - ctnl_event_conntrack(&cth, AF_INET); + if (ctnl_event_conntrack(&cth, AF_INET) < 0) + return -1; - if (ctnl_close(&cth) < 0) { - printf("error2\n"); - exit(0); - } + if (ctnl_close(&cth) < 0) + return -1; + + return 0; } struct ctproto_handler *findproto(char *name) @@ -462,6 +410,9 @@ struct ctproto_handler *findproto(char *name) struct list_head *i; struct ctproto_handler *cur = NULL, *handler = NULL; + if (!name) + return handler; + list_for_each(i, &proto_list) { cur = (struct ctproto_handler *) i; if (strcmp(cur->name, name) == 0) { @@ -480,9 +431,6 @@ struct ctproto_handler *findproto(char *name) fprintf (stderr, "%s\n", dlerror());*/ } - if (!handler) - handler = &generic_handler; - return handler; } @@ -496,7 +444,7 @@ void unregister_proto(struct ctproto_handler *h) list_del(&h->head); } -void dump_expect_list() +int dump_expect_list() { struct ctnl_handle cth; struct ctnl_msg_handler h = { @@ -504,21 +452,32 @@ void dump_expect_list() .handler = expect_handler }; - if (ctnl_open(&cth, 0) < 0) { - printf("error\n"); - exit(0); - } + if (ctnl_open(&cth, 0) < 0) + return -1; ctnl_register_handler(&cth, &h); - if (ctnl_list_expect(&cth, AF_INET) != -100) { - printf("error list\n"); - exit(0); - } + if (ctnl_list_expect(&cth, AF_INET) != -100) + return -1; - if (ctnl_close(&cth) < 0) { - printf("error2\n"); - exit(0); - } + if (ctnl_close(&cth) < 0) + return -1; + + return 0; } +int set_dump_mask(unsigned int mask) +{ + struct ctnl_handle cth; + + if (ctnl_open(&cth, 0) < 0) + return -1; + + if (ctnl_set_dumpmask(&cth, mask) < 0) + return -1; + + if (ctnl_close(&cth) < 0) + return -1; + + return 0; +} -- cgit v1.2.3 From d894e26211f38db37015850afab6b7331edeecdb 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, 1 May 2005 23:19:42 +0000 Subject: o Created changelog file o Deleted libctnetlink.h and libnfnetlink.h from the include/ dir. o Added support for version (-V) and help (-h) o Added event mask based support o Added GPLv2 headers o Use fprintf instead of printf o Defined print_tuple and print_proto output interfaces o ctnl_[get|del]_conntrack handles return value from kernel via msgerr o Added support for conntrack table flushing o Added test case file (test.sh) o Improve dump output o Autoconf stuff for conntrack + some pablo's modifications. o Fixed packet counters formatting (use %llu instead of %lu) --- AUTHORS | 1 + ChangeLog | 23 + EXAMPLES | 23 - INSTALL | 229 ++ Makefile | 14 - Makefile.am | 13 + TODO | 14 +- config.guess | 1317 +++++++++ config.h.in | 64 + config.sub | 1411 ++++++++++ configure.in | 88 + extensions/Makefile | 12 - extensions/Makefile.am | 14 + extensions/libct_proto_tcp.c | 29 +- extensions/libct_proto_udp.c | 49 +- include/Makefile.am | 2 + include/libct_proto.h | 9 +- include/libctnetlink.h | 72 - include/libnfnetlink.h | 50 - install-sh | 251 ++ ltmain.sh | 6426 ++++++++++++++++++++++++++++++++++++++++++ missing | 336 +++ mkinstalldirs | 40 + src/Makefile.am | 8 + src/conntrack.c | 255 +- src/libct.c | 174 +- test.sh | 67 + 27 files changed, 10620 insertions(+), 371 deletions(-) create mode 100644 AUTHORS create mode 100644 ChangeLog delete mode 100644 EXAMPLES create mode 100644 INSTALL delete mode 100644 Makefile create mode 100644 Makefile.am create mode 100644 config.guess create mode 100644 config.h.in create mode 100644 config.sub create mode 100644 configure.in delete mode 100644 extensions/Makefile create mode 100644 extensions/Makefile.am create mode 100644 include/Makefile.am delete mode 100644 include/libctnetlink.h delete mode 100644 include/libnfnetlink.h create mode 100644 install-sh create mode 100644 ltmain.sh create mode 100644 missing create mode 100644 mkinstalldirs create mode 100644 src/Makefile.am create mode 100644 test.sh (limited to 'src') diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..2cc79e0 --- /dev/null +++ b/AUTHORS @@ -0,0 +1 @@ +Pablo Neira Ayuso diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..147f8d6 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,23 @@ +2005-04-25 + + o Added support for mask based event dumping + o Added support for mask based event notification + o On-demand autoload of ip_conntrack_netlink + +2005-05-01 + + o Created changelog file + o Deleted libctnetlink.h and libnfnetlink.h from the include/ dir. + o Added support for version (-V) and help (-h) + o Added event mask based support + o Added GPLv2 headers + o Use fprintf instead of printf + o Defined print_tuple and print_proto output interfaces + o ctnl_[get|del]_conntrack handles return value from kernel via msgerr + o Added support for conntrack table flushing + o Added test case file (test.sh) + o Improve dump output + + + o Autoconf stuff for conntrack + some pablo's modifications. + o Fixed packet counters formatting (use %llu instead of %lu) diff --git a/EXAMPLES b/EXAMPLES deleted file mode 100644 index 16e192e..0000000 --- a/EXAMPLES +++ /dev/null @@ -1,23 +0,0 @@ -o List conntrack table - - $ conntrack -L conntrack - -o Get a conntrack - - $ conntrack -G conntrack --reply-src 85.136.102.173 \ - --reply-dst 66.111.58.51 -p tcp --reply-port-src 44843 \ - --reply-port-dst 993 -i 13 - -o Delete a conntrack - - $ conntrack -D conntrack --reply-src 85.136.102.173 \ - --reply-dst 66.111.58.51 -p tcp --reply-port-src 44843 \ - --reply-port-dst 993 -i 13 - -o Create a conntrack - - $ conntrack -I conntrack --orig-src 1.1.1.4 --orig-dst 2.2.2.3 \ - --reply-src 2.2.2.3 --reply-dst 1.1.1.4 -p tcp --orig-port-src 20 \ - --orig-port-dst 10 --reply-port-src 10 --orig-port-dst 20 \ - -u ASSURED -t 100 - diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..54caf7c --- /dev/null +++ b/INSTALL @@ -0,0 +1,229 @@ +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software +Foundation, Inc. + + This file is free documentation; the Free Software Foundation gives +unlimited permission to copy, distribute and modify it. + +Basic Installation +================== + + These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. (Caching is +disabled by default to prevent problems with accidental use of stale +cache files.) + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You only need +`configure.ac' if you want to change it or regenerate `configure' using +a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. Run `./configure --help' +for details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not support the `VPATH' +variable, you have to compile the package for one architecture at a +time in the source code directory. After you have installed the +package for one architecture, use `make distclean' before reconfiguring +for another architecture. + +Installation Names +================== + + By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/man', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PATH'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PATH', the package will use +PATH as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=PATH' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + + There may be some features `configure' cannot figure out +automatically, but needs to determine by the type of machine the package +will run on. Usually, assuming the package is built to be run on the +_same_ architectures, `configure' can figure that out, but if it prints +a message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the `--target=TYPE' option to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + + Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +will cause the specified gcc to be used as the C compiler (unless it is +overridden in the site shell script). + +`configure' Invocation +====================== + + `configure' recognizes the following options to control how it +operates. + +`--help' +`-h' + Print a summary of the options to `configure', and exit. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. + diff --git a/Makefile b/Makefile deleted file mode 100644 index 03edebc..0000000 --- a/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -LINKOPTS=-ldl -lnfnetlink -lctnetlink -rdynamic -KERNELDIR=/lib/modules/$(shell uname -r)/build/include/ -CFLAGS=-I${KERNELDIR} -Iinclude/ -g - -default: - ${CC} -c ${CFLAGS} src/conntrack.c -o src/conntrack.o - ${CC} -c ${CFLAGS} src/libct.c -o src/libct.o - ${CC} ${LINKOPTS} src/conntrack.o src/libct.o -o conntrack - ${MAKE} -C extensions/ - -clean: - rm -rf src/*.o conntrack - ${MAKE} clean -C extensions/ - diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..888d53e --- /dev/null +++ b/Makefile.am @@ -0,0 +1,13 @@ +# not a GNU package. You can remove this line, if +# have all needed files, that a GNU package needs +AUTOMAKE_OPTIONS = foreign 1.4 + +INCLUDES = $(all_includes) -I$(top_srcdir)/include -I${KERNELDIR} +SUBDIRS = src extensions +DIST_SUBDIRS = include src extensions +LINKOPTS = -ldl -lnfnetlink -lctnetlink +AM_CFLAGS = -g + +$(OBJECTS): libtool +libtool: $(LIBTOOL_DEPS) + $(SHELL) ./config.status --recheck diff --git a/TODO b/TODO index 12af6af..4b1654f 100644 --- a/TODO +++ b/TODO @@ -1,25 +1,23 @@ user space tool --------------- -General: -[ ] Proper Makefiles -[ ] Modify Event Display (-E conntrack). +[X] Proper Makefiles +[X] Modify Event Display (-E conntrack). Extensions: [ ] ICMP library -[ ] finish TCP: help and protocol specific stuff: --state, etc... -[ ] finish UDP: help +[X] finish TCP: protocol specific stuff: --state, etc... +[ ] finish UDP, TCP, ICMP: help nfnetlink_conntrack: -------------------- Now: -[ ] Error handling (nlerrmsg) +[X] Error handling (nlerrmsg) [X] Use id's to identify conntracks [ ] Split NEW and CHANGE [ ] Split DUMP and GET [ ] Kill Change API. Move locks to ip_conntrack_[protocol|helper]. -[ ] implement conntrack FLUSH -[ ] Per CPU id. Currently racy. +[X] implement conntrack FLUSH Later: [ ] convert CTA_SOMETHING-1 to CTA_SOMETHING, annoying! diff --git a/config.guess b/config.guess new file mode 100644 index 0000000..dff9e48 --- /dev/null +++ b/config.guess @@ -0,0 +1,1317 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 +# Free Software Foundation, Inc. + +timestamp='2001-09-04' + +# This file 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. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Written by Per Bothner . +# Please send patches to . +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# The plan is that this can be called by configure scripts if you +# don't specify an explicit build system type. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit 0 ;; + --version | -v ) + echo "$version" ; exit 0 ;; + --help | --h* | -h ) + echo "$usage"; exit 0 ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + + +dummy=dummy-$$ +trap 'rm -f $dummy.c $dummy.o $dummy.rel $dummy; exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +set_cc_for_build='case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int dummy(){}" > $dummy.c ; + for c in cc gcc c89 ; do + ($c $dummy.c -c -o $dummy.o) >/dev/null 2>&1 ; + if test $? = 0 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + rm -f $dummy.c $dummy.o $dummy.rel ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # Netbsd (nbsd) targets should (where applicable) match one or + # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # Determine the machine/vendor (is the vendor relevant). + case "${UNAME_MACHINE}" in + amiga) machine=m68k-unknown ;; + arm32) machine=arm-unknown ;; + atari*) machine=m68k-atari ;; + sun3*) machine=m68k-sun ;; + mac68k) machine=m68k-apple ;; + macppc) machine=powerpc-apple ;; + hp3[0-9][05]) machine=m68k-hp ;; + ibmrt|romp-ibm) machine=romp-ibm ;; + *) machine=${UNAME_MACHINE}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE}" in + i386|sparc|amiga|arm*|hp300|mvme68k|vax|atari|luna68k|mac68k|news68k|next68k|pc532|sun3*|x68k) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep __ELF__ >/dev/null + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit 0 ;; + alpha:OSF1:*:*) + if test $UNAME_RELEASE = "V4.0"; then + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + fi + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + cat <$dummy.s + .data +\$Lformat: + .byte 37,100,45,37,120,10,0 # "%d-%x\n" + + .text + .globl main + .align 4 + .ent main +main: + .frame \$30,16,\$26,0 + ldgp \$29,0(\$27) + .prologue 1 + .long 0x47e03d80 # implver \$0 + lda \$2,-1 + .long 0x47e20c21 # amask \$2,\$1 + lda \$16,\$Lformat + mov \$0,\$17 + not \$1,\$18 + jsr \$26,printf + ldgp \$29,0(\$26) + mov 0,\$16 + jsr \$26,exit + .end main +EOF + eval $set_cc_for_build + $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null + if test "$?" = 0 ; then + case `./$dummy` in + 0-0) + UNAME_MACHINE="alpha" + ;; + 1-0) + UNAME_MACHINE="alphaev5" + ;; + 1-1) + UNAME_MACHINE="alphaev56" + ;; + 1-101) + UNAME_MACHINE="alphapca56" + ;; + 2-303) + UNAME_MACHINE="alphaev6" + ;; + 2-307) + UNAME_MACHINE="alphaev67" + ;; + 2-1307) + UNAME_MACHINE="alphaev68" + ;; + esac + fi + rm -f $dummy.s $dummy + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + exit 0 ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit 0 ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit 0 ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit 0;; + amiga:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit 0 ;; + arc64:OpenBSD:*:*) + echo mips64el-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + arc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + hkmips:OpenBSD:*:*) + echo mips-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + pmax:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sgi:OpenBSD:*:*) + echo mips-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + wgrisc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit 0 ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit 0;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit 0;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit 0 ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit 0 ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + i86pc:SunOS:5.*:*) + echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit 0 ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit 0 ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit 0 ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit 0 ;; + sparc*:NetBSD:*) + echo `uname -p`-unknown-netbsd${UNAME_RELEASE} + exit 0 ;; + atari*:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit 0 ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit 0 ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit 0 ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit 0 ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit 0 ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit 0 ;; + sun3*:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mac68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme88k:OpenBSD:*:*) + echo m88k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit 0 ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit 0 ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit 0 ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit 0 ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit 0 ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD $dummy.c -o $dummy \ + && ./$dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \ + && rm -f $dummy.c $dummy && exit 0 + rm -f $dummy.c $dummy + echo mips-mips-riscos${UNAME_RELEASE} + exit 0 ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit 0 ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit 0 ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit 0 ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit 0 ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit 0 ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit 0 ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit 0 ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit 0 ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit 0 ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit 0 ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit 0 ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit 0 ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit 0 ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm -f $dummy.c $dummy && exit 0 + rm -f $dummy.c $dummy + echo rs6000-ibm-aix3.2.5 + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit 0 ;; + *:AIX:*:[45]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | head -1 | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit 0 ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit 0 ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit 0 ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit 0 ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit 0 ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit 0 ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit 0 ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit 0 ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + case "${HPUX_REV}" in + 11.[0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + esac ;; + esac + fi ;; + esac + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null ) && HP_ARCH=`./$dummy` + if test -z "$HP_ARCH"; then HP_ARCH=hppa; fi + rm -f $dummy.c $dummy + fi ;; + esac + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit 0 ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit 0 ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm -f $dummy.c $dummy && exit 0 + rm -f $dummy.c $dummy + echo unknown-hitachi-hiuxwe2 + exit 0 ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit 0 ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit 0 ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit 0 ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit 0 ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit 0 ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit 0 ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit 0 ;; + hppa*:OpenBSD:*:*) + echo hppa-unknown-openbsd + exit 0 ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit 0 ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit 0 ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit 0 ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit 0 ;; + CRAY*X-MP:*:*:*) + echo xmp-cray-unicos + exit 0 ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*T3D:*:*:*) + echo alpha-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY-2:*:*:*) + echo cray2-cray-unicos + exit 0 ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit 0 ;; + hp300:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit 0 ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit 0 ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit 0 ;; + *:FreeBSD:*:*) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit 0 ;; + *:OpenBSD:*:*) + echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + exit 0 ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit 0 ;; + i*:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit 0 ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit 0 ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i386-pc-interix + exit 0 ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit 0 ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit 0 ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + *:GNU:*:*) + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit 0 ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit 0 ;; + arm*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux + exit 0 ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + mips:Linux:*:*) + case `sed -n '/^byte/s/^.*: \(.*\) endian/\1/p' < /proc/cpuinfo` in + big) echo mips-unknown-linux-gnu && exit 0 ;; + little) echo mipsel-unknown-linux-gnu && exit 0 ;; + esac + ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-gnu + exit 0 ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-gnu + exit 0 ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} + exit 0 ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-gnu ;; + PA8*) echo hppa2.0-unknown-linux-gnu ;; + *) echo hppa-unknown-linux-gnu ;; + esac + exit 0 ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-gnu + exit 0 ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux + exit 0 ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + x86_64:Linux:*:*) + echo x86_64-unknown-linux-gnu + exit 0 ;; + i*86:Linux:*:*) + # The BFD linker knows what the default object file format is, so + # first see if it will tell us. cd to the root directory to prevent + # problems with other programs or directories called `ld' in the path. + ld_supported_targets=`cd /; ld --help 2>&1 \ + | sed -ne '/supported targets:/!d + s/[ ][ ]*/ /g + s/.*supported targets: *// + s/ .*// + p'` + case "$ld_supported_targets" in + elf32-i386) + TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" + ;; + a.out-i386-linux) + echo "${UNAME_MACHINE}-pc-linux-gnuaout" + exit 0 ;; + coff-i386) + echo "${UNAME_MACHINE}-pc-linux-gnucoff" + exit 0 ;; + "") + # Either a pre-BFD a.out linker (linux-gnuoldld) or + # one that does not give us useful --help. + echo "${UNAME_MACHINE}-pc-linux-gnuoldld" + exit 0 ;; + esac + # Determine whether the default compiler is a.out or elf + eval $set_cc_for_build + cat >$dummy.c < +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif +#ifdef __ELF__ +# ifdef __GLIBC__ +# if __GLIBC__ >= 2 + printf ("%s-pc-linux-gnu\n", argv[1]); +# else + printf ("%s-pc-linux-gnulibc1\n", argv[1]); +# endif +# else + printf ("%s-pc-linux-gnulibc1\n", argv[1]); +# endif +#else + printf ("%s-pc-linux-gnuaout\n", argv[1]); +#endif + return 0; +} +EOF + $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm -f $dummy.c $dummy && exit 0 + rm -f $dummy.c $dummy + test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0 + ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit 0 ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit 0 ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit 0 ;; + i*86:*:5:[78]*) + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit 0 ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')` + (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|egrep '^Machine.*Pent ?II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|egrep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit 0 ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit 0 ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i386. + echo i386-pc-msdosdjgpp + exit 0 ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit 0 ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit 0 ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit 0 ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit 0 ;; + M68*:*:R3V[567]*:*) + test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; + 3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4.3${OS_REL} && exit 0 + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4 && exit 0 ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit 0 ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit 0 ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit 0 ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit 0 ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit 0 ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit 0 ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit 0 ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit 0 ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit 0 ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit 0 ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit 0 ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit 0 ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit 0 ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit 0 ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit 0 ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit 0 ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit 0 ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit 0 ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit 0 ;; + *:Darwin:*:*) + echo `uname -p`-apple-darwin${UNAME_RELEASE} + exit 0 ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + if test "${UNAME_MACHINE}" = "x86pc"; then + UNAME_MACHINE=pc + fi + echo `uname -p`-${UNAME_MACHINE}-nto-qnx + exit 0 ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit 0 ;; + NSR-[KW]:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit 0 ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit 0 ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit 0 ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit 0 ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit 0 ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit 0 ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit 0 ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit 0 ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit 0 ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit 0 ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit 0 ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit 0 ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit 0 ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit 0 ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +eval $set_cc_for_build +cat >$dummy.c < +# include +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy && rm -f $dummy.c $dummy && exit 0 +rm -f $dummy.c $dummy + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit 0 ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + c34*) + echo c34-convex-bsd + exit 0 ;; + c38*) + echo c38-convex-bsd + exit 0 ;; + c4*) + echo c4-convex-bsd + exit 0 ;; + esac +fi + +cat >&2 < in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/config.h.in b/config.h.in new file mode 100644 index 0000000..3921abd --- /dev/null +++ b/config.h.in @@ -0,0 +1,64 @@ +/* config.h.in. Generated from configure.in by autoheader. */ + +/* Define to 1 if you have the header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the `ctnetlink' library (-lctnetlink). */ +#undef HAVE_LIBCTNETLINK + +/* Define to 1 if you have the `dl' library (-ldl). */ +#undef HAVE_LIBDL + +/* Define to 1 if you have the `nfnetlink' library (-lnfnetlink). */ +#undef HAVE_LIBNFNETLINK + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Version number of package */ +#undef VERSION diff --git a/config.sub b/config.sub new file mode 100644 index 0000000..393f13d --- /dev/null +++ b/config.sub @@ -0,0 +1,1411 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 +# Free Software Foundation, Inc. + +timestamp='2001-09-07' + +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file 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. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Please send patches to . +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit 0 ;; + --version | -v ) + echo "$version" ; exit 0 ;; + --help | --h* | -h ) + echo "$usage"; exit 0 ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit 0;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | storm-chaos* | os2-emx* | windows32-*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis) + os= + basic_machine=$1 + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \ + | c4x | clipper \ + | d10v | d30v | dsp16xx \ + | fr30 \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | i370 | i860 | i960 | ia64 \ + | m32r | m68000 | m68k | m88k | mcore \ + | mips16 | mips64 | mips64el | mips64orion | mips64orionel \ + | mips64vr4100 | mips64vr4100el | mips64vr4300 \ + | mips64vr4300el | mips64vr5000 | mips64vr5000el \ + | mipsbe | mipseb | mipsel | mipsle | mipstx39 | mipstx39el \ + | mipsisa32 \ + | mn10200 | mn10300 \ + | ns16k | ns32k \ + | openrisc \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ + | pyramid \ + | s390 | s390x \ + | sh | sh[34] | sh[34]eb | shbe | shle \ + | sparc | sparc64 | sparclet | sparclite | sparcv9 | sparcv9b \ + | stormy16 | strongarm \ + | tahoe | thumb | tic80 | tron \ + | v850 \ + | we32k \ + | x86 | xscale \ + | z8k) + basic_machine=$basic_machine-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12) + # Motorola 68HC11/12. + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alphapca5[67]-* | arc-* \ + | arm-* | armbe-* | armle-* | armv*-* \ + | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c54x-* \ + | clipper-* | cray2-* | cydra-* \ + | d10v-* | d30v-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fr30-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | m32r-* \ + | m68000-* | m680[01234]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | mcore-* \ + | mips-* | mips16-* | mips64-* | mips64el-* | mips64orion-* \ + | mips64orionel-* | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* | mipsbe-* | mipseb-* \ + | mipsle-* | mipsel-* | mipstx39-* | mipstx39el-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ + | pyramid-* \ + | romp-* | rs6000-* \ + | s390-* | s390x-* \ + | sh-* | sh[34]-* | sh[34]eb-* | shbe-* | shle-* \ + | sparc-* | sparc64-* | sparc86x-* | sparclite-* \ + | sparcv9-* | sparcv9b-* | stormy16-* | strongarm-* | sv1-* \ + | t3e-* | tahoe-* | thumb-* | tic30-* | tic54x-* | tic80-* | tron-* \ + | v850-* | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xmp-* | xps100-* | xscale-* \ + | ymp-* \ + | z8k-*) + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | ymp) + basic_machine=ymp-cray + os=-unicos + ;; + cray2) + basic_machine=cray2-cray + os=-unicos + ;; + [cjt]90) + basic_machine=${basic_machine}-cray + os=-unicos + ;; + crds | unos) + basic_machine=m68k-crds + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + mingw32) + basic_machine=i386-pc + os=-mingw32 + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mipsel*-linux*) + basic_machine=mipsel-unknown + os=-linux-gnu + ;; + mips*-linux*) + basic_machine=mips-unknown + os=-linux-gnu + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + mmix*) + basic_machine=mmix-knuth + os=-mmixware + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pentium | p5 | k5 | k6 | nexgen) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon) + basic_machine=i686-pc + ;; + pentiumii | pentium2) + basic_machine=i686-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sparclite-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=t3e-cray + os=-unicos + ;; + tic54x | c54x*) + basic_machine=tic54x-unknown + os=-coff + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + windows32) + basic_machine=i386-pc + os=-windows32-msvcrt + ;; + xmp) + basic_machine=xmp-cray + os=-unicos + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + mips) + if [ x$os = x-linux-gnu ]; then + basic_machine=mips-unknown + else + basic_machine=mips-mips + fi + ;; + romp) + basic_machine=romp-ibm + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh3 | sh4 | sh3eb | sh4eb) + basic_machine=sh-unknown + ;; + sparc | sparcv9 | sparcv9b) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + c4x*) + basic_machine=c4x-none + os=-coff + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \ + | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto*) + os=-nto-qnx + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + m68*-cisco) + os=-aout + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-ibm) + os=-aix + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -vxsim* | -vxworks*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit 0 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/configure.in b/configure.in new file mode 100644 index 0000000..2cdeec7 --- /dev/null +++ b/configure.in @@ -0,0 +1,88 @@ +AC_INIT + +AC_CANONICAL_SYSTEM + +AM_INIT_AUTOMAKE(conntrack, 0.50) +AM_CONFIG_HEADER(config.h) + +AC_PROG_CC +AM_PROG_LIBTOOL +AC_PROG_INSTALL +AC_PROG_LN_S + +case $target in +*-*-linux*) ;; +*) AC_MSG_ERROR([Linux only, dude!]);; +esac + +# Checks for libraries. +# FIXME: Replace `main' with a function in `-lc': +dnl AC_CHECK_LIB([c], [main]) +# FIXME: Replace `main' with a function in `-ldl': + +AC_CHECK_LIB([dl], [dlopen]) +AC_CHECK_LIB([nfnetlink], [nfnl_listen]) +AC_CHECK_LIB([ctnetlink], [ctnl_register_handler] ,,,[-lnfnetlink]) + +# Checks for header files. +dnl AC_HEADER_STDC +dnl AC_CHECK_HEADERS([netinet/in.h stdlib.h]) + +# Checks for typedefs, structures, and compiler characteristics. +dnl AC_C_CONST +dnl AC_C_INLINE + +# Checks for library functions. +dnl AC_FUNC_MALLOC +dnl AC_FUNC_VPRINTF +dnl AC_CHECK_FUNCS([memset]) + +dnl-------------------------------- + +AC_DEFUN([NF_KERNEL_SOURCE],[ + + if test "$with_kernel" = ""; then + KERNEL="`uname -r`" + else + KERNEL="$with_kernel" + fi + + THIS_PREFIX="" + for i in "/lib/modules/$KERNEL/build/include" "$KERNEL" "$KERNEL/include" "/usr/src/linux-$KERNEL" "/usr/src/kernel-$KERNEL" "/usr/src/linux-headers-$KERNEL" "/usr/src/kernel-headers-$KERNEL" + do + AC_MSG_CHECKING([Looking for kernel source or headers in $i]) + if test -r "$i/linux/config.h" + then + THIS_PREFIX="$i" + AC_MSG_RESULT([found]) + break + fi + AC_MSG_RESULT([ ]) + done + if test -r "$THIS_PREFIX/linux/config.h" ; then + AC_SUBST(KERNELDIR,[$THIS_PREFIX]) + AC_MSG_RESULT([found]) + else + AC_MSG_ERROR([not found $THIS_PREFIX]) + fi + + # somehow add this as an include path +]) + +AC_ARG_WITH(kernel, + AC_HELP_STRING([--with-kernel=DIR], + [ Show location of kernel source. Default is to use uname -r and look in /lib/modules/KERNEL/build/include. ]), + NF_KERNEL_SOURCE($with_kernel),NF_KERNEL_SOURCE()) + +CONNTRACK_LIB_DIR=$PREFIX/lib +AC_SUBST(CONNTRACK_LIB_DIR) + +dnl-------------------------------- + +dnl AC_CONFIG_FILES([Makefile +dnl debug/Makefile +dnl debug/src/Makefile +dnl extensions/Makefile +dnl src/Makefile]) + +AC_OUTPUT(Makefile src/Makefile extensions/Makefile include/Makefile) diff --git a/extensions/Makefile b/extensions/Makefile deleted file mode 100644 index e23ed90..0000000 --- a/extensions/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -CC=gcc - -all: - ${CC} -fPIC -Wall -g -c libct_proto_tcp.c - ${CC} -g -shared -Wl,-soname,libct_proto_tcp.so.0 -o libct_proto_tcp.so.0.0 libct_proto_tcp.o -lc - ln -sf libct_proto_tcp.so.0.0 libct_proto_tcp.so - - ${CC} -fPIC -Wall -g -c libct_proto_udp.c - ${CC} -g -shared -Wl,-soname,libct_proto_udp.so.0 -o libct_proto_udp.so.0.0 libct_proto_udp.o -lc - ln -sf libct_proto_udp.so.0.0 libct_proto_udp.so -clean: - rm -rf *.so *.so.* *.o diff --git a/extensions/Makefile.am b/extensions/Makefile.am new file mode 100644 index 0000000..ae78346 --- /dev/null +++ b/extensions/Makefile.am @@ -0,0 +1,14 @@ +AUTOMAKE_OPTIONS = no-dependencies foreign + +EXTRA_DIST = $(man_MANS) acinclude.m4 + +man_MANS = + +INCLUDES=-I../include -I/lib/modules/$(shell (uname -r))/build/include +CFLAGS=-fPIC -Wall +LIBS= + +lib_LTLIBRARIES = libct_proto_tcp.la libct_proto_udp.la + +libct_proto_tcp_la_SOURCES = libct_proto_tcp.c +libct_proto_udp_la_SOURCES = libct_proto_udp.c diff --git a/extensions/libct_proto_tcp.c b/extensions/libct_proto_tcp.c index 3366da4..58005b0 100644 --- a/extensions/libct_proto_tcp.c +++ b/extensions/libct_proto_tcp.c @@ -1,10 +1,19 @@ +/* + * (C) 2005 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 #include #include #include /* For htons */ #include #include -#include "../include/libct_proto.h" +#include "libct_proto.h" static struct option opts[] = { {"orig-port-src", 1, 0, '1'}, @@ -85,25 +94,33 @@ int parse(char c, char *argv[], break; } } - if (i == 10) + if (i == 10) { printf("doh?\n"); + return 0; + } } break; } return 1; } -void print(struct ip_conntrack_tuple *t) +void print_tuple(struct ip_conntrack_tuple *t) +{ + fprintf(stdout, "sport=%d dport=%d ", ntohs(t->src.u.tcp.port), + ntohs(t->dst.u.tcp.port)); +} + +void print_proto(union ip_conntrack_proto *proto) { - printf("sport=%d dport=%d ", ntohs(t->src.u.tcp.port), - ntohs(t->dst.u.tcp.port)); + fprintf(stdout, "[%s] ", states[proto->tcp.state]); } static struct ctproto_handler tcp = { .name = "tcp", .protonum = 6, .parse = parse, - .print = print, + .print_tuple = print_tuple, + .print_proto = print_proto, .opts = opts }; diff --git a/extensions/libct_proto_udp.c b/extensions/libct_proto_udp.c index cf91934..5675a05 100644 --- a/extensions/libct_proto_udp.c +++ b/extensions/libct_proto_udp.c @@ -1,10 +1,19 @@ +/* + * (C) 2005 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 #include #include #include /* For htons */ #include #include -#include "../include/libct_proto.h" +#include "libct_proto.h" static struct option opts[] = { {"orig-port-src", 1, 0, '1'}, @@ -14,6 +23,20 @@ static struct option opts[] = { {0, 0, 0, 0} }; +enum udp_param_flags { + ORIG_SPORT_BIT = 0, + ORIG_SPORT = (1 << ORIG_SPORT_BIT), + + ORIG_DPORT_BIT = 1, + ORIG_DPORT = (1 << ORIG_DPORT_BIT), + + REPL_SPORT_BIT = 2, + REPL_SPORT = (1 << REPL_SPORT_BIT), + + REPL_DPORT_BIT = 3, + REPL_DPORT = (1 << REPL_DPORT_BIT), +}; + int parse(char c, char *argv[], struct ip_conntrack_tuple *orig, struct ip_conntrack_tuple *reply, @@ -22,36 +45,44 @@ int parse(char c, char *argv[], { switch(c) { case '1': - if (optarg) + if (optarg) { orig->src.u.udp.port = htons(atoi(optarg)); + *flags |= ORIG_SPORT; + } break; case '2': - if (optarg) + if (optarg) { orig->dst.u.udp.port = htons(atoi(optarg)); + *flags |= ORIG_DPORT; + } break; case '3': - if (optarg) + if (optarg) { reply->src.u.udp.port = htons(atoi(optarg)); + *flags |= REPL_SPORT; + } break; case '4': - if (optarg) + if (optarg) { reply->dst.u.udp.port = htons(atoi(optarg)); + *flags |= REPL_DPORT; + } break; } return 1; } -void print(struct ip_conntrack_tuple *t) +void print_tuple(struct ip_conntrack_tuple *t) { - printf("sport=%d dport=%d ", ntohs(t->src.u.udp.port), - ntohs(t->dst.u.udp.port)); + fprintf(stdout, "sport=%d dport=%d ", ntohs(t->src.u.udp.port), + ntohs(t->dst.u.udp.port)); } static struct ctproto_handler udp = { .name = "udp", .protonum = 17, .parse = parse, - .print = print, + .print_tuple = print_tuple, .opts = opts }; diff --git a/include/Makefile.am b/include/Makefile.am new file mode 100644 index 0000000..f91ed48 --- /dev/null +++ b/include/Makefile.am @@ -0,0 +1,2 @@ + +include_HEADERS = libct_proto.h linux_list.h diff --git a/include/libct_proto.h b/include/libct_proto.h index 416d916..1049cef 100644 --- a/include/libct_proto.h +++ b/include/libct_proto.h @@ -1,9 +1,15 @@ #ifndef _LIBCT_PROTO_H #define _LIBCT_PROTO_H +/* FIXME: Rename this file pablo... */ + #include "linux_list.h" #include +#define CONNTRACK_LIB_DIR "/usr/local/lib" + +struct cta_proto; + struct ctproto_handler { struct list_head head; @@ -15,7 +21,8 @@ struct ctproto_handler { struct ip_conntrack_tuple *reply, union ip_conntrack_proto *proto, unsigned int *flags); - void (*print)(struct ip_conntrack_tuple *t); + void (*print_tuple)(struct ip_conntrack_tuple *t); + void (*print_proto)(union ip_conntrack_proto *proto); int (*final_check)(unsigned int flags); diff --git a/include/libctnetlink.h b/include/libctnetlink.h deleted file mode 100644 index 2cba075..0000000 --- a/include/libctnetlink.h +++ /dev/null @@ -1,72 +0,0 @@ -/* libctnetlink.h: Header file for the Connection Tracking library. - * - * Jay Schulist , Copyright (c) 2001. - * (C) 2002 by Harald Welte - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - */ - -#ifndef __LIBCTNETLINK_H -#define __LIBCTNETLINK_H - -#include -#include -#include -#include -#include -#include -#include "libnfnetlink.h" - -#define CTNL_BUFFSIZE 8192 - -struct ctnl_msg_handler { - int type; - int (*handler)(struct sockaddr_nl *, struct nlmsghdr *, void *arg); -}; - -struct ctnl_handle { - struct nfnl_handle nfnlh; - struct ctnl_msg_handler *handler[IPCTNL_MSG_COUNT]; -}; - -extern int ctnl_open(struct ctnl_handle *cth, unsigned subscriptions); -extern int ctnl_close(struct ctnl_handle *cth); -extern int ctnl_unregister_handler(struct ctnl_handle *cth, int type); -extern int ctnl_register_handler(struct ctnl_handle *cth, - struct ctnl_msg_handler *hndlr); -extern int ctnl_get_conntrack(struct ctnl_handle *cth, - struct ip_conntrack_tuple *tuple, - enum ctattr_type_t t, - unsigned long id); -extern int ctnl_del_conntrack(struct ctnl_handle *cth, - struct ip_conntrack_tuple *tuple, - enum ctattr_type_t t, - unsigned long id); -extern int ctnl_list_conntrack(struct ctnl_handle *cth, int family); - -extern int ctnl_list_expect(struct ctnl_handle *cth, int family); -extern int ctnl_del_expect(struct ctnl_handle *cth, - struct ip_conntrack_tuple *t); - -#if 0 -extern int ctnl_listen(struct ctnl_handle *ctnl, - int (*handler)(struct sockaddr_nl *, struct nlmsghdr *n, void *), - void *jarg); -extern int ctnl_talk(struct ctnl_handle *ctnl, struct nlmsghdr *n, pid_t peer, - unsigned groups, struct nlmsghdr *answer, - int (*junk)(struct sockaddr_nl *, struct nlmsghdr *n, void *), - void *jarg); -extern int ctnl_dump_request(struct ctnl_handle *cth, int type, void *req, - int len); -extern int ctnl_dump_filter(struct ctnl_handle *cth, - int (*filter)(struct sockaddr_nl *, struct nlmsghdr *n, void *), - void *arg1, - int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *), - void *arg2); -#endif - -extern int ctnl_send(struct ctnl_handle *cth, struct nlmsghdr *n); -extern int ctnl_wilddump_request(struct ctnl_handle *cth, int family, int type); - -#endif /* __LIBCTNETLINK_H */ diff --git a/include/libnfnetlink.h b/include/libnfnetlink.h deleted file mode 100644 index 944e607..0000000 --- a/include/libnfnetlink.h +++ /dev/null @@ -1,50 +0,0 @@ -/* libnfnetlink.h: Header file for generic netfilter netlink interface - * - * (C) 2002 Harald Welte - */ - -#ifndef __LIBNFNETLINK_H -#define __LIBNFNETLINK_H - -#include -#include -#include - -#define NFNL_BUFFSIZE 8192 - -struct nfnl_handle { - int fd; - struct sockaddr_nl local; - struct sockaddr_nl peer; - u_int8_t subsys_id; - u_int32_t seq; - u_int32_t dump; -}; - -/* get a new library handle */ -extern int nfnl_open(struct nfnl_handle *, u_int8_t, unsigned int); -extern int nfnl_close(struct nfnl_handle *); -extern int nfnl_send(struct nfnl_handle *, struct nlmsghdr *); - - -extern void nfnl_fill_hdr(struct nfnl_handle *, struct nlmsghdr *, int, - u_int8_t, u_int16_t, u_int16_t); - -extern int nfnl_listen(struct nfnl_handle *, - int (*)(struct sockaddr_nl *, struct nlmsghdr *, void *), - void *); - -extern int nfnl_talk(struct nfnl_handle *, struct nlmsghdr *, pid_t, - unsigned, struct nlmsghdr *, - int (*)(struct sockaddr_nl *, struct nlmsghdr *, void *), - void *); - -/* nfnl attribute handling functions */ -extern int nfnl_addattr_l(struct nlmsghdr *, int, int, void *, int); -extern int nfnl_addattr32(struct nlmsghdr *, int, int, u_int32_t); -extern int nfnl_nfa_addattr_l(struct nfattr *, int, int, void *, int); -extern int nfnl_nfa_addattr32(struct nfattr *, int, int, u_int32_t); -extern int nfnl_parse_attr(struct nfattr **, int, struct nfattr *, int); - -extern void nfnl_dump_packet(struct nlmsghdr *, int, char *); -#endif /* __LIBNFNETLINK_H */ diff --git a/install-sh b/install-sh new file mode 100644 index 0000000..e9de238 --- /dev/null +++ b/install-sh @@ -0,0 +1,251 @@ +#!/bin/sh +# +# install - install a program, script, or datafile +# This comes from X11R5 (mit/util/scripts/install.sh). +# +# Copyright 1991 by the Massachusetts Institute of Technology +# +# Permission to use, copy, modify, distribute, and sell this software and its +# documentation for any purpose is hereby granted without fee, provided that +# the above copyright notice appear in all copies and that both that +# copyright notice and this permission notice appear in supporting +# documentation, and that the name of M.I.T. not be used in advertising or +# publicity pertaining to distribution of the software without specific, +# written prior permission. M.I.T. makes no representations about the +# suitability of this software for any purpose. It is provided "as is" +# without express or implied warranty. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. It can only install one file at a time, a restriction +# shared with many OS's install programs. + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +transformbasename="" +transform_arg="" +instcmd="$mvprog" +chmodcmd="$chmodprog 0755" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" +dir_arg="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + # this colon is to work around a 386BSD /bin/sh bug + : + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +else + true +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d $dst ]; then + instcmd=: + chmodcmd="" + else + instcmd=mkdir + fi +else + +# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f $src -o -d $src ] + then + true + else + echo "install: $src does not exist" + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "install: no destination specified" + exit 1 + else + true + fi + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + + if [ -d $dst ] + then + dst="$dst"/`basename $src` + else + true + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' +' +IFS="${IFS-${defaultIFS}}" + +oIFS="${IFS}" +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS="${oIFS}" + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp="${pathcomp}${1}" + shift + + if [ ! -d "${pathcomp}" ] ; + then + $mkdirprog "${pathcomp}" + else + true + fi + + pathcomp="${pathcomp}/" +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd $dst && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi +else + +# If we're going to rename the final executable, determine the name now. + + if [ x"$transformarg" = x ] + then + dstfile=`basename $dst` + else + dstfile=`basename $dst $transformbasename | + sed $transformarg`$transformbasename + fi + +# don't allow the sed command to completely eliminate the filename + + if [ x"$dstfile" = x ] + then + dstfile=`basename $dst` + else + true + fi + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + + $doit $instcmd $src $dsttmp && + + trap "rm -f ${dsttmp}" 0 && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && + +# Now rename the file to the real destination. + + $doit $rmcmd -f $dstdir/$dstfile && + $doit $mvcmd $dsttmp $dstdir/$dstfile + +fi && + + +exit 0 diff --git a/ltmain.sh b/ltmain.sh new file mode 100644 index 0000000..1a224ac --- /dev/null +++ b/ltmain.sh @@ -0,0 +1,6426 @@ +# ltmain.sh - Provide generalized library-building support services. +# NOTE: Changing this file will not affect anything until you rerun configure. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004 +# Free Software Foundation, Inc. +# Originally by Gordon Matzigkeit , 1996 +# +# 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. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +basename="s,^.*/,,g" + +# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh +# is ksh but when the shell is invoked as "sh" and the current value of +# the _XPG environment variable is not equal to 1 (one), the special +# positional parameter $0, within a function call, is the name of the +# function. +progpath="$0" + +# The name of this program: +progname=`echo "$progpath" | $SED $basename` +modename="$progname" + +# Global variables: +EXIT_SUCCESS=0 +EXIT_FAILURE=1 + +PROGRAM=ltmain.sh +PACKAGE=libtool +VERSION=1.5.6 +TIMESTAMP=" (1.1220.2.95 2004/04/11 05:50:42) Debian$Rev: 224 $" + + +# Check that we have a working $echo. +if test "X$1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X$1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then + # Yippee, $echo works! + : +else + # Restart under the correct shell, and then maybe $echo will work. + exec $SHELL "$progpath" --no-reexec ${1+"$@"} +fi + +if test "X$1" = X--fallback-echo; then + # used as fallback echo + shift + cat <&2 + $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit $EXIT_FAILURE +fi + +# Global variables. +mode=$default_mode +nonopt= +prev= +prevopt= +run= +show="$echo" +show_help= +execute_dlfiles= +lo2o="s/\\.lo\$/.${objext}/" +o2lo="s/\\.${objext}\$/.lo/" + +##################################### +# Shell function definitions: +# This seems to be the best place for them + +# func_win32_libid arg +# return the library type of file 'arg' +# +# Need a lot of goo to handle *both* DLLs and import libs +# Has to be a shell function in order to 'eat' the argument +# that is supplied when $file_magic_command is called. +func_win32_libid () { + win32_libid_type="unknown" + win32_fileres=`file -L $1 2>/dev/null` + case $win32_fileres in + *ar\ archive\ import\ library*) # definitely import + win32_libid_type="x86 archive import" + ;; + *ar\ archive*) # could be an import, or static + if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | \ + $EGREP -e 'file format pe-i386(.*architecture: i386)?' >/dev/null ; then + win32_nmres=`eval $NM -f posix -A $1 | \ + sed -n -e '1,100{/ I /{x;/import/!{s/^/import/;h;p;};x;};}'` + if test "X$win32_nmres" = "Ximport" ; then + win32_libid_type="x86 archive import" + else + win32_libid_type="x86 archive static" + fi + fi + ;; + *DLL*) + win32_libid_type="x86 DLL" + ;; + *executable*) # but shell scripts are "executable" too... + case $win32_fileres in + *MS\ Windows\ PE\ Intel*) + win32_libid_type="x86 DLL" + ;; + esac + ;; + esac + $echo $win32_libid_type +} + + +# func_infer_tag arg +# Infer tagged configuration to use if any are available and +# if one wasn't chosen via the "--tag" command line option. +# Only attempt this if the compiler in the base compile +# command doesn't match the default compiler. +# arg is usually of the form 'gcc ...' +func_infer_tag () { + if test -n "$available_tags" && test -z "$tagname"; then + CC_quoted= + for arg in $CC; do + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + CC_quoted="$CC_quoted $arg" + done + case $@ in + # Blanks in the command may have been stripped by the calling shell, + # but not from the CC environment variable when configure was run. + " $CC "* | "$CC "* | " `$echo $CC` "* | "`$echo $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$echo $CC_quoted` "* | "`$echo $CC_quoted` "*) ;; + # Blanks at the start of $base_compile will cause this to fail + # if we don't check for them as well. + *) + for z in $available_tags; do + if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then + # Evaluate the configuration. + eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" + CC_quoted= + for arg in $CC; do + # Double-quote args containing other shell metacharacters. + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + CC_quoted="$CC_quoted $arg" + done + case "$@ " in + " $CC "* | "$CC "* | " `$echo $CC` "* | "`$echo $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$echo $CC_quoted` "* | "`$echo $CC_quoted` "*) + # The compiler in the base compile command matches + # the one in the tagged configuration. + # Assume this is the tagged configuration we want. + tagname=$z + break + ;; + esac + fi + done + # If $tagname still isn't set, then no tagged configuration + # was found and let the user know that the "--tag" command + # line option must be used. + if test -z "$tagname"; then + $echo "$modename: unable to infer tagged configuration" + $echo "$modename: specify a tag with \`--tag'" 1>&2 + exit $EXIT_FAILURE +# else +# $echo "$modename: using $tagname tagged configuration" + fi + ;; + esac + fi +} +# End of Shell function definitions +##################################### + +# Darwin sucks +eval std_shrext=\"$shrext_cmds\" + +# Parse our command line options once, thoroughly. +while test "$#" -gt 0 +do + arg="$1" + shift + + case $arg in + -*=*) optarg=`$echo "X$arg" | $Xsed -e 's/[-_a-zA-Z0-9]*=//'` ;; + *) optarg= ;; + esac + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case $prev in + execute_dlfiles) + execute_dlfiles="$execute_dlfiles $arg" + ;; + tag) + tagname="$arg" + preserve_args="${preserve_args}=$arg" + + # Check whether tagname contains only valid characters + case $tagname in + *[!-_A-Za-z0-9,/]*) + $echo "$progname: invalid tag name: $tagname" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + case $tagname in + CC) + # Don't test for the "default" C tag, as we know, it's there, but + # not specially marked. + ;; + *) + if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "$progpath" > /dev/null; then + taglist="$taglist $tagname" + # Evaluate the configuration. + eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$tagname'$/,/^# ### END LIBTOOL TAG CONFIG: '$tagname'$/p' < $progpath`" + else + $echo "$progname: ignoring unknown tag $tagname" 1>&2 + fi + ;; + esac + ;; + *) + eval "$prev=\$arg" + ;; + esac + + prev= + prevopt= + continue + fi + + # Have we seen a non-optional argument yet? + case $arg in + --help) + show_help=yes + ;; + + --version) + $echo "$PROGRAM (GNU $PACKAGE) $VERSION$TIMESTAMP" + $echo + $echo "Copyright (C) 2003 Free Software Foundation, Inc." + $echo "This is free software; see the source for copying conditions. There is NO" + $echo "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + exit $EXIT_SUCCESS + ;; + + --config) + ${SED} -e '1,/^# ### BEGIN LIBTOOL CONFIG/d' -e '/^# ### END LIBTOOL CONFIG/,$d' $progpath + # Now print the configurations for the tags. + for tagname in $taglist; do + ${SED} -n -e "/^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$/,/^# ### END LIBTOOL TAG CONFIG: $tagname$/p" < "$progpath" + done + exit $EXIT_SUCCESS + ;; + + --debug) + $echo "$progname: enabling shell trace mode" + set -x + preserve_args="$preserve_args $arg" + ;; + + --dry-run | -n) + run=: + ;; + + --features) + $echo "host: $host" + if test "$build_libtool_libs" = yes; then + $echo "enable shared libraries" + else + $echo "disable shared libraries" + fi + if test "$build_old_libs" = yes; then + $echo "enable static libraries" + else + $echo "disable static libraries" + fi + exit $EXIT_SUCCESS + ;; + + --finish) mode="finish" ;; + + --mode) prevopt="--mode" prev=mode ;; + --mode=*) mode="$optarg" ;; + + --preserve-dup-deps) duplicate_deps="yes" ;; + + --quiet | --silent) + show=: + preserve_args="$preserve_args $arg" + ;; + + --tag) prevopt="--tag" prev=tag ;; + --tag=*) + set tag "$optarg" ${1+"$@"} + shift + prev=tag + preserve_args="$preserve_args --tag" + ;; + + -dlopen) + prevopt="-dlopen" + prev=execute_dlfiles + ;; + + -*) + $echo "$modename: unrecognized option \`$arg'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + ;; + + *) + nonopt="$arg" + break + ;; + esac +done + +if test -n "$prevopt"; then + $echo "$modename: option \`$prevopt' requires an argument" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE +fi + +# If this variable is set in any of the actions, the command in it +# will be execed at the end. This prevents here-documents from being +# left over by shells. +exec_cmd= + +if test -z "$show_help"; then + + # Infer the operation mode. + if test -z "$mode"; then + $echo "*** Warning: inferring the mode of operation is deprecated." 1>&2 + $echo "*** Future versions of Libtool will require -mode=MODE be specified." 1>&2 + case $nonopt in + *cc | cc* | *++ | gcc* | *-gcc* | g++* | xlc*) + mode=link + for arg + do + case $arg in + -c) + mode=compile + break + ;; + esac + done + ;; + *db | *dbx | *strace | *truss) + mode=execute + ;; + *install*|cp|mv) + mode=install + ;; + *rm) + mode=uninstall + ;; + *) + # If we have no mode, but dlfiles were specified, then do execute mode. + test -n "$execute_dlfiles" && mode=execute + + # Just use the default operation mode. + if test -z "$mode"; then + if test -n "$nonopt"; then + $echo "$modename: warning: cannot infer operation mode from \`$nonopt'" 1>&2 + else + $echo "$modename: warning: cannot infer operation mode without MODE-ARGS" 1>&2 + fi + fi + ;; + esac + fi + + # Only execute mode is allowed to have -dlopen flags. + if test -n "$execute_dlfiles" && test "$mode" != execute; then + $echo "$modename: unrecognized option \`-dlopen'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Change the help message to a mode-specific one. + generic_help="$help" + help="Try \`$modename --help --mode=$mode' for more information." + + # These modes are in order of execution frequency so that they run quickly. + case $mode in + # libtool compile mode + compile) + modename="$modename: compile" + # Get the compilation command and the source file. + base_compile= + srcfile="$nonopt" # always keep a non-empty value in "srcfile" + suppress_opt=yes + suppress_output= + arg_mode=normal + libobj= + later= + + for arg + do + case "$arg_mode" in + arg ) + # do not "continue". Instead, add this to base_compile + lastarg="$arg" + arg_mode=normal + ;; + + target ) + libobj="$arg" + arg_mode=normal + continue + ;; + + normal ) + # Accept any command-line options. + case $arg in + -o) + if test -n "$libobj" ; then + $echo "$modename: you cannot specify \`-o' more than once" 1>&2 + exit $EXIT_FAILURE + fi + arg_mode=target + continue + ;; + + -static | -prefer-pic | -prefer-non-pic) + later="$later $arg" + continue + ;; + + -no-suppress) + suppress_opt=no + continue + ;; + + -Xcompiler) + arg_mode=arg # the next one goes into the "base_compile" arg list + continue # The current "srcfile" will either be retained or + ;; # replaced later. I would guess that would be a bug. + + -Wc,*) + args=`$echo "X$arg" | $Xsed -e "s/^-Wc,//"` + lastarg= + save_ifs="$IFS"; IFS=',' + for arg in $args; do + IFS="$save_ifs" + + # Double-quote args containing other shell metacharacters. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + lastarg="$lastarg $arg" + done + IFS="$save_ifs" + lastarg=`$echo "X$lastarg" | $Xsed -e "s/^ //"` + + # Add the arguments to base_compile. + base_compile="$base_compile $lastarg" + continue + ;; + + * ) + # Accept the current argument as the source file. + # The previous "srcfile" becomes the current argument. + # + lastarg="$srcfile" + srcfile="$arg" + ;; + esac # case $arg + ;; + esac # case $arg_mode + + # Aesthetically quote the previous argument. + lastarg=`$echo "X$lastarg" | $Xsed -e "$sed_quote_subst"` + + case $lastarg in + # Double-quote args containing other shell metacharacters. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + lastarg="\"$lastarg\"" + ;; + esac + + base_compile="$base_compile $lastarg" + done # for arg + + case $arg_mode in + arg) + $echo "$modename: you must specify an argument for -Xcompile" + exit $EXIT_FAILURE + ;; + target) + $echo "$modename: you must specify a target with \`-o'" 1>&2 + exit $EXIT_FAILURE + ;; + *) + # Get the name of the library object. + [ -z "$libobj" ] && libobj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%'` + ;; + esac + + # Recognize several different file suffixes. + # If the user specifies -o file.o, it is replaced with file.lo + xform='[cCFSifmso]' + case $libobj in + *.ada) xform=ada ;; + *.adb) xform=adb ;; + *.ads) xform=ads ;; + *.asm) xform=asm ;; + *.c++) xform=c++ ;; + *.cc) xform=cc ;; + *.ii) xform=ii ;; + *.class) xform=class ;; + *.cpp) xform=cpp ;; + *.cxx) xform=cxx ;; + *.f90) xform=f90 ;; + *.for) xform=for ;; + *.java) xform=java ;; + esac + + libobj=`$echo "X$libobj" | $Xsed -e "s/\.$xform$/.lo/"` + + case $libobj in + *.lo) obj=`$echo "X$libobj" | $Xsed -e "$lo2o"` ;; + *) + $echo "$modename: cannot determine name of library object from \`$libobj'" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + func_infer_tag $base_compile + + for arg in $later; do + case $arg in + -static) + build_old_libs=yes + continue + ;; + + -prefer-pic) + pic_mode=yes + continue + ;; + + -prefer-non-pic) + pic_mode=no + continue + ;; + esac + done + + objname=`$echo "X$obj" | $Xsed -e 's%^.*/%%'` + xdir=`$echo "X$obj" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$obj"; then + xdir= + else + xdir=$xdir/ + fi + lobj=${xdir}$objdir/$objname + + if test -z "$base_compile"; then + $echo "$modename: you must specify a compilation command" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Delete any leftover library objects. + if test "$build_old_libs" = yes; then + removelist="$obj $lobj $libobj ${libobj}T" + else + removelist="$lobj $libobj ${libobj}T" + fi + + $run $rm $removelist + trap "$run $rm $removelist; exit $EXIT_FAILURE" 1 2 15 + + # On Cygwin there's no "real" PIC flag so we must build both object types + case $host_os in + cygwin* | mingw* | pw32* | os2*) + pic_mode=default + ;; + esac + if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then + # non-PIC code in shared libraries is not supported + pic_mode=default + fi + + # Calculate the filename of the output object if compiler does + # not support -o with -c + if test "$compiler_c_o" = no; then + output_obj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\.[^.]*$%%'`.${objext} + lockfile="$output_obj.lock" + removelist="$removelist $output_obj $lockfile" + trap "$run $rm $removelist; exit $EXIT_FAILURE" 1 2 15 + else + output_obj= + need_locks=no + lockfile= + fi + + # Lock this critical section if it is needed + # We use this script file to make the link, it avoids creating a new file + if test "$need_locks" = yes; then + until $run ln "$progpath" "$lockfile" 2>/dev/null; do + $show "Waiting for $lockfile to be removed" + sleep 2 + done + elif test "$need_locks" = warn; then + if test -f "$lockfile"; then + $echo "\ +*** ERROR, $lockfile exists and contains: +`cat $lockfile 2>/dev/null` + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $run $rm $removelist + exit $EXIT_FAILURE + fi + $echo $srcfile > "$lockfile" + fi + + if test -n "$fix_srcfile_path"; then + eval srcfile=\"$fix_srcfile_path\" + fi + + $run $rm "$libobj" "${libobj}T" + + # Create a libtool object file (analogous to a ".la" file), + # but don't create it if we're doing a dry run. + test -z "$run" && cat > ${libobj}T </dev/null`" != "X$srcfile"; then + $echo "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $run $rm $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed, then go on to compile the next one + if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then + $show "$mv $output_obj $lobj" + if $run $mv $output_obj $lobj; then : + else + error=$? + $run $rm $removelist + exit $error + fi + fi + + # Append the name of the PIC object to the libtool object file. + test -z "$run" && cat >> ${libobj}T <> ${libobj}T </dev/null`" != "X$srcfile"; then + $echo "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $run $rm $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed + if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then + $show "$mv $output_obj $obj" + if $run $mv $output_obj $obj; then : + else + error=$? + $run $rm $removelist + exit $error + fi + fi + + # Append the name of the non-PIC object the libtool object file. + # Only append if the libtool object file exists. + test -z "$run" && cat >> ${libobj}T <> ${libobj}T <&2 + fi + if test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + else + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + fi + build_libtool_libs=no + build_old_libs=yes + prefer_static_libs=yes + break + ;; + esac + done + + # See if our shared archives depend on static archives. + test -n "$old_archive_from_new_cmds" && build_old_libs=yes + + # Go through the arguments, transforming them on the way. + while test "$#" -gt 0; do + arg="$1" + shift + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + qarg=\"`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`\" ### testsuite: skip nested quoting test + ;; + *) qarg=$arg ;; + esac + libtool_args="$libtool_args $qarg" + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case $prev in + output) + compile_command="$compile_command @OUTPUT@" + finalize_command="$finalize_command @OUTPUT@" + ;; + esac + + case $prev in + dlfiles|dlprefiles) + if test "$preload" = no; then + # Add the symbol object into the linking commands. + compile_command="$compile_command @SYMFILE@" + finalize_command="$finalize_command @SYMFILE@" + preload=yes + fi + case $arg in + *.la | *.lo) ;; # We handle these cases below. + force) + if test "$dlself" = no; then + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + self) + if test "$prev" = dlprefiles; then + dlself=yes + elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then + dlself=yes + else + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + *) + if test "$prev" = dlfiles; then + dlfiles="$dlfiles $arg" + else + dlprefiles="$dlprefiles $arg" + fi + prev= + continue + ;; + esac + ;; + expsyms) + export_symbols="$arg" + if test ! -f "$arg"; then + $echo "$modename: symbol file \`$arg' does not exist" + exit $EXIT_FAILURE + fi + prev= + continue + ;; + expsyms_regex) + export_symbols_regex="$arg" + prev= + continue + ;; + inst_prefix) + inst_prefix_dir="$arg" + prev= + continue + ;; + precious_regex) + precious_files_regex="$arg" + prev= + continue + ;; + release) + release="-$arg" + prev= + continue + ;; + objectlist) + if test -f "$arg"; then + save_arg=$arg + moreargs= + for fil in `cat $save_arg` + do +# moreargs="$moreargs $fil" + arg=$fil + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if (${SED} -e '2q' $arg | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + pic_object= + non_pic_object= + + # Read the .lo file + # If there is no directory component, then add one. + case $arg in + */* | *\\*) . $arg ;; + *) . ./$arg ;; + esac + + if test -z "$pic_object" || \ + test -z "$non_pic_object" || + test "$pic_object" = none && \ + test "$non_pic_object" = none; then + $echo "$modename: cannot find name of object for \`$arg'" 1>&2 + exit $EXIT_FAILURE + fi + + # Extract subdirectory from the argument. + xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$arg"; then + xdir= + else + xdir="$xdir/" + fi + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + dlfiles="$dlfiles $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + dlprefiles="$dlprefiles $pic_object" + prev= + fi + + # A PIC object. + libobjs="$libobjs $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + non_pic_objects="$non_pic_objects $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + fi + else + # Only an error if not doing a dry-run. + if test -z "$run"; then + $echo "$modename: \`$arg' is not a valid libtool object" 1>&2 + exit $EXIT_FAILURE + else + # Dry-run case. + + # Extract subdirectory from the argument. + xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$arg"; then + xdir= + else + xdir="$xdir/" + fi + + pic_object=`$echo "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"` + non_pic_object=`$echo "X${xdir}${arg}" | $Xsed -e "$lo2o"` + libobjs="$libobjs $pic_object" + non_pic_objects="$non_pic_objects $non_pic_object" + fi + fi + done + else + $echo "$modename: link input file \`$save_arg' does not exist" + exit $EXIT_FAILURE + fi + arg=$save_arg + prev= + continue + ;; + rpath | xrpath) + # We need an absolute path. + case $arg in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + $echo "$modename: only absolute run-paths are allowed" 1>&2 + exit $EXIT_FAILURE + ;; + esac + if test "$prev" = rpath; then + case "$rpath " in + *" $arg "*) ;; + *) rpath="$rpath $arg" ;; + esac + else + case "$xrpath " in + *" $arg "*) ;; + *) xrpath="$xrpath $arg" ;; + esac + fi + prev= + continue + ;; + xcompiler) + compiler_flags="$compiler_flags $qarg" + prev= + compile_command="$compile_command $qarg" + finalize_command="$finalize_command $qarg" + continue + ;; + xlinker) + linker_flags="$linker_flags $qarg" + compiler_flags="$compiler_flags $wl$qarg" + prev= + compile_command="$compile_command $wl$qarg" + finalize_command="$finalize_command $wl$qarg" + continue + ;; + xcclinker) + linker_flags="$linker_flags $qarg" + compiler_flags="$compiler_flags $qarg" + prev= + compile_command="$compile_command $qarg" + finalize_command="$finalize_command $qarg" + continue + ;; + shrext) + shrext_cmds="$arg" + prev= + continue + ;; + *) + eval "$prev=\"\$arg\"" + prev= + continue + ;; + esac + fi # test -n "$prev" + + prevarg="$arg" + + case $arg in + -all-static) + if test -n "$link_static_flag"; then + compile_command="$compile_command $link_static_flag" + finalize_command="$finalize_command $link_static_flag" + fi + continue + ;; + + -allow-undefined) + # FIXME: remove this flag sometime in the future. + $echo "$modename: \`-allow-undefined' is deprecated because it is the default" 1>&2 + continue + ;; + + -avoid-version) + avoid_version=yes + continue + ;; + + -dlopen) + prev=dlfiles + continue + ;; + + -dlpreopen) + prev=dlprefiles + continue + ;; + + -export-dynamic) + export_dynamic=yes + continue + ;; + + -export-symbols | -export-symbols-regex) + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + $echo "$modename: more than one -exported-symbols argument is not allowed" + exit $EXIT_FAILURE + fi + if test "X$arg" = "X-export-symbols"; then + prev=expsyms + else + prev=expsyms_regex + fi + continue + ;; + + -inst-prefix-dir) + prev=inst_prefix + continue + ;; + + # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* + # so, if we see these flags be careful not to treat them like -L + -L[A-Z][A-Z]*:*) + case $with_gcc/$host in + no/*-*-irix* | /*-*-irix*) + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + ;; + esac + continue + ;; + + -L*) + dir=`$echo "X$arg" | $Xsed -e 's/^-L//'` + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + $echo "$modename: cannot determine absolute directory name of \`$dir'" 1>&2 + exit $EXIT_FAILURE + fi + dir="$absdir" + ;; + esac + case "$deplibs " in + *" -L$dir "*) ;; + *) + deplibs="$deplibs -L$dir" + lib_search_path="$lib_search_path $dir" + ;; + esac + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) + case :$dllsearchpath: in + *":$dir:"*) ;; + *) dllsearchpath="$dllsearchpath:$dir";; + esac + ;; + esac + continue + ;; + + -l*) + if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then + case $host in + *-*-cygwin* | *-*-pw32* | *-*-beos*) + # These systems don't actually have a C or math library (as such) + continue + ;; + *-*-mingw* | *-*-os2*) + # These systems don't actually have a C library (as such) + test "X$arg" = "X-lc" && continue + ;; + *-*-openbsd* | *-*-freebsd*) + # Do not include libc due to us having libc/libc_r. + test "X$arg" = "X-lc" && continue + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C and math libraries are in the System framework + deplibs="$deplibs -framework System" + continue + esac + elif test "X$arg" = "X-lc_r"; then + case $host in + *-*-openbsd* | *-*-freebsd*) + # Do not include libc_r directly, use -pthread flag. + continue + ;; + esac + fi + deplibs="$deplibs $arg" + continue + ;; + + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe) + deplibs="$deplibs $arg" + continue + ;; + + -module) + module=yes + continue + ;; + + # gcc -m* arguments should be passed to the linker via $compiler_flags + # in order to pass architecture information to the linker + # (e.g. 32 vs 64-bit). This may also be accomplished via -Wl,-mfoo + # but this is not reliable with gcc because gcc may use -mfoo to + # select a different linker, different libraries, etc, while + # -Wl,-mfoo simply passes -mfoo to the linker. + -m*) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + if test "$with_gcc" = "yes" ; then + compiler_flags="$compiler_flags $arg" + fi + continue + ;; + + -shrext) + prev=shrext + continue + ;; + + -no-fast-install) + fast_install=no + continue + ;; + + -no-install) + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) + # The PATH hackery in wrapper scripts is required on Windows + # in order for the loader to find any dlls it needs. + $echo "$modename: warning: \`-no-install' is ignored for $host" 1>&2 + $echo "$modename: warning: assuming \`-no-fast-install' instead" 1>&2 + fast_install=no + ;; + *) no_install=yes ;; + esac + continue + ;; + + -no-undefined) + allow_undefined=no + continue + ;; + + -objectlist) + prev=objectlist + continue + ;; + + -o) prev=output ;; + + -precious-files-regex) + prev=precious_regex + continue + ;; + + -release) + prev=release + continue + ;; + + -rpath) + prev=rpath + continue + ;; + + -R) + prev=xrpath + continue + ;; + + -R*) + dir=`$echo "X$arg" | $Xsed -e 's/^-R//'` + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + $echo "$modename: only absolute run-paths are allowed" 1>&2 + exit $EXIT_FAILURE + ;; + esac + case "$xrpath " in + *" $dir "*) ;; + *) xrpath="$xrpath $dir" ;; + esac + continue + ;; + + -static) + # The effects of -static are defined in a previous loop. + # We used to do the same as -all-static on platforms that + # didn't have a PIC flag, but the assumption that the effects + # would be equivalent was wrong. It would break on at least + # Digital Unix and AIX. + continue + ;; + + -thread-safe) + thread_safe=yes + continue + ;; + + -version-info) + prev=vinfo + continue + ;; + -version-number) + prev=vinfo + vinfo_number=yes + continue + ;; + + -Wc,*) + args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wc,//'` + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + case $flag in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + flag="\"$flag\"" + ;; + esac + arg="$arg $wl$flag" + compiler_flags="$compiler_flags $flag" + done + IFS="$save_ifs" + arg=`$echo "X$arg" | $Xsed -e "s/^ //"` + ;; + + -Wl,*) + args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wl,//'` + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + case $flag in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + flag="\"$flag\"" + ;; + esac + arg="$arg $wl$flag" + compiler_flags="$compiler_flags $wl$flag" + linker_flags="$linker_flags $flag" + done + IFS="$save_ifs" + arg=`$echo "X$arg" | $Xsed -e "s/^ //"` + ;; + + -Xcompiler) + prev=xcompiler + continue + ;; + + -Xlinker) + prev=xlinker + continue + ;; + + -XCClinker) + prev=xcclinker + continue + ;; + + # Some other compiler flag. + -* | +*) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + ;; + + *.$objext) + # A standard object. + objs="$objs $arg" + ;; + + *.lo) + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if (${SED} -e '2q' $arg | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + pic_object= + non_pic_object= + + # Read the .lo file + # If there is no directory component, then add one. + case $arg in + */* | *\\*) . $arg ;; + *) . ./$arg ;; + esac + + if test -z "$pic_object" || \ + test -z "$non_pic_object" || + test "$pic_object" = none && \ + test "$non_pic_object" = none; then + $echo "$modename: cannot find name of object for \`$arg'" 1>&2 + exit $EXIT_FAILURE + fi + + # Extract subdirectory from the argument. + xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$arg"; then + xdir= + else + xdir="$xdir/" + fi + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + dlfiles="$dlfiles $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + dlprefiles="$dlprefiles $pic_object" + prev= + fi + + # A PIC object. + libobjs="$libobjs $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + non_pic_objects="$non_pic_objects $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + fi + else + # Only an error if not doing a dry-run. + if test -z "$run"; then + $echo "$modename: \`$arg' is not a valid libtool object" 1>&2 + exit $EXIT_FAILURE + else + # Dry-run case. + + # Extract subdirectory from the argument. + xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$arg"; then + xdir= + else + xdir="$xdir/" + fi + + pic_object=`$echo "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"` + non_pic_object=`$echo "X${xdir}${arg}" | $Xsed -e "$lo2o"` + libobjs="$libobjs $pic_object" + non_pic_objects="$non_pic_objects $non_pic_object" + fi + fi + ;; + + *.$libext) + # An archive. + deplibs="$deplibs $arg" + old_deplibs="$old_deplibs $arg" + continue + ;; + + *.la) + # A libtool-controlled library. + + if test "$prev" = dlfiles; then + # This library was specified with -dlopen. + dlfiles="$dlfiles $arg" + prev= + elif test "$prev" = dlprefiles; then + # The library was specified with -dlpreopen. + dlprefiles="$dlprefiles $arg" + prev= + else + deplibs="$deplibs $arg" + fi + continue + ;; + + # Some other compiler argument. + *) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + ;; + esac # arg + + # Now actually substitute the argument into the commands. + if test -n "$arg"; then + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + fi + done # argument parsing loop + + if test -n "$prev"; then + $echo "$modename: the \`$prevarg' option requires an argument" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then + eval arg=\"$export_dynamic_flag_spec\" + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + fi + + oldlibs= + # calculate the name of the file, without its directory + outputname=`$echo "X$output" | $Xsed -e 's%^.*/%%'` + libobjs_save="$libobjs" + + if test -n "$shlibpath_var"; then + # get the directories listed in $shlibpath_var + eval shlib_search_path=\`\$echo \"X\${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\` + else + shlib_search_path= + fi + eval sys_lib_search_path=\"$sys_lib_search_path_spec\" + eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" + + output_objdir=`$echo "X$output" | $Xsed -e 's%/[^/]*$%%'` + if test "X$output_objdir" = "X$output"; then + output_objdir="$objdir" + else + output_objdir="$output_objdir/$objdir" + fi + # Create the object directory. + if test ! -d "$output_objdir"; then + $show "$mkdir $output_objdir" + $run $mkdir $output_objdir + status=$? + if test "$status" -ne 0 && test ! -d "$output_objdir"; then + exit $status + fi + fi + + # Determine the type of output + case $output in + "") + $echo "$modename: you must specify an output file" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + ;; + *.$libext) linkmode=oldlib ;; + *.lo | *.$objext) linkmode=obj ;; + *.la) linkmode=lib ;; + *) linkmode=prog ;; # Anything else should be a program. + esac + + case $host in + *cygwin* | *mingw* | *pw32*) + # don't eliminate duplications in $postdeps and $predeps + duplicate_compiler_generated_deps=yes + ;; + *) + duplicate_compiler_generated_deps=$duplicate_deps + ;; + esac + specialdeplibs= + + libs= + # Find all interdependent deplibs by searching for libraries + # that are linked more than once (e.g. -la -lb -la) + for deplib in $deplibs; do + if test "X$duplicate_deps" = "Xyes" ; then + case "$libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + libs="$libs $deplib" + done + + if test "$linkmode" = lib; then + libs="$predeps $libs $compiler_lib_search_path $postdeps" + + # Compute libraries that are listed more than once in $predeps + # $postdeps and mark them as special (i.e., whose duplicates are + # not to be eliminated). + pre_post_deps= + if test "X$duplicate_compiler_generated_deps" = "Xyes" ; then + for pre_post_dep in $predeps $postdeps; do + case "$pre_post_deps " in + *" $pre_post_dep "*) specialdeplibs="$specialdeplibs $pre_post_deps" ;; + esac + pre_post_deps="$pre_post_deps $pre_post_dep" + done + fi + pre_post_deps= + fi + + deplibs= + newdependency_libs= + newlib_search_path= + need_relink=no # whether we're linking any uninstalled libtool libraries + notinst_deplibs= # not-installed libtool libraries + notinst_path= # paths that contain not-installed libtool libraries + case $linkmode in + lib) + passes="conv link" + for file in $dlfiles $dlprefiles; do + case $file in + *.la) ;; + *) + $echo "$modename: libraries can \`-dlopen' only libtool libraries: $file" 1>&2 + exit $EXIT_FAILURE + ;; + esac + done + ;; + prog) + compile_deplibs= + finalize_deplibs= + alldeplibs=no + newdlfiles= + newdlprefiles= + passes="conv scan dlopen dlpreopen link" + ;; + *) passes="conv" + ;; + esac + for pass in $passes; do + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan"; then + libs="$deplibs" + deplibs= + fi + if test "$linkmode" = prog; then + case $pass in + dlopen) libs="$dlfiles" ;; + dlpreopen) libs="$dlprefiles" ;; + link) + libs="$deplibs %DEPLIBS%" + test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs" + ;; + esac + fi + if test "$pass" = dlopen; then + # Collect dlpreopened libraries + save_deplibs="$deplibs" + deplibs= + fi + for deplib in $libs; do + lib= + found=no + case $deplib in + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe) + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + fi + continue + ;; + -l*) + if test "$linkmode" != lib && test "$linkmode" != prog; then + $echo "$modename: warning: \`-l' is ignored for archives/objects" 1>&2 + continue + fi + name=`$echo "X$deplib" | $Xsed -e 's/^-l//'` + for searchdir in $newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path; do + for search_ext in .la $std_shrext .so .a; do + # Search the libtool library + lib="$searchdir/lib${name}${search_ext}" + if test -f "$lib"; then + if test "$search_ext" = ".la"; then + found=yes + else + found=no + fi + break 2 + fi + done + done + if test "$found" != yes; then + # deplib doesn't seem to be a libtool library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + else # deplib is a libtool library + # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, + # We need to do some special things here, and not later. + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $deplib "*) + if (${SED} -e '2q' $lib | + grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + library_names= + old_library= + case $lib in + */* | *\\*) . $lib ;; + *) . ./$lib ;; + esac + for l in $old_library $library_names; do + ll="$l" + done + if test "X$ll" = "X$old_library" ; then # only static version available + found=no + ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'` + test "X$ladir" = "X$lib" && ladir="." + lib=$ladir/$old_library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + fi + fi + ;; + *) ;; + esac + fi + fi + ;; # -l + -L*) + case $linkmode in + lib) + deplibs="$deplib $deplibs" + test "$pass" = conv && continue + newdependency_libs="$deplib $newdependency_libs" + newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'` + ;; + prog) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + if test "$pass" = scan; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'` + ;; + *) + $echo "$modename: warning: \`-L' is ignored for archives/objects" 1>&2 + ;; + esac # linkmode + continue + ;; # -L + -R*) + if test "$pass" = link; then + dir=`$echo "X$deplib" | $Xsed -e 's/^-R//'` + # Make sure the xrpath contains only unique directories. + case "$xrpath " in + *" $dir "*) ;; + *) xrpath="$xrpath $dir" ;; + esac + fi + deplibs="$deplib $deplibs" + continue + ;; + *.la) lib="$deplib" ;; + *.$libext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + case $linkmode in + lib) + if test "$deplibs_check_method" != pass_all; then + $echo + $echo "*** Warning: Trying to link with static lib archive $deplib." + $echo "*** I have the capability to make that library automatically link in when" + $echo "*** you link to this library. But I can only do this if you have a" + $echo "*** shared version of the library, which you do not appear to have" + $echo "*** because the file extensions .$libext of this argument makes me believe" + $echo "*** that it is just a static archive that I should not used here." + else + $echo + $echo "*** Warning: Linking the shared library $output against the" + $echo "*** static library $deplib is not portable!" + deplibs="$deplib $deplibs" + fi + continue + ;; + prog) + if test "$pass" != link; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + continue + ;; + esac # linkmode + ;; # *.$libext + *.lo | *.$objext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + elif test "$linkmode" = prog; then + if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then + # If there is no dlopen support or we're linking statically, + # we need to preload. + newdlprefiles="$newdlprefiles $deplib" + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + newdlfiles="$newdlfiles $deplib" + fi + fi + continue + ;; + %DEPLIBS%) + alldeplibs=yes + continue + ;; + esac # case $deplib + if test "$found" = yes || test -f "$lib"; then : + else + $echo "$modename: cannot find the library \`$lib'" 1>&2 + exit $EXIT_FAILURE + fi + + # Check to see that this really is a libtool archive. + if (${SED} -e '2q' $lib | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : + else + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + exit $EXIT_FAILURE + fi + + ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'` + test "X$ladir" = "X$lib" && ladir="." + + dlname= + dlopen= + dlpreopen= + libdir= + library_names= + old_library= + # If the library was installed with an old release of libtool, + # it will not redefine variables installed, or shouldnotlink + installed=yes + shouldnotlink=no + + # Read the .la file + case $lib in + */* | *\\*) . $lib ;; + *) . ./$lib ;; + esac + + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan" || + { test "$linkmode" != prog && test "$linkmode" != lib; }; then + test -n "$dlopen" && dlfiles="$dlfiles $dlopen" + test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen" + fi + + if test "$pass" = conv; then + # Only check for convenience libraries + deplibs="$lib $deplibs" + if test -z "$libdir"; then + if test -z "$old_library"; then + $echo "$modename: cannot find name of link library for \`$lib'" 1>&2 + exit $EXIT_FAILURE + fi + # It is a libtool convenience library, so add in its objects. + convenience="$convenience $ladir/$objdir/$old_library" + old_convenience="$old_convenience $ladir/$objdir/$old_library" + tmp_libs= + for deplib in $dependency_libs; do + deplibs="$deplib $deplibs" + if test "X$duplicate_deps" = "Xyes" ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done + elif test "$linkmode" != prog && test "$linkmode" != lib; then + $echo "$modename: \`$lib' is not a convenience library" 1>&2 + exit $EXIT_FAILURE + fi + continue + fi # $pass = conv + + + # Get the name of the library we link against. + linklib= + for l in $old_library $library_names; do + linklib="$l" + done + if test -z "$linklib"; then + $echo "$modename: cannot find name of link library for \`$lib'" 1>&2 + exit $EXIT_FAILURE + fi + + # This library was specified with -dlopen. + if test "$pass" = dlopen; then + if test -z "$libdir"; then + $echo "$modename: cannot -dlopen a convenience library: \`$lib'" 1>&2 + exit $EXIT_FAILURE + fi + if test -z "$dlname" || + test "$dlopen_support" != yes || + test "$build_libtool_libs" = no; then + # If there is no dlname, no dlopen support or we're linking + # statically, we need to preload. We also need to preload any + # dependent libraries so libltdl's deplib preloader doesn't + # bomb out in the load deplibs phase. + dlprefiles="$dlprefiles $lib $dependency_libs" + else + newdlfiles="$newdlfiles $lib" + fi + continue + fi # $pass = dlopen + + # We need an absolute path. + case $ladir in + [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; + *) + abs_ladir=`cd "$ladir" && pwd` + if test -z "$abs_ladir"; then + $echo "$modename: warning: cannot determine absolute directory name of \`$ladir'" 1>&2 + $echo "$modename: passing it literally to the linker, although it might fail" 1>&2 + abs_ladir="$ladir" + fi + ;; + esac + laname=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` + + # Find the relevant object directory and library name. + if test "X$installed" = Xyes; then + if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then + $echo "$modename: warning: library \`$lib' was moved." 1>&2 + dir="$ladir" + absdir="$abs_ladir" + libdir="$abs_ladir" + else + dir="$libdir" + absdir="$libdir" + fi + else + dir="$ladir/$objdir" + absdir="$abs_ladir/$objdir" + # Remove this search path later + notinst_path="$notinst_path $abs_ladir" + fi # $installed = yes + name=`$echo "X$laname" | $Xsed -e 's/\.la$//' -e 's/^lib//'` + + # This library was specified with -dlpreopen. + if test "$pass" = dlpreopen; then + if test -z "$libdir"; then + $echo "$modename: cannot -dlpreopen a convenience library: \`$lib'" 1>&2 + exit $EXIT_FAILURE + fi + # Prefer using a static library (so that no silly _DYNAMIC symbols + # are required to link). + if test -n "$old_library"; then + newdlprefiles="$newdlprefiles $dir/$old_library" + # Otherwise, use the dlname, so that lt_dlopen finds it. + elif test -n "$dlname"; then + newdlprefiles="$newdlprefiles $dir/$dlname" + else + newdlprefiles="$newdlprefiles $dir/$linklib" + fi + fi # $pass = dlpreopen + + if test -z "$libdir"; then + # Link the convenience library + if test "$linkmode" = lib; then + deplibs="$dir/$old_library $deplibs" + elif test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$dir/$old_library $compile_deplibs" + finalize_deplibs="$dir/$old_library $finalize_deplibs" + else + deplibs="$lib $deplibs" # used for prog,scan pass + fi + continue + fi + + + if test "$linkmode" = prog && test "$pass" != link; then + newlib_search_path="$newlib_search_path $ladir" + deplibs="$lib $deplibs" + + linkalldeplibs=no + if test "$link_all_deplibs" != no || test -z "$library_names" || + test "$build_libtool_libs" = no; then + linkalldeplibs=yes + fi + + tmp_libs= + for deplib in $dependency_libs; do + case $deplib in + -L*) newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`;; ### testsuite: skip nested quoting test + esac + # Need to link against all dependency_libs? + if test "$linkalldeplibs" = yes; then + deplibs="$deplib $deplibs" + else + # Need to hardcode shared library paths + # or/and link against static libraries + newdependency_libs="$deplib $newdependency_libs" + fi + if test "X$duplicate_deps" = "Xyes" ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done # for deplib + continue + fi # $linkmode = prog... + + if test "$linkmode,$pass" = "prog,link"; then + if test -n "$library_names" && + { test "$prefer_static_libs" = no || test -z "$old_library"; }; then + # We need to hardcode the library path + if test -n "$shlibpath_var"; then + # Make sure the rpath contains only unique directories. + case "$temp_rpath " in + *" $dir "*) ;; + *" $absdir "*) ;; + *) temp_rpath="$temp_rpath $dir" ;; + esac + fi + + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) compile_rpath="$compile_rpath $absdir" + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" + esac + ;; + esac + fi # $linkmode,$pass = prog,link... + + if test "$alldeplibs" = yes && + { test "$deplibs_check_method" = pass_all || + { test "$build_libtool_libs" = yes && + test -n "$library_names"; }; }; then + # We only need to search for static libraries + continue + fi + fi + + link_static=no # Whether the deplib will be linked statically + if test -n "$library_names" && + { test "$prefer_static_libs" = no || test -z "$old_library"; }; then + if test "$installed" = no; then + notinst_deplibs="$notinst_deplibs $lib" + need_relink=yes + fi + # This is a shared library + + # Warn about portability, can't link against -module's on + # some systems (darwin) + if test "$shouldnotlink" = yes && test "$pass" = link ; then + $echo + if test "$linkmode" = prog; then + $echo "*** Warning: Linking the executable $output against the loadable module" + else + $echo "*** Warning: Linking the shared library $output against the loadable module" + fi + $echo "*** $linklib is not portable!" + fi + if test "$linkmode" = lib && + test "$hardcode_into_libs" = yes; then + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) compile_rpath="$compile_rpath $absdir" + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" + esac + ;; + esac + fi + + if test -n "$old_archive_from_expsyms_cmds"; then + # figure out the soname + set dummy $library_names + realname="$2" + shift; shift + libname=`eval \\$echo \"$libname_spec\"` + # use dlname if we got it. it's perfectly good, no? + if test -n "$dlname"; then + soname="$dlname" + elif test -n "$soname_spec"; then + # bleh windows + case $host in + *cygwin* | mingw*) + major=`expr $current - $age` + versuffix="-$major" + ;; + esac + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + + # Make a new name for the extract_expsyms_cmds to use + soroot="$soname" + soname=`$echo $soroot | ${SED} -e 's/^.*\///'` + newlib="libimp-`$echo $soname | ${SED} 's/^lib//;s/\.dll$//'`.a" + + # If the library has no export list, then create one now + if test -f "$output_objdir/$soname-def"; then : + else + $show "extracting exported symbol list from \`$soname'" + save_ifs="$IFS"; IFS='~' + cmds=$extract_expsyms_cmds + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + + # Create $newlib + if test -f "$output_objdir/$newlib"; then :; else + $show "generating import library for \`$soname'" + save_ifs="$IFS"; IFS='~' + cmds=$old_archive_from_expsyms_cmds + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + # make sure the library variables are pointing to the new library + dir=$output_objdir + linklib=$newlib + fi # test -n "$old_archive_from_expsyms_cmds" + + if test "$linkmode" = prog || test "$mode" != relink; then + add_shlibpath= + add_dir= + add= + lib_linked=yes + case $hardcode_action in + immediate | unsupported) + if test "$hardcode_direct" = no; then + add="$dir/$linklib" + case $host in + *-*-sco3.2v5* ) add_dir="-L$dir" ;; + *-*-darwin* ) + # if the lib is a module then we can not link against + # it, someone is ignoring the new warnings I added + if /usr/bin/file -L $add 2> /dev/null | $EGREP "bundle" >/dev/null ; then + $echo "** Warning, lib $linklib is a module, not a shared library" + if test -z "$old_library" ; then + $echo + $echo "** And there doesn't seem to be a static archive available" + $echo "** The link will probably fail, sorry" + else + add="$dir/$old_library" + fi + fi + esac + elif test "$hardcode_minus_L" = no; then + case $host in + *-*-sunos*) add_shlibpath="$dir" ;; + esac + add_dir="-L$dir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = no; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + relink) + if test "$hardcode_direct" = yes; then + add="$dir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$dir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case "$libdir" in + [\\/]*) + add_dir="$add_dir -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + *) lib_linked=no ;; + esac + + if test "$lib_linked" != yes; then + $echo "$modename: configuration error: unsupported hardcode properties" + exit $EXIT_FAILURE + fi + + if test -n "$add_shlibpath"; then + case :$compile_shlibpath: in + *":$add_shlibpath:"*) ;; + *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;; + esac + fi + if test "$linkmode" = prog; then + test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" + test -n "$add" && compile_deplibs="$add $compile_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + if test "$hardcode_direct" != yes && \ + test "$hardcode_minus_L" != yes && \ + test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; + esac + fi + fi + fi + + if test "$linkmode" = prog || test "$mode" = relink; then + add_shlibpath= + add_dir= + add= + # Finalize command for both is simple: just hardcode it. + if test "$hardcode_direct" = yes; then + add="$libdir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$libdir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; + esac + add="-l$name" + elif test "$hardcode_automatic" = yes; then + if test -n "$inst_prefix_dir" && + test -f "$inst_prefix_dir$libdir/$linklib" ; then + add="$inst_prefix_dir$libdir/$linklib" + else + add="$libdir/$linklib" + fi + else + # We cannot seem to hardcode it, guess we'll fake it. + add_dir="-L$libdir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case "$libdir" in + [\\/]*) + add_dir="$add_dir -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + fi + + if test "$linkmode" = prog; then + test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" + test -n "$add" && finalize_deplibs="$add $finalize_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + fi + fi + elif test "$linkmode" = prog; then + # Here we assume that one of hardcode_direct or hardcode_minus_L + # is not unsupported. This is valid on all known static and + # shared platforms. + if test "$hardcode_direct" != unsupported; then + test -n "$old_library" && linklib="$old_library" + compile_deplibs="$dir/$linklib $compile_deplibs" + finalize_deplibs="$dir/$linklib $finalize_deplibs" + else + compile_deplibs="-l$name -L$dir $compile_deplibs" + finalize_deplibs="-l$name -L$dir $finalize_deplibs" + fi + elif test "$build_libtool_libs" = yes; then + # Not a shared library + if test "$deplibs_check_method" != pass_all; then + # We're trying link a shared library against a static one + # but the system doesn't support it. + + # Just print a warning and add the library to dependency_libs so + # that the program can be linked against the static library. + $echo + $echo "*** Warning: This system can not link to static lib archive $lib." + $echo "*** I have the capability to make that library automatically link in when" + $echo "*** you link to this library. But I can only do this if you have a" + $echo "*** shared version of the library, which you do not appear to have." + if test "$module" = yes; then + $echo "*** But as you try to build a module library, libtool will still create " + $echo "*** a static module, that should work as long as the dlopening application" + $echo "*** is linked with the -dlopen flag to resolve symbols at runtime." + if test -z "$global_symbol_pipe"; then + $echo + $echo "*** However, this would only work if libtool was able to extract symbol" + $echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + $echo "*** not find such a program. So, this module is probably useless." + $echo "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + else + convenience="$convenience $dir/$old_library" + old_convenience="$old_convenience $dir/$old_library" + deplibs="$dir/$old_library $deplibs" + link_static=yes + fi + fi # link shared/static library? + + if test "$linkmode" = lib; then + if test -n "$dependency_libs" && + { test "$hardcode_into_libs" != yes || + test "$build_old_libs" = yes || + test "$link_static" = yes; }; then + # Extract -R from dependency_libs + temp_deplibs= + for libdir in $dependency_libs; do + case $libdir in + -R*) temp_xrpath=`$echo "X$libdir" | $Xsed -e 's/^-R//'` + case " $xrpath " in + *" $temp_xrpath "*) ;; + *) xrpath="$xrpath $temp_xrpath";; + esac;; + *) temp_deplibs="$temp_deplibs $libdir";; + esac + done + dependency_libs="$temp_deplibs" + fi + + newlib_search_path="$newlib_search_path $absdir" + # Link against this library + test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" + # ... and its dependency_libs + tmp_libs= + for deplib in $dependency_libs; do + newdependency_libs="$deplib $newdependency_libs" + if test "X$duplicate_deps" = "Xyes" ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done + + if test "$link_all_deplibs" != no; then + # Add the search paths of all dependency libraries + for deplib in $dependency_libs; do + case $deplib in + -L*) path="$deplib" ;; + *.la) + dir=`$echo "X$deplib" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$deplib" && dir="." + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + $echo "$modename: warning: cannot determine absolute directory name of \`$dir'" 1>&2 + absdir="$dir" + fi + ;; + esac + if grep "^installed=no" $deplib > /dev/null; then + path="$absdir/$objdir" + else + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + if test -z "$libdir"; then + $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2 + exit $EXIT_FAILURE + fi + if test "$absdir" != "$libdir"; then + $echo "$modename: warning: \`$deplib' seems to be moved" 1>&2 + fi + path="$absdir" + fi + depdepl= + case $host in + *-*-darwin*) + # we do not want to link against static libs, + # but need to link against shared + eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` + if test -n "$deplibrary_names" ; then + for tmp in $deplibrary_names ; do + depdepl=$tmp + done + if test -f "$path/$depdepl" ; then + depdepl="$path/$depdepl" + fi + # do not add paths which are already there + case " $newlib_search_path " in + *" $path "*) ;; + *) newlib_search_path="$newlib_search_path $path";; + esac + fi + path="" + ;; + *) + path="-L$path" + ;; + esac + ;; + -l*) + case $host in + *-*-darwin*) + # Again, we only want to link against shared libraries + eval tmp_libs=`$echo "X$deplib" | $Xsed -e "s,^\-l,,"` + for tmp in $newlib_search_path ; do + if test -f "$tmp/lib$tmp_libs.dylib" ; then + eval depdepl="$tmp/lib$tmp_libs.dylib" + break + fi + done + path="" + ;; + *) continue ;; + esac + ;; + *) continue ;; + esac + case " $deplibs " in + *" $depdepl "*) ;; + *) deplibs="$depdepl $deplibs" ;; + esac + case " $deplibs " in + *" $path "*) ;; + *) deplibs="$deplibs $path" ;; + esac + done + fi # link_all_deplibs != no + fi # linkmode = lib + done # for deplib in $libs + dependency_libs="$newdependency_libs" + if test "$pass" = dlpreopen; then + # Link the dlpreopened libraries before other libraries + for deplib in $save_deplibs; do + deplibs="$deplib $deplibs" + done + fi + if test "$pass" != dlopen; then + if test "$pass" != conv; then + # Make sure lib_search_path contains only unique directories. + lib_search_path= + for dir in $newlib_search_path; do + case "$lib_search_path " in + *" $dir "*) ;; + *) lib_search_path="$lib_search_path $dir" ;; + esac + done + newlib_search_path= + fi + + if test "$linkmode,$pass" != "prog,link"; then + vars="deplibs" + else + vars="compile_deplibs finalize_deplibs" + fi + for var in $vars dependency_libs; do + # Add libraries to $var in reverse order + eval tmp_libs=\"\$$var\" + new_libs= + for deplib in $tmp_libs; do + # FIXME: Pedantically, this is the right thing to do, so + # that some nasty dependency loop isn't accidentally + # broken: + #new_libs="$deplib $new_libs" + # Pragmatically, this seems to cause very few problems in + # practice: + case $deplib in + -L*) new_libs="$deplib $new_libs" ;; + -R*) ;; + *) + # And here is the reason: when a library appears more + # than once as an explicit dependence of a library, or + # is implicitly linked in more than once by the + # compiler, it is considered special, and multiple + # occurrences thereof are not removed. Compare this + # with having the same library being listed as a + # dependency of multiple other libraries: in this case, + # we know (pedantically, we assume) the library does not + # need to be listed more than once, so we keep only the + # last copy. This is not always right, but it is rare + # enough that we require users that really mean to play + # such unportable linking tricks to link the library + # using -Wl,-lname, so that libtool does not consider it + # for duplicate removal. + case " $specialdeplibs " in + *" $deplib "*) new_libs="$deplib $new_libs" ;; + *) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$deplib $new_libs" ;; + esac + ;; + esac + ;; + esac + done + tmp_libs= + for deplib in $new_libs; do + case $deplib in + -L*) + case " $tmp_libs " in + *" $deplib "*) ;; + *) tmp_libs="$tmp_libs $deplib" ;; + esac + ;; + *) tmp_libs="$tmp_libs $deplib" ;; + esac + done + eval $var=\"$tmp_libs\" + done # for var + fi + # Last step: remove runtime libs from dependency_libs + # (they stay in deplibs) + tmp_libs= + for i in $dependency_libs ; do + case " $predeps $postdeps $compiler_lib_search_path " in + *" $i "*) + i="" + ;; + esac + if test -n "$i" ; then + tmp_libs="$tmp_libs $i" + fi + done + dependency_libs=$tmp_libs + done # for pass + if test "$linkmode" = prog; then + dlfiles="$newdlfiles" + dlprefiles="$newdlprefiles" + fi + + case $linkmode in + oldlib) + if test -n "$deplibs"; then + $echo "$modename: warning: \`-l' and \`-L' are ignored for archives" 1>&2 + fi + + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + $echo "$modename: warning: \`-dlopen' is ignored for archives" 1>&2 + fi + + if test -n "$rpath"; then + $echo "$modename: warning: \`-rpath' is ignored for archives" 1>&2 + fi + + if test -n "$xrpath"; then + $echo "$modename: warning: \`-R' is ignored for archives" 1>&2 + fi + + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info/-version-number' is ignored for archives" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for archives" 1>&2 + fi + + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + $echo "$modename: warning: \`-export-symbols' is ignored for archives" 1>&2 + fi + + # Now set the variables for building old libraries. + build_libtool_libs=no + oldlibs="$output" + objs="$objs$old_deplibs" + ;; + + lib) + # Make sure we only generate libraries of the form `libNAME.la'. + case $outputname in + lib*) + name=`$echo "X$outputname" | $Xsed -e 's/\.la$//' -e 's/^lib//'` + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + ;; + *) + if test "$module" = no; then + $echo "$modename: libtool library \`$output' must begin with \`lib'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + if test "$need_lib_prefix" != no; then + # Add the "lib" prefix for modules if required + name=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + else + libname=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` + fi + ;; + esac + + if test -n "$objs"; then + if test "$deplibs_check_method" != pass_all; then + $echo "$modename: cannot build libtool library \`$output' from non-libtool objects on this host:$objs" 2>&1 + exit $EXIT_FAILURE + else + $echo + $echo "*** Warning: Linking the shared library $output against the non-libtool" + $echo "*** objects $objs is not portable!" + libobjs="$libobjs $objs" + fi + fi + + if test "$dlself" != no; then + $echo "$modename: warning: \`-dlopen self' is ignored for libtool libraries" 1>&2 + fi + + set dummy $rpath + if test "$#" -gt 2; then + $echo "$modename: warning: ignoring multiple \`-rpath's for a libtool library" 1>&2 + fi + install_libdir="$2" + + oldlibs= + if test -z "$rpath"; then + if test "$build_libtool_libs" = yes; then + # Building a libtool convenience library. + # Some compilers have problems with a `.al' extension so + # convenience libraries should have the same extension an + # archive normally would. + oldlibs="$output_objdir/$libname.$libext $oldlibs" + build_libtool_libs=convenience + build_old_libs=yes + fi + + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info/-version-number' is ignored for convenience libraries" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for convenience libraries" 1>&2 + fi + else + + # Parse the version information argument. + save_ifs="$IFS"; IFS=':' + set dummy $vinfo 0 0 0 + IFS="$save_ifs" + + if test -n "$8"; then + $echo "$modename: too many parameters to \`-version-info'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # convert absolute version numbers to libtool ages + # this retains compatibility with .la files and attempts + # to make the code below a bit more comprehensible + + case $vinfo_number in + yes) + number_major="$2" + number_minor="$3" + number_revision="$4" + # + # There are really only two kinds -- those that + # use the current revision as the major version + # and those that subtract age and use age as + # a minor version. But, then there is irix + # which has an extra 1 added just for fun + # + case $version_type in + darwin|linux|osf|windows) + current=`expr $number_major + $number_minor` + age="$number_minor" + revision="$number_revision" + ;; + freebsd-aout|freebsd-elf|sunos) + current="$number_major" + revision="$number_minor" + age="0" + ;; + irix|nonstopux) + current=`expr $number_major + $number_minor - 1` + age="$number_minor" + revision="$number_minor" + ;; + *) + $echo "$modename: unknown library version type \`$version_type'" 1>&2 + $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit $EXIT_FAILURE + ;; + esac + ;; + no) + current="$2" + revision="$3" + age="$4" + ;; + esac + + # Check that each of the things are valid numbers. + case $current in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + $echo "$modename: CURRENT \`$current' is not a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + case $revision in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + $echo "$modename: REVISION \`$revision' is not a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + case $age in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + $echo "$modename: AGE \`$age' is not a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + if test "$age" -gt "$current"; then + $echo "$modename: AGE \`$age' is greater than the current interface number \`$current'" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit $EXIT_FAILURE + fi + + # Calculate the version variables. + major= + versuffix= + verstring= + case $version_type in + none) ;; + + darwin) + # Like Linux, but with the current version available in + # verstring for coding it into the library header + major=.`expr $current - $age` + versuffix="$major.$age.$revision" + # Darwin ld doesn't like 0 for these options... + minor_current=`expr $current + 1` + verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" + ;; + + freebsd-aout) + major=".$current" + versuffix=".$current.$revision"; + ;; + + freebsd-elf) + major=".$current" + versuffix=".$current"; + ;; + + irix | nonstopux) + major=`expr $current - $age + 1` + + case $version_type in + nonstopux) verstring_prefix=nonstopux ;; + *) verstring_prefix=sgi ;; + esac + verstring="$verstring_prefix$major.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$revision + while test "$loop" -ne 0; do + iface=`expr $revision - $loop` + loop=`expr $loop - 1` + verstring="$verstring_prefix$major.$iface:$verstring" + done + + # Before this point, $major must not contain `.'. + major=.$major + versuffix="$major.$revision" + ;; + + linux) + major=.`expr $current - $age` + versuffix="$major.$age.$revision" + ;; + + osf) + major=.`expr $current - $age` + versuffix=".$current.$age.$revision" + verstring="$current.$age.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$age + while test "$loop" -ne 0; do + iface=`expr $current - $loop` + loop=`expr $loop - 1` + verstring="$verstring:${iface}.0" + done + + # Make executables depend on our current version. + verstring="$verstring:${current}.0" + ;; + + sunos) + major=".$current" + versuffix=".$current.$revision" + ;; + + windows) + # Use '-' rather than '.', since we only want one + # extension on DOS 8.3 filesystems. + major=`expr $current - $age` + versuffix="-$major" + ;; + + *) + $echo "$modename: unknown library version type \`$version_type'" 1>&2 + $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit $EXIT_FAILURE + ;; + esac + + # Clear the version info if we defaulted, and they specified a release. + if test -z "$vinfo" && test -n "$release"; then + major= + case $version_type in + darwin) + # we can't check for "0.0" in archive_cmds due to quoting + # problems, so we reset it completely + verstring= + ;; + *) + verstring="0.0" + ;; + esac + if test "$need_version" = no; then + versuffix= + else + versuffix=".0.0" + fi + fi + + # Remove version info from name if versioning should be avoided + if test "$avoid_version" = yes && test "$need_version" = no; then + major= + versuffix= + verstring="" + fi + + # Check to see if the archive will have undefined symbols. + if test "$allow_undefined" = yes; then + if test "$allow_undefined_flag" = unsupported; then + $echo "$modename: warning: undefined symbols not allowed in $host shared libraries" 1>&2 + build_libtool_libs=no + build_old_libs=yes + fi + else + # Don't allow undefined symbols. + allow_undefined_flag="$no_undefined_flag" + fi + fi + + if test "$mode" != relink; then + # Remove our outputs, but don't remove object files since they + # may have been created when compiling PIC objects. + removelist= + tempremovelist=`$echo "$output_objdir/*"` + for p in $tempremovelist; do + case $p in + *.$objext) + ;; + $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) + if test "X$precious_files_regex" != "X"; then + if echo $p | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 + then + continue + fi + fi + removelist="$removelist $p" + ;; + *) ;; + esac + done + if test -n "$removelist"; then + $show "${rm}r $removelist" + $run ${rm}r $removelist + fi + fi + + # Now set the variables for building old libraries. + if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then + oldlibs="$oldlibs $output_objdir/$libname.$libext" + + # Transform .lo files to .o files. + oldobjs="$objs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP` + fi + + # Eliminate all temporary directories. + for path in $notinst_path; do + lib_search_path=`$echo "$lib_search_path " | ${SED} -e 's% $path % %g'` + deplibs=`$echo "$deplibs " | ${SED} -e 's% -L$path % %g'` + dependency_libs=`$echo "$dependency_libs " | ${SED} -e 's% -L$path % %g'` + done + + if test -n "$xrpath"; then + # If the user specified any rpath flags, then add them. + temp_xrpath= + for libdir in $xrpath; do + temp_xrpath="$temp_xrpath -R$libdir" + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" ;; + esac + done + if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then + dependency_libs="$temp_xrpath $dependency_libs" + fi + fi + + # Make sure dlfiles contains only unique files that won't be dlpreopened + old_dlfiles="$dlfiles" + dlfiles= + for lib in $old_dlfiles; do + case " $dlprefiles $dlfiles " in + *" $lib "*) ;; + *) dlfiles="$dlfiles $lib" ;; + esac + done + + # Make sure dlprefiles contains only unique files + old_dlprefiles="$dlprefiles" + dlprefiles= + for lib in $old_dlprefiles; do + case "$dlprefiles " in + *" $lib "*) ;; + *) dlprefiles="$dlprefiles $lib" ;; + esac + done + + if test "$build_libtool_libs" = yes; then + if test -n "$rpath"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos*) + # these systems don't actually have a c library (as such)! + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C library is in the System framework + deplibs="$deplibs -framework System" + ;; + *-*-netbsd*) + # Don't link with libc until the a.out ld.so is fixed. + ;; + *-*-openbsd* | *-*-freebsd*) + # Do not include libc due to us having libc/libc_r. + test "X$arg" = "X-lc" && continue + ;; + *) + # Add libc to deplibs on all other systems if necessary. + if test "$build_libtool_need_lc" = "yes"; then + deplibs="$deplibs -lc" + fi + ;; + esac + fi + + # Transform deplibs into only deplibs that can be linked in shared. + name_save=$name + libname_save=$libname + release_save=$release + versuffix_save=$versuffix + major_save=$major + # I'm not sure if I'm treating the release correctly. I think + # release should show up in the -l (ie -lgmp5) so we don't want to + # add it in twice. Is that correct? + release="" + versuffix="" + major="" + newdeplibs= + droppeddeps=no + case $deplibs_check_method in + pass_all) + # Don't check for shared/static. Everything works. + # This might be a little naive. We might want to check + # whether the library exists or not. But this is on + # osf3 & osf4 and I'm not really sure... Just + # implementing what was already the behavior. + newdeplibs=$deplibs + ;; + test_compile) + # This code stresses the "libraries are programs" paradigm to its + # limits. Maybe even breaks it. We compile a program, linking it + # against the deplibs as a proxy for the library. Then we can check + # whether they linked in statically or dynamically with ldd. + $rm conftest.c + cat > conftest.c </dev/null` + for potent_lib in $potential_libs; do + # Follow soft links. + if ls -lLd "$potent_lib" 2>/dev/null \ + | grep " -> " >/dev/null; then + continue + fi + # The statement above tries to avoid entering an + # endless loop below, in case of cyclic links. + # We might still enter an endless loop, since a link + # loop can be closed while we follow links, + # but so what? + potlib="$potent_lib" + while test -h "$potlib" 2>/dev/null; do + potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` + case $potliblink in + [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; + *) potlib=`$echo "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";; + esac + done + if eval $file_magic_cmd \"\$potlib\" 2>/dev/null \ + | ${SED} 10q \ + | $EGREP "$file_magic_regex" > /dev/null; then + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + $echo + $echo "*** Warning: linker path does not have real file for library $a_deplib." + $echo "*** I have the capability to make that library automatically link in when" + $echo "*** you link to this library. But I can only do this if you have a" + $echo "*** shared version of the library, which you do not appear to have" + $echo "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $echo "*** with $libname but no candidates were found. (...for file magic test)" + else + $echo "*** with $libname and none of the candidates passed a file format test" + $echo "*** using a file magic. Last file checked: $potlib" + fi + fi + else + # Add a -L argument. + newdeplibs="$newdeplibs $a_deplib" + fi + done # Gone through all deplibs. + ;; + match_pattern*) + set dummy $deplibs_check_method + match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"` + for a_deplib in $deplibs; do + name="`expr $a_deplib : '-l\(.*\)'`" + # If $name is empty we are operating on a -L argument. + if test -n "$name" && test "$name" != "0"; then + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $a_deplib "*) + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + ;; + esac + fi + if test -n "$a_deplib" ; then + libname=`eval \\$echo \"$libname_spec\"` + for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do + potential_libs=`ls $i/$libname[.-]* 2>/dev/null` + for potent_lib in $potential_libs; do + potlib="$potent_lib" # see symlink-check above in file_magic test + if eval $echo \"$potent_lib\" 2>/dev/null \ + | ${SED} 10q \ + | $EGREP "$match_pattern_regex" > /dev/null; then + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + $echo + $echo "*** Warning: linker path does not have real file for library $a_deplib." + $echo "*** I have the capability to make that library automatically link in when" + $echo "*** you link to this library. But I can only do this if you have a" + $echo "*** shared version of the library, which you do not appear to have" + $echo "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $echo "*** with $libname but no candidates were found. (...for regex pattern test)" + else + $echo "*** with $libname and none of the candidates passed a file format test" + $echo "*** using a regex pattern. Last file checked: $potlib" + fi + fi + else + # Add a -L argument. + newdeplibs="$newdeplibs $a_deplib" + fi + done # Gone through all deplibs. + ;; + none | unknown | *) + newdeplibs="" + tmp_deplibs=`$echo "X $deplibs" | $Xsed -e 's/ -lc$//' \ + -e 's/ -[LR][^ ]*//g'` + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + for i in $predeps $postdeps ; do + # can't use Xsed below, because $i might contain '/' + tmp_deplibs=`$echo "X $tmp_deplibs" | ${SED} -e "1s,^X,," -e "s,$i,,"` + done + fi + if $echo "X $tmp_deplibs" | $Xsed -e 's/[ ]//g' \ + | grep . >/dev/null; then + $echo + if test "X$deplibs_check_method" = "Xnone"; then + $echo "*** Warning: inter-library dependencies are not supported in this platform." + else + $echo "*** Warning: inter-library dependencies are not known to be supported." + fi + $echo "*** All declared inter-library dependencies are being dropped." + droppeddeps=yes + fi + ;; + esac + versuffix=$versuffix_save + major=$major_save + release=$release_save + libname=$libname_save + name=$name_save + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library is the System framework + newdeplibs=`$echo "X $newdeplibs" | $Xsed -e 's/ -lc / -framework System /'` + ;; + esac + + if test "$droppeddeps" = yes; then + if test "$module" = yes; then + $echo + $echo "*** Warning: libtool could not satisfy all declared inter-library" + $echo "*** dependencies of module $libname. Therefore, libtool will create" + $echo "*** a static module, that should work as long as the dlopening" + $echo "*** application is linked with the -dlopen flag." + if test -z "$global_symbol_pipe"; then + $echo + $echo "*** However, this would only work if libtool was able to extract symbol" + $echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + $echo "*** not find such a program. So, this module is probably useless." + $echo "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + else + $echo "*** The inter-library dependencies that have been dropped here will be" + $echo "*** automatically added whenever a program is linked with this library" + $echo "*** or is declared to -dlopen it." + + if test "$allow_undefined" = no; then + $echo + $echo "*** Since this library must not contain undefined symbols," + $echo "*** because either the platform does not support them or" + $echo "*** it was explicitly requested with -no-undefined," + $echo "*** libtool will only create a static version of it." + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + fi + fi + # Done checking deplibs! + deplibs=$newdeplibs + fi + + # All the library-specific variables (install_libdir is set above). + library_names= + old_library= + dlname= + + # Test again, we may have decided not to build it any more + if test "$build_libtool_libs" = yes; then + if test "$hardcode_into_libs" = yes; then + # Hardcode the library paths + hardcode_libdirs= + dep_rpath= + rpath="$finalize_rpath" + test "$mode" != relink && rpath="$compile_rpath$rpath" + for libdir in $rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + dep_rpath="$dep_rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + if test -n "$hardcode_libdir_flag_spec_ld"; then + eval dep_rpath=\"$hardcode_libdir_flag_spec_ld\" + else + eval dep_rpath=\"$hardcode_libdir_flag_spec\" + fi + fi + if test -n "$runpath_var" && test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" + fi + test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" + fi + + shlibpath="$finalize_shlibpath" + test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath" + if test -n "$shlibpath"; then + eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" + fi + + # Get the real and link names of the library. + eval shared_ext=\"$shrext_cmds\" + eval library_names=\"$library_names_spec\" + set dummy $library_names + realname="$2" + shift; shift + + if test -n "$soname_spec"; then + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + if test -z "$dlname"; then + dlname=$soname + fi + + lib="$output_objdir/$realname" + for link + do + linknames="$linknames $link" + done + + # Use standard objects if they are pic + test -z "$pic_flag" && libobjs=`$echo "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then + $show "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $run $rm $export_symbols + cmds=$export_symbols_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + if len=`expr "X$cmd" : ".*"` && + test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then + $show "$cmd" + $run eval "$cmd" || exit $? + skipped_export=false + else + # The command line is too long to execute in one step. + $show "using reloadable object file for export list..." + skipped_export=: + fi + done + IFS="$save_ifs" + if test -n "$export_symbols_regex"; then + $show "$EGREP -e \"$export_symbols_regex\" \"$export_symbols\" > \"${export_symbols}T\"" + $run eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + $show "$mv \"${export_symbols}T\" \"$export_symbols\"" + $run eval '$mv "${export_symbols}T" "$export_symbols"' + fi + fi + fi + + if test -n "$export_symbols" && test -n "$include_expsyms"; then + $run eval '$echo "X$include_expsyms" | $SP2NL >> "$export_symbols"' + fi + + tmp_deplibs= + for test_deplib in $deplibs; do + case " $convenience " in + *" $test_deplib "*) ;; + *) + tmp_deplibs="$tmp_deplibs $test_deplib" + ;; + esac + done + deplibs="$tmp_deplibs" + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + else + gentop="$output_objdir/${outputname}x" + $show "${rm}r $gentop" + $run ${rm}r "$gentop" + $show "$mkdir $gentop" + $run $mkdir "$gentop" + status=$? + if test "$status" -ne 0 && test ! -d "$gentop"; then + exit $status + fi + generated="$generated $gentop" + + for xlib in $convenience; do + # Extract the objects. + case $xlib in + [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;; + *) xabs=`pwd`"/$xlib" ;; + esac + xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'` + xdir="$gentop/$xlib" + + $show "${rm}r $xdir" + $run ${rm}r "$xdir" + $show "$mkdir $xdir" + $run $mkdir "$xdir" + status=$? + if test "$status" -ne 0 && test ! -d "$xdir"; then + exit $status + fi + # We will extract separately just the conflicting names and we will no + # longer touch any unique names. It is faster to leave these extract + # automatically by $AR in one run. + $show "(cd $xdir && $AR x $xabs)" + $run eval "(cd \$xdir && $AR x \$xabs)" || exit $? + if ($AR t "$xabs" | sort | sort -uc >/dev/null 2>&1); then + : + else + $echo "$modename: warning: object name conflicts; renaming object files" 1>&2 + $echo "$modename: warning: to ensure that they will not overwrite" 1>&2 + $AR t "$xabs" | sort | uniq -cd | while read -r count name + do + i=1 + while test "$i" -le "$count" + do + # Put our $i before any first dot (extension) + # Never overwrite any file + name_to="$name" + while test "X$name_to" = "X$name" || test -f "$xdir/$name_to" + do + name_to=`$echo "X$name_to" | $Xsed -e "s/\([^.]*\)/\1-$i/"` + done + $show "(cd $xdir && $AR xN $i $xabs '$name' && $mv '$name' '$name_to')" + $run eval "(cd \$xdir && $AR xN $i \$xabs '$name' && $mv '$name' '$name_to')" || exit $? + i=`expr $i + 1` + done + done + fi + + libobjs="$libobjs "`find $xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP` + done + fi + fi + + if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then + eval flag=\"$thread_safe_flag_spec\" + linker_flags="$linker_flags $flag" + fi + + # Make a backup of the uninstalled library when relinking + if test "$mode" = relink; then + $run eval '(cd $output_objdir && $rm ${realname}U && $mv $realname ${realname}U)' || exit $? + fi + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + eval test_cmds=\"$module_expsym_cmds\" + cmds=$module_expsym_cmds + else + eval test_cmds=\"$module_cmds\" + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + eval test_cmds=\"$archive_expsym_cmds\" + cmds=$archive_expsym_cmds + else + eval test_cmds=\"$archive_cmds\" + cmds=$archive_cmds + fi + fi + + if test "X$skipped_export" != "X:" && len=`expr "X$test_cmds" : ".*"` && + test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then + : + else + # The command line is too long to link in one step, link piecewise. + $echo "creating reloadable object files..." + + # Save the value of $output and $libobjs because we want to + # use them later. If we have whole_archive_flag_spec, we + # want to use save_libobjs as it was before + # whole_archive_flag_spec was expanded, because we can't + # assume the linker understands whole_archive_flag_spec. + # This may have to be revisited, in case too many + # convenience libraries get linked in and end up exceeding + # the spec. + if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + fi + save_output=$output + + # Clear the reloadable object creation command queue and + # initialize k to one. + test_cmds= + concat_cmds= + objlist= + delfiles= + last_robj= + k=1 + output=$output_objdir/$save_output-${k}.$objext + # Loop over the list of objects to be linked. + for obj in $save_libobjs + do + eval test_cmds=\"$reload_cmds $objlist $last_robj\" + if test "X$objlist" = X || + { len=`expr "X$test_cmds" : ".*"` && + test "$len" -le "$max_cmd_len"; }; then + objlist="$objlist $obj" + else + # The command $test_cmds is almost too long, add a + # command to the queue. + if test "$k" -eq 1 ; then + # The first file doesn't have a previous command to add. + eval concat_cmds=\"$reload_cmds $objlist $last_robj\" + else + # All subsequent reloadable object files will link in + # the last one created. + eval concat_cmds=\"\$concat_cmds~$reload_cmds $objlist $last_robj\" + fi + last_robj=$output_objdir/$save_output-${k}.$objext + k=`expr $k + 1` + output=$output_objdir/$save_output-${k}.$objext + objlist=$obj + len=1 + fi + done + # Handle the remaining objects by creating one last + # reloadable object file. All subsequent reloadable object + # files will link in the last one created. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\${concat_cmds}$reload_cmds $objlist $last_robj\" + + if ${skipped_export-false}; then + $show "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $run $rm $export_symbols + libobjs=$output + # Append the command to create the export file. + eval concat_cmds=\"\$concat_cmds~$export_symbols_cmds\" + fi + + # Set up a command to remove the reloadale object files + # after they are used. + i=0 + while test "$i" -lt "$k" + do + i=`expr $i + 1` + delfiles="$delfiles $output_objdir/$save_output-${i}.$objext" + done + + $echo "creating a temporary reloadable object file: $output" + + # Loop through the commands generated above and execute them. + save_ifs="$IFS"; IFS='~' + for cmd in $concat_cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + + libobjs=$output + # Restore the value of output. + output=$save_output + + if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + fi + # Expand the library linking commands again to reset the + # value of $libobjs for piecewise linking. + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + cmds=$module_expsym_cmds + else + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + cmds=$archive_expsym_cmds + else + cmds=$archive_cmds + fi + fi + + # Append the command to remove the reloadable object files + # to the just-reset $cmds. + eval cmds=\"\$cmds~\$rm $delfiles\" + fi + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + $run eval '(cd $output_objdir && $rm ${realname}T && $mv $realname ${realname}T && $mv "$realname"U $realname)' || exit $? + exit $EXIT_SUCCESS + fi + + # Create links to the real library. + for linkname in $linknames; do + if test "$realname" != "$linkname"; then + $show "(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)" + $run eval '(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)' || exit $? + fi + done + + # If -module or -export-dynamic was specified, set the dlname. + if test "$module" = yes || test "$export_dynamic" = yes; then + # On all known operating systems, these are identical. + dlname="$soname" + fi + fi + ;; + + obj) + if test -n "$deplibs"; then + $echo "$modename: warning: \`-l' and \`-L' are ignored for objects" 1>&2 + fi + + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + $echo "$modename: warning: \`-dlopen' is ignored for objects" 1>&2 + fi + + if test -n "$rpath"; then + $echo "$modename: warning: \`-rpath' is ignored for objects" 1>&2 + fi + + if test -n "$xrpath"; then + $echo "$modename: warning: \`-R' is ignored for objects" 1>&2 + fi + + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info' is ignored for objects" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for objects" 1>&2 + fi + + case $output in + *.lo) + if test -n "$objs$old_deplibs"; then + $echo "$modename: cannot build library object \`$output' from non-libtool objects" 1>&2 + exit $EXIT_FAILURE + fi + libobj="$output" + obj=`$echo "X$output" | $Xsed -e "$lo2o"` + ;; + *) + libobj= + obj="$output" + ;; + esac + + # Delete the old objects. + $run $rm $obj $libobj + + # Objects from convenience libraries. This assumes + # single-version convenience libraries. Whenever we create + # different ones for PIC/non-PIC, this we'll have to duplicate + # the extraction. + reload_conv_objs= + gentop= + # reload_cmds runs $LD directly, so let us get rid of + # -Wl from whole_archive_flag_spec + wl= + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + eval reload_conv_objs=\"\$reload_objs $whole_archive_flag_spec\" + else + gentop="$output_objdir/${obj}x" + $show "${rm}r $gentop" + $run ${rm}r "$gentop" + $show "$mkdir $gentop" + $run $mkdir "$gentop" + status=$? + if test "$status" -ne 0 && test ! -d "$gentop"; then + exit $status + fi + generated="$generated $gentop" + + for xlib in $convenience; do + # Extract the objects. + case $xlib in + [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;; + *) xabs=`pwd`"/$xlib" ;; + esac + xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'` + xdir="$gentop/$xlib" + + $show "${rm}r $xdir" + $run ${rm}r "$xdir" + $show "$mkdir $xdir" + $run $mkdir "$xdir" + status=$? + if test "$status" -ne 0 && test ! -d "$xdir"; then + exit $status + fi + # We will extract separately just the conflicting names and we will no + # longer touch any unique names. It is faster to leave these extract + # automatically by $AR in one run. + $show "(cd $xdir && $AR x $xabs)" + $run eval "(cd \$xdir && $AR x \$xabs)" || exit $? + if ($AR t "$xabs" | sort | sort -uc >/dev/null 2>&1); then + : + else + $echo "$modename: warning: object name conflicts; renaming object files" 1>&2 + $echo "$modename: warning: to ensure that they will not overwrite" 1>&2 + $AR t "$xabs" | sort | uniq -cd | while read -r count name + do + i=1 + while test "$i" -le "$count" + do + # Put our $i before any first dot (extension) + # Never overwrite any file + name_to="$name" + while test "X$name_to" = "X$name" || test -f "$xdir/$name_to" + do + name_to=`$echo "X$name_to" | $Xsed -e "s/\([^.]*\)/\1-$i/"` + done + $show "(cd $xdir && $AR xN $i $xabs '$name' && $mv '$name' '$name_to')" + $run eval "(cd \$xdir && $AR xN $i \$xabs '$name' && $mv '$name' '$name_to')" || exit $? + i=`expr $i + 1` + done + done + fi + + reload_conv_objs="$reload_objs "`find $xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP` + done + fi + fi + + # Create the old-style object. + reload_objs="$objs$old_deplibs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test + + output="$obj" + cmds=$reload_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + + # Exit if we aren't doing a library object file. + if test -z "$libobj"; then + if test -n "$gentop"; then + $show "${rm}r $gentop" + $run ${rm}r $gentop + fi + + exit $EXIT_SUCCESS + fi + + if test "$build_libtool_libs" != yes; then + if test -n "$gentop"; then + $show "${rm}r $gentop" + $run ${rm}r $gentop + fi + + # Create an invalid libtool object if no PIC, so that we don't + # accidentally link it into a program. + # $show "echo timestamp > $libobj" + # $run eval "echo timestamp > $libobj" || exit $? + exit $EXIT_SUCCESS + fi + + if test -n "$pic_flag" || test "$pic_mode" != default; then + # Only do commands if we really have different PIC objects. + reload_objs="$libobjs $reload_conv_objs" + output="$libobj" + cmds=$reload_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + + if test -n "$gentop"; then + $show "${rm}r $gentop" + $run ${rm}r $gentop + fi + + exit $EXIT_SUCCESS + ;; + + prog) + case $host in + *cygwin*) output=`$echo $output | ${SED} -e 's,.exe$,,;s,$,.exe,'` ;; + esac + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info' is ignored for programs" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for programs" 1>&2 + fi + + if test "$preload" = yes; then + if test "$dlopen_support" = unknown && test "$dlopen_self" = unknown && + test "$dlopen_self_static" = unknown; then + $echo "$modename: warning: \`AC_LIBTOOL_DLOPEN' not used. Assuming no dlopen support." + fi + fi + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library is the System framework + compile_deplibs=`$echo "X $compile_deplibs" | $Xsed -e 's/ -lc / -framework System /'` + finalize_deplibs=`$echo "X $finalize_deplibs" | $Xsed -e 's/ -lc / -framework System /'` + ;; + esac + + case $host in + *darwin*) + # Don't allow lazy linking, it breaks C++ global constructors + if test "$tagname" = CXX ; then + compile_command="$compile_command ${wl}-bind_at_load" + finalize_command="$finalize_command ${wl}-bind_at_load" + fi + ;; + esac + + compile_command="$compile_command $compile_deplibs" + finalize_command="$finalize_command $finalize_deplibs" + + if test -n "$rpath$xrpath"; then + # If the user specified any rpath flags, then add them. + for libdir in $rpath $xrpath; do + # This is the magic to use -rpath. + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" ;; + esac + done + fi + + # Now hardcode the library paths + rpath= + hardcode_libdirs= + for libdir in $compile_rpath $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + rpath="$rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) + case :$dllsearchpath: in + *":$libdir:"*) ;; + *) dllsearchpath="$dllsearchpath:$libdir";; + esac + ;; + esac + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + compile_rpath="$rpath" + + rpath= + hardcode_libdirs= + for libdir in $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + rpath="$rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$finalize_perm_rpath " in + *" $libdir "*) ;; + *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + finalize_rpath="$rpath" + + if test -n "$libobjs" && test "$build_old_libs" = yes; then + # Transform all the library objects into standard objects. + compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + fi + + dlsyms= + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + if test -n "$NM" && test -n "$global_symbol_pipe"; then + dlsyms="${outputname}S.c" + else + $echo "$modename: not configured to extract global symbols from dlpreopened files" 1>&2 + fi + fi + + if test -n "$dlsyms"; then + case $dlsyms in + "") ;; + *.c) + # Discover the nlist of each of the dlfiles. + nlist="$output_objdir/${outputname}.nm" + + $show "$rm $nlist ${nlist}S ${nlist}T" + $run $rm "$nlist" "${nlist}S" "${nlist}T" + + # Parse the name list into a source file. + $show "creating $output_objdir/$dlsyms" + + test -z "$run" && $echo > "$output_objdir/$dlsyms" "\ +/* $dlsyms - symbol resolution table for \`$outputname' dlsym emulation. */ +/* Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP */ + +#ifdef __cplusplus +extern \"C\" { +#endif + +/* Prevent the only kind of declaration conflicts we can make. */ +#define lt_preloaded_symbols some_other_symbol + +/* External symbol declarations for the compiler. */\ +" + + if test "$dlself" = yes; then + $show "generating symbol list for \`$output'" + + test -z "$run" && $echo ': @PROGRAM@ ' > "$nlist" + + # Add our own program objects to the symbol list. + progfiles=`$echo "X$objs$old_deplibs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + for arg in $progfiles; do + $show "extracting global C symbols from \`$arg'" + $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" + done + + if test -n "$exclude_expsyms"; then + $run eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' + $run eval '$mv "$nlist"T "$nlist"' + fi + + if test -n "$export_symbols_regex"; then + $run eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' + $run eval '$mv "$nlist"T "$nlist"' + fi + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + export_symbols="$output_objdir/$output.exp" + $run $rm $export_symbols + $run eval "${SED} -n -e '/^: @PROGRAM@$/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' + else + $run eval "${SED} -e 's/\([][.*^$]\)/\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$output.exp"' + $run eval 'grep -f "$output_objdir/$output.exp" < "$nlist" > "$nlist"T' + $run eval 'mv "$nlist"T "$nlist"' + fi + fi + + for arg in $dlprefiles; do + $show "extracting global C symbols from \`$arg'" + name=`$echo "$arg" | ${SED} -e 's%^.*/%%'` + $run eval '$echo ": $name " >> "$nlist"' + $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" + done + + if test -z "$run"; then + # Make sure we have at least an empty file. + test -f "$nlist" || : > "$nlist" + + if test -n "$exclude_expsyms"; then + $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T + $mv "$nlist"T "$nlist" + fi + + # Try sorting and uniquifying the output. + if grep -v "^: " < "$nlist" | + if sort -k 3 /dev/null 2>&1; then + sort -k 3 + else + sort +2 + fi | + uniq > "$nlist"S; then + : + else + grep -v "^: " < "$nlist" > "$nlist"S + fi + + if test -f "$nlist"S; then + eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$dlsyms"' + else + $echo '/* NONE */' >> "$output_objdir/$dlsyms" + fi + + $echo >> "$output_objdir/$dlsyms" "\ + +#undef lt_preloaded_symbols + +#if defined (__STDC__) && __STDC__ +# define lt_ptr void * +#else +# define lt_ptr char * +# define const +#endif + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + lt_ptr address; +} +lt_preloaded_symbols[] = +{\ +" + + eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$dlsyms" + + $echo >> "$output_objdir/$dlsyms" "\ + {0, (lt_ptr) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif\ +" + fi + + pic_flag_for_symtable= + case $host in + # compiling the symbol table file with pic_flag works around + # a FreeBSD bug that causes programs to crash when -lm is + # linked before any other PIC object. But we must not use + # pic_flag when linking with -static. The problem exists in + # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. + *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) + case "$compile_command " in + *" -static "*) ;; + *) pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND";; + esac;; + *-*-hpux*) + case "$compile_command " in + *" -static "*) ;; + *) pic_flag_for_symtable=" $pic_flag";; + esac + esac + + # Now compile the dynamic symbol file. + $show "(cd $output_objdir && $LTCC -c$no_builtin_flag$pic_flag_for_symtable \"$dlsyms\")" + $run eval '(cd $output_objdir && $LTCC -c$no_builtin_flag$pic_flag_for_symtable "$dlsyms")' || exit $? + + # Clean up the generated files. + $show "$rm $output_objdir/$dlsyms $nlist ${nlist}S ${nlist}T" + $run $rm "$output_objdir/$dlsyms" "$nlist" "${nlist}S" "${nlist}T" + + # Transform the symbol file into the correct name. + compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"` + finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"` + ;; + *) + $echo "$modename: unknown suffix for \`$dlsyms'" 1>&2 + exit $EXIT_FAILURE + ;; + esac + else + # We keep going just in case the user didn't refer to + # lt_preloaded_symbols. The linker will fail if global_symbol_pipe + # really was required. + + # Nullify the symbol file. + compile_command=`$echo "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"` + finalize_command=`$echo "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"` + fi + + if test "$need_relink" = no || test "$build_libtool_libs" != yes; then + # Replace the output file specification. + compile_command=`$echo "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` + link_command="$compile_command$compile_rpath" + + # We have no uninstalled library dependencies, so finalize right now. + $show "$link_command" + $run eval "$link_command" + status=$? + + # Delete the generated files. + if test -n "$dlsyms"; then + $show "$rm $output_objdir/${outputname}S.${objext}" + $run $rm "$output_objdir/${outputname}S.${objext}" + fi + + exit $status + fi + + if test -n "$shlibpath_var"; then + # We should set the shlibpath_var + rpath= + for dir in $temp_rpath; do + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) + # Absolute path. + rpath="$rpath$dir:" + ;; + *) + # Relative path: add a thisdir entry. + rpath="$rpath\$thisdir/$dir:" + ;; + esac + done + temp_rpath="$rpath" + fi + + if test -n "$compile_shlibpath$finalize_shlibpath"; then + compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" + fi + if test -n "$finalize_shlibpath"; then + finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" + fi + + compile_var= + finalize_var= + if test -n "$runpath_var"; then + if test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + compile_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + if test -n "$finalize_perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $finalize_perm_rpath; do + rpath="$rpath$dir:" + done + finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + fi + + if test "$no_install" = yes; then + # We don't need to create a wrapper script. + link_command="$compile_var$compile_command$compile_rpath" + # Replace the output file specification. + link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` + # Delete the old output file. + $run $rm $output + # Link the executable and exit + $show "$link_command" + $run eval "$link_command" || exit $? + exit $EXIT_SUCCESS + fi + + if test "$hardcode_action" = relink; then + # Fast installation is not supported + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + + $echo "$modename: warning: this platform does not like uninstalled shared libraries" 1>&2 + $echo "$modename: \`$output' will be relinked during installation" 1>&2 + else + if test "$fast_install" != no; then + link_command="$finalize_var$compile_command$finalize_rpath" + if test "$fast_install" = yes; then + relink_command=`$echo "X$compile_var$compile_command$compile_rpath" | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g'` + else + # fast_install is set to needless + relink_command= + fi + else + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + fi + fi + + # Replace the output file specification. + link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` + + # Delete the old output files. + $run $rm $output $output_objdir/$outputname $output_objdir/lt-$outputname + + $show "$link_command" + $run eval "$link_command" || exit $? + + # Now create the wrapper script. + $show "creating $output" + + # Quote the relink command for shipping. + if test -n "$relink_command"; then + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"` + relink_command="$var=\"$var_value\"; export $var; $relink_command" + fi + done + relink_command="(cd `pwd`; $relink_command)" + relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"` + fi + + # Quote $echo for shipping. + if test "X$echo" = "X$SHELL $progpath --fallback-echo"; then + case $progpath in + [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $progpath --fallback-echo";; + *) qecho="$SHELL `pwd`/$progpath --fallback-echo";; + esac + qecho=`$echo "X$qecho" | $Xsed -e "$sed_quote_subst"` + else + qecho=`$echo "X$echo" | $Xsed -e "$sed_quote_subst"` + fi + + # Only actually do things if our run command is non-null. + if test -z "$run"; then + # win32 will think the script is a binary if it has + # a .exe suffix, so we strip it off here. + case $output in + *.exe) output=`$echo $output|${SED} 's,.exe$,,'` ;; + esac + # test for cygwin because mv fails w/o .exe extensions + case $host in + *cygwin*) + exeext=.exe + outputname=`$echo $outputname|${SED} 's,.exe$,,'` ;; + *) exeext= ;; + esac + case $host in + *cygwin* | *mingw* ) + cwrappersource=`$echo ${objdir}/lt-${output}.c` + cwrapper=`$echo ${output}.exe` + $rm $cwrappersource $cwrapper + trap "$rm $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 + + cat > $cwrappersource <> $cwrappersource<<"EOF" +#include +#include +#include +#include +#include +#include + +#if defined(PATH_MAX) +# define LT_PATHMAX PATH_MAX +#elif defined(MAXPATHLEN) +# define LT_PATHMAX MAXPATHLEN +#else +# define LT_PATHMAX 1024 +#endif + +#ifndef DIR_SEPARATOR +#define DIR_SEPARATOR '/' +#endif + +#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ + defined (__OS2__) +#define HAVE_DOS_BASED_FILE_SYSTEM +#ifndef DIR_SEPARATOR_2 +#define DIR_SEPARATOR_2 '\\' +#endif +#endif + +#ifndef DIR_SEPARATOR_2 +# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) +#else /* DIR_SEPARATOR_2 */ +# define IS_DIR_SEPARATOR(ch) \ + (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) +#endif /* DIR_SEPARATOR_2 */ + +#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) +#define XFREE(stale) do { \ + if (stale) { free ((void *) stale); stale = 0; } \ +} while (0) + +const char *program_name = NULL; + +void * xmalloc (size_t num); +char * xstrdup (const char *string); +char * basename (const char *name); +char * fnqualify(const char *path); +char * strendzap(char *str, const char *pat); +void lt_fatal (const char *message, ...); + +int +main (int argc, char *argv[]) +{ + char **newargz; + int i; + + program_name = (char *) xstrdup ((char *) basename (argv[0])); + newargz = XMALLOC(char *, argc+2); +EOF + + cat >> $cwrappersource <> $cwrappersource <<"EOF" + newargz[1] = fnqualify(argv[0]); + /* we know the script has the same name, without the .exe */ + /* so make sure newargz[1] doesn't end in .exe */ + strendzap(newargz[1],".exe"); + for (i = 1; i < argc; i++) + newargz[i+1] = xstrdup(argv[i]); + newargz[argc+1] = NULL; +EOF + + cat >> $cwrappersource <> $cwrappersource <<"EOF" +} + +void * +xmalloc (size_t num) +{ + void * p = (void *) malloc (num); + if (!p) + lt_fatal ("Memory exhausted"); + + return p; +} + +char * +xstrdup (const char *string) +{ + return string ? strcpy ((char *) xmalloc (strlen (string) + 1), string) : NULL +; +} + +char * +basename (const char *name) +{ + const char *base; + +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + /* Skip over the disk name in MSDOS pathnames. */ + if (isalpha (name[0]) && name[1] == ':') + name += 2; +#endif + + for (base = name; *name; name++) + if (IS_DIR_SEPARATOR (*name)) + base = name + 1; + return (char *) base; +} + +char * +fnqualify(const char *path) +{ + size_t size; + char *p; + char tmp[LT_PATHMAX + 1]; + + assert(path != NULL); + + /* Is it qualified already? */ +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + if (isalpha (path[0]) && path[1] == ':') + return xstrdup (path); +#endif + if (IS_DIR_SEPARATOR (path[0])) + return xstrdup (path); + + /* prepend the current directory */ + /* doesn't handle '~' */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal ("getcwd failed"); + size = strlen(tmp) + 1 + strlen(path) + 1; /* +2 for '/' and '\0' */ + p = XMALLOC(char, size); + sprintf(p, "%s%c%s", tmp, DIR_SEPARATOR, path); + return p; +} + +char * +strendzap(char *str, const char *pat) +{ + size_t len, patlen; + + assert(str != NULL); + assert(pat != NULL); + + len = strlen(str); + patlen = strlen(pat); + + if (patlen <= len) + { + str += len - patlen; + if (strcmp(str, pat) == 0) + *str = '\0'; + } + return str; +} + +static void +lt_error_core (int exit_status, const char * mode, + const char * message, va_list ap) +{ + fprintf (stderr, "%s: %s: ", program_name, mode); + vfprintf (stderr, message, ap); + fprintf (stderr, ".\n"); + + if (exit_status >= 0) + exit (exit_status); +} + +void +lt_fatal (const char *message, ...) +{ + va_list ap; + va_start (ap, message); + lt_error_core (EXIT_FAILURE, "FATAL", message, ap); + va_end (ap); +} +EOF + # we should really use a build-platform specific compiler + # here, but OTOH, the wrappers (shell script and this C one) + # are only useful if you want to execute the "real" binary. + # Since the "real" binary is built for $host, then this + # wrapper might as well be built for $host, too. + $run $LTCC -s -o $cwrapper $cwrappersource + ;; + esac + $rm $output + trap "$rm $output; exit $EXIT_FAILURE" 1 2 15 + + $echo > $output "\ +#! $SHELL + +# $output - temporary wrapper script for $objdir/$outputname +# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP +# +# The $output program cannot be directly executed until all the libtool +# libraries that it depends on are installed. +# +# This wrapper script should never be moved out of the build directory. +# If it is, it will not operate correctly. + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='${SED} -e 1s/^X//' +sed_quote_subst='$sed_quote_subst' + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +if test \"\${CDPATH+set}\" = set; then CDPATH=:; export CDPATH; fi + +relink_command=\"$relink_command\" + +# This environment variable determines our operation mode. +if test \"\$libtool_install_magic\" = \"$magic\"; then + # install mode needs the following variable: + notinst_deplibs='$notinst_deplibs' +else + # When we are sourced in execute mode, \$file and \$echo are already set. + if test \"\$libtool_execute_magic\" != \"$magic\"; then + echo=\"$qecho\" + file=\"\$0\" + # Make sure echo works. + if test \"X\$1\" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift + elif test \"X\`(\$echo '\t') 2>/dev/null\`\" = 'X\t'; then + # Yippee, \$echo works! + : + else + # Restart under the correct shell, and then maybe \$echo will work. + exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"} + fi + fi\ +" + $echo >> $output "\ + + # Find the directory that this script lives in. + thisdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\` + test \"x\$thisdir\" = \"x\$file\" && thisdir=. + + # Follow symbolic links until we get to the real thisdir. + file=\`ls -ld \"\$file\" | ${SED} -n 's/.*-> //p'\` + while test -n \"\$file\"; do + destdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\` + + # If there was a directory component, then change thisdir. + if test \"x\$destdir\" != \"x\$file\"; then + case \"\$destdir\" in + [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; + *) thisdir=\"\$thisdir/\$destdir\" ;; + esac + fi + + file=\`\$echo \"X\$file\" | \$Xsed -e 's%^.*/%%'\` + file=\`ls -ld \"\$thisdir/\$file\" | ${SED} -n 's/.*-> //p'\` + done + + # Try to get the absolute directory name. + absdir=\`cd \"\$thisdir\" && pwd\` + test -n \"\$absdir\" && thisdir=\"\$absdir\" +" + + if test "$fast_install" = yes; then + $echo >> $output "\ + program=lt-'$outputname'$exeext + progdir=\"\$thisdir/$objdir\" + + if test ! -f \"\$progdir/\$program\" || \\ + { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ + test \"X\$file\" != \"X\$progdir/\$program\"; }; then + + file=\"\$\$-\$program\" + + if test ! -d \"\$progdir\"; then + $mkdir \"\$progdir\" + else + $rm \"\$progdir/\$file\" + fi" + + $echo >> $output "\ + + # relink executable if necessary + if test -n \"\$relink_command\"; then + if relink_command_output=\`eval \$relink_command 2>&1\`; then : + else + $echo \"\$relink_command_output\" >&2 + $rm \"\$progdir/\$file\" + exit $EXIT_FAILURE + fi + fi + + $mv \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || + { $rm \"\$progdir/\$program\"; + $mv \"\$progdir/\$file\" \"\$progdir/\$program\"; } + $rm \"\$progdir/\$file\" + fi" + else + $echo >> $output "\ + program='$outputname' + progdir=\"\$thisdir/$objdir\" +" + fi + + $echo >> $output "\ + + if test -f \"\$progdir/\$program\"; then" + + # Export our shlibpath_var if we have one. + if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then + $echo >> $output "\ + # Add our own library path to $shlibpath_var + $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" + + # Some systems cannot cope with colon-terminated $shlibpath_var + # The second colon is a workaround for a bug in BeOS R4 sed + $shlibpath_var=\`\$echo \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\` + + export $shlibpath_var +" + fi + + # fixup the dll searchpath if we need to. + if test -n "$dllsearchpath"; then + $echo >> $output "\ + # Add the dll search path components to the executable PATH + PATH=$dllsearchpath:\$PATH +" + fi + + $echo >> $output "\ + if test \"\$libtool_execute_magic\" != \"$magic\"; then + # Run the actual program with our arguments. +" + case $host in + # Backslashes separate directories on plain windows + *-*-mingw | *-*-os2*) + $echo >> $output "\ + exec \$progdir\\\\\$program \${1+\"\$@\"} +" + ;; + + *) + $echo >> $output "\ + exec \$progdir/\$program \${1+\"\$@\"} +" + ;; + esac + $echo >> $output "\ + \$echo \"\$0: cannot exec \$program \${1+\"\$@\"}\" + exit $EXIT_FAILURE + fi + else + # The program doesn't exist. + \$echo \"\$0: error: \$progdir/\$program does not exist\" 1>&2 + \$echo \"This script is just a wrapper for \$program.\" 1>&2 + $echo \"See the $PACKAGE documentation for more information.\" 1>&2 + exit $EXIT_FAILURE + fi +fi\ +" + chmod +x $output + fi + exit $EXIT_SUCCESS + ;; + esac + + # See if we need to build an old-fashioned archive. + for oldlib in $oldlibs; do + + if test "$build_libtool_libs" = convenience; then + oldobjs="$libobjs_save" + addlibs="$convenience" + build_libtool_libs=no + else + if test "$build_libtool_libs" = module; then + oldobjs="$libobjs_save" + build_libtool_libs=no + else + oldobjs="$old_deplibs $non_pic_objects" + fi + addlibs="$old_convenience" + fi + + if test -n "$addlibs"; then + gentop="$output_objdir/${outputname}x" + $show "${rm}r $gentop" + $run ${rm}r "$gentop" + $show "$mkdir $gentop" + $run $mkdir "$gentop" + status=$? + if test "$status" -ne 0 && test ! -d "$gentop"; then + exit $status + fi + generated="$generated $gentop" + + # Add in members from convenience archives. + for xlib in $addlibs; do + # Extract the objects. + case $xlib in + [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;; + *) xabs=`pwd`"/$xlib" ;; + esac + xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'` + xdir="$gentop/$xlib" + + $show "${rm}r $xdir" + $run ${rm}r "$xdir" + $show "$mkdir $xdir" + $run $mkdir "$xdir" + status=$? + if test "$status" -ne 0 && test ! -d "$xdir"; then + exit $status + fi + # We will extract separately just the conflicting names and we will no + # longer touch any unique names. It is faster to leave these extract + # automatically by $AR in one run. + $show "(cd $xdir && $AR x $xabs)" + $run eval "(cd \$xdir && $AR x \$xabs)" || exit $? + if ($AR t "$xabs" | sort | sort -uc >/dev/null 2>&1); then + : + else + $echo "$modename: warning: object name conflicts; renaming object files" 1>&2 + $echo "$modename: warning: to ensure that they will not overwrite" 1>&2 + $AR t "$xabs" | sort | uniq -cd | while read -r count name + do + i=1 + while test "$i" -le "$count" + do + # Put our $i before any first dot (extension) + # Never overwrite any file + name_to="$name" + while test "X$name_to" = "X$name" || test -f "$xdir/$name_to" + do + name_to=`$echo "X$name_to" | $Xsed -e "s/\([^.]*\)/\1-$i/"` + done + $show "(cd $xdir && $AR xN $i $xabs '$name' && $mv '$name' '$name_to')" + $run eval "(cd \$xdir && $AR xN $i \$xabs '$name' && $mv '$name' '$name_to')" || exit $? + i=`expr $i + 1` + done + done + fi + + oldobjs="$oldobjs "`find $xdir -name \*.${objext} -print -o -name \*.lo -print | $NL2SP` + done + fi + + # Do each command in the archive commands. + if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then + cmds=$old_archive_from_new_cmds + else + eval cmds=\"$old_archive_cmds\" + + if len=`expr "X$cmds" : ".*"` && + test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then + cmds=$old_archive_cmds + else + # the command line is too long to link in one step, link in parts + $echo "using piecewise archive linking..." + save_RANLIB=$RANLIB + RANLIB=: + objlist= + concat_cmds= + save_oldobjs=$oldobjs + # GNU ar 2.10+ was changed to match POSIX; thus no paths are + # encoded into archives. This makes 'ar r' malfunction in + # this piecewise linking case whenever conflicting object + # names appear in distinct ar calls; check, warn and compensate. + if (for obj in $save_oldobjs + do + $echo "X$obj" | $Xsed -e 's%^.*/%%' + done | sort | sort -uc >/dev/null 2>&1); then + : + else + $echo "$modename: warning: object name conflicts; overriding AR_FLAGS to 'cq'" 1>&2 + $echo "$modename: warning: to ensure that POSIX-compatible ar will work" 1>&2 + AR_FLAGS=cq + fi + # Is there a better way of finding the last object in the list? + for obj in $save_oldobjs + do + last_oldobj=$obj + done + for obj in $save_oldobjs + do + oldobjs="$objlist $obj" + objlist="$objlist $obj" + eval test_cmds=\"$old_archive_cmds\" + if len=`expr "X$test_cmds" : ".*"` && + test "$len" -le "$max_cmd_len"; then + : + else + # the above command should be used before it gets too long + oldobjs=$objlist + if test "$obj" = "$last_oldobj" ; then + RANLIB=$save_RANLIB + fi + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\" + objlist= + fi + done + RANLIB=$save_RANLIB + oldobjs=$objlist + if test "X$oldobjs" = "X" ; then + eval cmds=\"\$concat_cmds\" + else + eval cmds=\"\$concat_cmds~\$old_archive_cmds\" + fi + fi + fi + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + eval cmd=\"$cmd\" + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + done + + if test -n "$generated"; then + $show "${rm}r$generated" + $run ${rm}r$generated + fi + + # Now create the libtool archive. + case $output in + *.la) + old_library= + test "$build_old_libs" = yes && old_library="$libname.$libext" + $show "creating $output" + + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"` + relink_command="$var=\"$var_value\"; export $var; $relink_command" + fi + done + # Quote the link command for shipping. + relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" + relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"` + if test "$hardcode_automatic" = yes ; then + relink_command= + fi + + + # Only create the output if not a dry run. + if test -z "$run"; then + for installed in no yes; do + if test "$installed" = yes; then + if test -z "$install_libdir"; then + break + fi + output="$output_objdir/$outputname"i + # Replace all uninstalled libtool libraries with the installed ones + newdependency_libs= + for deplib in $dependency_libs; do + case $deplib in + *.la) + name=`$echo "X$deplib" | $Xsed -e 's%^.*/%%'` + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + if test -z "$libdir"; then + $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2 + exit $EXIT_FAILURE + fi + newdependency_libs="$newdependency_libs $libdir/$name" + ;; + *) newdependency_libs="$newdependency_libs $deplib" ;; + esac + done + dependency_libs="$newdependency_libs" + newdlfiles= + for lib in $dlfiles; do + name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + if test -z "$libdir"; then + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + exit $EXIT_FAILURE + fi + newdlfiles="$newdlfiles $libdir/$name" + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + if test -z "$libdir"; then + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + exit $EXIT_FAILURE + fi + newdlprefiles="$newdlprefiles $libdir/$name" + done + dlprefiles="$newdlprefiles" + else + newdlfiles= + for lib in $dlfiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + newdlfiles="$newdlfiles $abs" + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + newdlprefiles="$newdlprefiles $abs" + done + dlprefiles="$newdlprefiles" + fi + $rm $output + # place dlname in correct position for cygwin + tdlname=$dlname + case $host,$output,$installed,$module,$dlname in + *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;; + esac + $echo > $output "\ +# $outputname - a libtool library file +# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='$tdlname' + +# Names of this library. +library_names='$library_names' + +# The name of the static archive. +old_library='$old_library' + +# Libraries that this one depends upon. +dependency_libs='$dependency_libs' + +# Version information for $libname. +current=$current +age=$age +revision=$revision + +# Is this an already installed library? +installed=$installed + +# Should we warn about portability when linking against -modules? +shouldnotlink=$module + +# Files to dlopen/dlpreopen +dlopen='$dlfiles' +dlpreopen='$dlprefiles' + +# Directory that this library needs to be installed in: +libdir='$install_libdir'" + if test "$installed" = no && test "$need_relink" = yes; then + $echo >> $output "\ +relink_command=\"$relink_command\"" + fi + done + fi + + # Do a symbolic link so that the libtool archive can be found in + # LD_LIBRARY_PATH before the program is installed. + $show "(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)" + $run eval '(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)' || exit $? + ;; + esac + exit $EXIT_SUCCESS + ;; + + # libtool install mode + install) + modename="$modename: install" + + # There may be an optional sh(1) argument at the beginning of + # install_prog (especially on Windows NT). + if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || + # Allow the use of GNU shtool's install command. + $echo "X$nonopt" | $Xsed | grep shtool > /dev/null; then + # Aesthetically quote it. + arg=`$echo "X$nonopt" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + install_prog="$arg " + arg="$1" + shift + else + install_prog= + arg="$nonopt" + fi + + # The real first argument should be the name of the installation program. + # Aesthetically quote it. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + install_prog="$install_prog$arg" + + # We need to accept at least all the BSD install flags. + dest= + files= + opts= + prev= + install_type= + isdir=no + stripme= + for arg + do + if test -n "$dest"; then + files="$files $dest" + dest="$arg" + continue + fi + + case $arg in + -d) isdir=yes ;; + -f) prev="-f" ;; + -g) prev="-g" ;; + -m) prev="-m" ;; + -o) prev="-o" ;; + -s) + stripme=" -s" + continue + ;; + -*) ;; + + *) + # If the previous option needed an argument, then skip it. + if test -n "$prev"; then + prev= + else + dest="$arg" + continue + fi + ;; + esac + + # Aesthetically quote the argument. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + install_prog="$install_prog $arg" + done + + if test -z "$install_prog"; then + $echo "$modename: you must specify an install program" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + if test -n "$prev"; then + $echo "$modename: the \`$prev' option requires an argument" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + if test -z "$files"; then + if test -z "$dest"; then + $echo "$modename: no file or destination specified" 1>&2 + else + $echo "$modename: you must specify a destination" 1>&2 + fi + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Strip any trailing slash from the destination. + dest=`$echo "X$dest" | $Xsed -e 's%/$%%'` + + # Check to see that the destination is a directory. + test -d "$dest" && isdir=yes + if test "$isdir" = yes; then + destdir="$dest" + destname= + else + destdir=`$echo "X$dest" | $Xsed -e 's%/[^/]*$%%'` + test "X$destdir" = "X$dest" && destdir=. + destname=`$echo "X$dest" | $Xsed -e 's%^.*/%%'` + + # Not a directory, so check to see that there is only one file specified. + set dummy $files + if test "$#" -gt 2; then + $echo "$modename: \`$dest' is not a directory" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + fi + case $destdir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + for file in $files; do + case $file in + *.lo) ;; + *) + $echo "$modename: \`$destdir' must be an absolute directory name" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + ;; + esac + done + ;; + esac + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + staticlibs= + future_libdirs= + current_libdirs= + for file in $files; do + + # Do each installation. + case $file in + *.$libext) + # Do the static libraries later. + staticlibs="$staticlibs $file" + ;; + + *.la) + # Check to see that this really is a libtool archive. + if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : + else + $echo "$modename: \`$file' is not a valid libtool archive" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + library_names= + old_library= + relink_command= + # If there is no directory component, then add one. + case $file in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Add the libdir to current_libdirs if it is the destination. + if test "X$destdir" = "X$libdir"; then + case "$current_libdirs " in + *" $libdir "*) ;; + *) current_libdirs="$current_libdirs $libdir" ;; + esac + else + # Note the libdir as a future libdir. + case "$future_libdirs " in + *" $libdir "*) ;; + *) future_libdirs="$future_libdirs $libdir" ;; + esac + fi + + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`/ + test "X$dir" = "X$file/" && dir= + dir="$dir$objdir" + + if test -n "$relink_command"; then + # Determine the prefix the user has applied to our future dir. + inst_prefix_dir=`$echo "$destdir" | $SED "s%$libdir\$%%"` + + # Don't allow the user to place us outside of our expected + # location b/c this prevents finding dependent libraries that + # are installed to the same prefix. + # At present, this check doesn't affect windows .dll's that + # are installed into $libdir/../bin (currently, that works fine) + # but it's something to keep an eye on. + if test "$inst_prefix_dir" = "$destdir"; then + $echo "$modename: error: cannot install \`$file' to a directory not ending in $libdir" 1>&2 + exit $EXIT_FAILURE + fi + + if test -n "$inst_prefix_dir"; then + # Stick the inst_prefix_dir data into the link command. + relink_command=`$echo "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` + else + relink_command=`$echo "$relink_command" | $SED "s%@inst_prefix_dir@%%"` + fi + + $echo "$modename: warning: relinking \`$file'" 1>&2 + $show "$relink_command" + if $run eval "$relink_command"; then : + else + $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2 + exit $EXIT_FAILURE + fi + fi + + # See the names of the shared library. + set dummy $library_names + if test -n "$2"; then + realname="$2" + shift + shift + + srcname="$realname" + test -n "$relink_command" && srcname="$realname"T + + # Install the shared library and build the symlinks. + $show "$install_prog $dir/$srcname $destdir/$realname" + $run eval "$install_prog $dir/$srcname $destdir/$realname" || exit $? + if test -n "$stripme" && test -n "$striplib"; then + $show "$striplib $destdir/$realname" + $run eval "$striplib $destdir/$realname" || exit $? + fi + + if test "$#" -gt 0; then + # Delete the old symlinks, and create new ones. + for linkname + do + if test "$linkname" != "$realname"; then + $show "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)" + $run eval "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)" + fi + done + fi + + # Do each command in the postinstall commands. + lib="$destdir/$realname" + cmds=$postinstall_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + + # Install the pseudo-library for information purposes. + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + instname="$dir/$name"i + $show "$install_prog $instname $destdir/$name" + $run eval "$install_prog $instname $destdir/$name" || exit $? + + # Maybe install the static library, too. + test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library" + ;; + + *.lo) + # Install (i.e. copy) a libtool object. + + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + destfile="$destdir/$destfile" + fi + + # Deduce the name of the destination old-style object file. + case $destfile in + *.lo) + staticdest=`$echo "X$destfile" | $Xsed -e "$lo2o"` + ;; + *.$objext) + staticdest="$destfile" + destfile= + ;; + *) + $echo "$modename: cannot copy a libtool object to \`$destfile'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + # Install the libtool object if requested. + if test -n "$destfile"; then + $show "$install_prog $file $destfile" + $run eval "$install_prog $file $destfile" || exit $? + fi + + # Install the old object if enabled. + if test "$build_old_libs" = yes; then + # Deduce the name of the old-style object file. + staticobj=`$echo "X$file" | $Xsed -e "$lo2o"` + + $show "$install_prog $staticobj $staticdest" + $run eval "$install_prog \$staticobj \$staticdest" || exit $? + fi + exit $EXIT_SUCCESS + ;; + + *) + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + destfile="$destdir/$destfile" + fi + + # If the file is missing, and there is a .exe on the end, strip it + # because it is most likely a libtool script we actually want to + # install + stripped_ext="" + case $file in + *.exe) + if test ! -f "$file"; then + file=`$echo $file|${SED} 's,.exe$,,'` + stripped_ext=".exe" + fi + ;; + esac + + # Do a test to see if this is really a libtool program. + case $host in + *cygwin*|*mingw*) + wrapper=`$echo $file | ${SED} -e 's,.exe$,,'` + ;; + *) + wrapper=$file + ;; + esac + if (${SED} -e '4q' $wrapper | grep "^# Generated by .*$PACKAGE")>/dev/null 2>&1; then + notinst_deplibs= + relink_command= + + # To insure that "foo" is sourced, and not "foo.exe", + # finese the cygwin/MSYS system by explicitly sourcing "foo." + # which disallows the automatic-append-.exe behavior. + case $build in + *cygwin* | *mingw*) wrapperdot=${wrapper}. ;; + *) wrapperdot=${wrapper} ;; + esac + # If there is no directory component, then add one. + case $file in + */* | *\\*) . ${wrapperdot} ;; + *) . ./${wrapperdot} ;; + esac + + # Check the variables that should have been set. + if test -z "$notinst_deplibs"; then + $echo "$modename: invalid libtool wrapper script \`$wrapper'" 1>&2 + exit $EXIT_FAILURE + fi + + finalize=yes + for lib in $notinst_deplibs; do + # Check to see that each library is installed. + libdir= + if test -f "$lib"; then + # If there is no directory component, then add one. + case $lib in + */* | *\\*) . $lib ;; + *) . ./$lib ;; + esac + fi + libfile="$libdir/"`$echo "X$lib" | $Xsed -e 's%^.*/%%g'` ### testsuite: skip nested quoting test + if test -n "$libdir" && test ! -f "$libfile"; then + $echo "$modename: warning: \`$lib' has not been installed in \`$libdir'" 1>&2 + finalize=no + fi + done + + relink_command= + # To insure that "foo" is sourced, and not "foo.exe", + # finese the cygwin/MSYS system by explicitly sourcing "foo." + # which disallows the automatic-append-.exe behavior. + case $build in + *cygwin* | *mingw*) wrapperdot=${wrapper}. ;; + *) wrapperdot=${wrapper} ;; + esac + # If there is no directory component, then add one. + case $file in + */* | *\\*) . ${wrapperdot} ;; + *) . ./${wrapperdot} ;; + esac + + outputname= + if test "$fast_install" = no && test -n "$relink_command"; then + if test "$finalize" = yes && test -z "$run"; then + tmpdir="/tmp" + test -n "$TMPDIR" && tmpdir="$TMPDIR" + tmpdir="$tmpdir/libtool-$$" + save_umask=`umask` + umask 0077 + if $mkdir "$tmpdir"; then + umask $save_umask + else + umask $save_umask + $echo "$modename: error: cannot create temporary directory \`$tmpdir'" 1>&2 + continue + fi + file=`$echo "X$file$stripped_ext" | $Xsed -e 's%^.*/%%'` + outputname="$tmpdir/$file" + # Replace the output file specification. + relink_command=`$echo "X$relink_command" | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g'` + + $show "$relink_command" + if $run eval "$relink_command"; then : + else + $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2 + ${rm}r "$tmpdir" + continue + fi + file="$outputname" + else + $echo "$modename: warning: cannot relink \`$file'" 1>&2 + fi + else + # Install the binary that we compiled earlier. + file=`$echo "X$file$stripped_ext" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"` + fi + fi + + # remove .exe since cygwin /usr/bin/install will append another + # one anyways + case $install_prog,$host in + */usr/bin/install*,*cygwin*) + case $file:$destfile in + *.exe:*.exe) + # this is ok + ;; + *.exe:*) + destfile=$destfile.exe + ;; + *:*.exe) + destfile=`$echo $destfile | ${SED} -e 's,.exe$,,'` + ;; + esac + ;; + esac + $show "$install_prog$stripme $file $destfile" + $run eval "$install_prog\$stripme \$file \$destfile" || exit $? + test -n "$outputname" && ${rm}r "$tmpdir" + ;; + esac + done + + for file in $staticlibs; do + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + + # Set up the ranlib parameters. + oldlib="$destdir/$name" + + $show "$install_prog $file $oldlib" + $run eval "$install_prog \$file \$oldlib" || exit $? + + if test -n "$stripme" && test -n "$old_striplib"; then + $show "$old_striplib $oldlib" + $run eval "$old_striplib $oldlib" || exit $? + fi + + # Do each command in the postinstall commands. + cmds=$old_postinstall_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + done + + if test -n "$future_libdirs"; then + $echo "$modename: warning: remember to run \`$progname --finish$future_libdirs'" 1>&2 + fi + + if test -n "$current_libdirs"; then + # Maybe just do a dry run. + test -n "$run" && current_libdirs=" -n$current_libdirs" + exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs' + else + exit $EXIT_SUCCESS + fi + ;; + + # libtool finish mode + finish) + modename="$modename: finish" + libdirs="$nonopt" + admincmds= + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + for dir + do + libdirs="$libdirs $dir" + done + + for libdir in $libdirs; do + if test -n "$finish_cmds"; then + # Do each command in the finish commands. + cmds=$finish_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || admincmds="$admincmds + $cmd" + done + IFS="$save_ifs" + fi + if test -n "$finish_eval"; then + # Do the single finish_eval. + eval cmds=\"$finish_eval\" + $run eval "$cmds" || admincmds="$admincmds + $cmds" + fi + done + fi + + # Exit here if they wanted silent mode. + test "$show" = : && exit $EXIT_SUCCESS + + $echo "----------------------------------------------------------------------" + $echo "Libraries have been installed in:" + for libdir in $libdirs; do + $echo " $libdir" + done + $echo + $echo "If you ever happen to want to link against installed libraries" + $echo "in a given directory, LIBDIR, you must either use libtool, and" + $echo "specify the full pathname of the library, or use the \`-LLIBDIR'" + $echo "flag during linking and do at least one of the following:" + if test -n "$shlibpath_var"; then + $echo " - add LIBDIR to the \`$shlibpath_var' environment variable" + $echo " during execution" + fi + if test -n "$runpath_var"; then + $echo " - add LIBDIR to the \`$runpath_var' environment variable" + $echo " during linking" + fi + if test -n "$hardcode_libdir_flag_spec"; then + libdir=LIBDIR + eval flag=\"$hardcode_libdir_flag_spec\" + + $echo " - use the \`$flag' linker flag" + fi + if test -n "$admincmds"; then + $echo " - have your system administrator run these commands:$admincmds" + fi + if test -f /etc/ld.so.conf; then + $echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" + fi + $echo + $echo "See any operating system documentation about shared libraries for" + $echo "more information, such as the ld(1) and ld.so(8) manual pages." + $echo "----------------------------------------------------------------------" + exit $EXIT_SUCCESS + ;; + + # libtool execute mode + execute) + modename="$modename: execute" + + # The first argument is the command name. + cmd="$nonopt" + if test -z "$cmd"; then + $echo "$modename: you must specify a COMMAND" 1>&2 + $echo "$help" + exit $EXIT_FAILURE + fi + + # Handle -dlopen flags immediately. + for file in $execute_dlfiles; do + if test ! -f "$file"; then + $echo "$modename: \`$file' is not a file" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + dir= + case $file in + *.la) + # Check to see that this really is a libtool archive. + if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : + else + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Read the libtool library. + dlname= + library_names= + + # If there is no directory component, then add one. + case $file in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Skip this library if it cannot be dlopened. + if test -z "$dlname"; then + # Warn if it was a shared library. + test -n "$library_names" && $echo "$modename: warning: \`$file' was not linked with \`-export-dynamic'" + continue + fi + + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$file" && dir=. + + if test -f "$dir/$objdir/$dlname"; then + dir="$dir/$objdir" + else + $echo "$modename: cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" 1>&2 + exit $EXIT_FAILURE + fi + ;; + + *.lo) + # Just add the directory containing the .lo file. + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$file" && dir=. + ;; + + *) + $echo "$modename: warning \`-dlopen' is ignored for non-libtool libraries and objects" 1>&2 + continue + ;; + esac + + # Get the absolute pathname. + absdir=`cd "$dir" && pwd` + test -n "$absdir" && dir="$absdir" + + # Now add the directory to shlibpath_var. + if eval "test -z \"\$$shlibpath_var\""; then + eval "$shlibpath_var=\"\$dir\"" + else + eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" + fi + done + + # This variable tells wrapper scripts just to set shlibpath_var + # rather than running their programs. + libtool_execute_magic="$magic" + + # Check if any of the arguments is a wrapper script. + args= + for file + do + case $file in + -*) ;; + *) + # Do a test to see if this is really a libtool program. + if (${SED} -e '4q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + # If there is no directory component, then add one. + case $file in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Transform arg to wrapped name. + file="$progdir/$program" + fi + ;; + esac + # Quote arguments (to preserve shell metacharacters). + file=`$echo "X$file" | $Xsed -e "$sed_quote_subst"` + args="$args \"$file\"" + done + + if test -z "$run"; then + if test -n "$shlibpath_var"; then + # Export the shlibpath_var. + eval "export $shlibpath_var" + fi + + # Restore saved environment variables + if test "${save_LC_ALL+set}" = set; then + LC_ALL="$save_LC_ALL"; export LC_ALL + fi + if test "${save_LANG+set}" = set; then + LANG="$save_LANG"; export LANG + fi + + # Now prepare to actually exec the command. + exec_cmd="\$cmd$args" + else + # Display what would be done. + if test -n "$shlibpath_var"; then + eval "\$echo \"\$shlibpath_var=\$$shlibpath_var\"" + $echo "export $shlibpath_var" + fi + $echo "$cmd$args" + exit $EXIT_SUCCESS + fi + ;; + + # libtool clean and uninstall mode + clean | uninstall) + modename="$modename: $mode" + rm="$nonopt" + files= + rmforce= + exit_status=0 + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + for arg + do + case $arg in + -f) rm="$rm $arg"; rmforce=yes ;; + -*) rm="$rm $arg" ;; + *) files="$files $arg" ;; + esac + done + + if test -z "$rm"; then + $echo "$modename: you must specify an RM program" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + rmdirs= + + origobjdir="$objdir" + for file in $files; do + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + if test "X$dir" = "X$file"; then + dir=. + objdir="$origobjdir" + else + objdir="$dir/$origobjdir" + fi + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + test "$mode" = uninstall && objdir="$dir" + + # Remember objdir for removal later, being careful to avoid duplicates + if test "$mode" = clean; then + case " $rmdirs " in + *" $objdir "*) ;; + *) rmdirs="$rmdirs $objdir" ;; + esac + fi + + # Don't error if the file doesn't exist and rm -f was used. + if (test -L "$file") >/dev/null 2>&1 \ + || (test -h "$file") >/dev/null 2>&1 \ + || test -f "$file"; then + : + elif test -d "$file"; then + exit_status=1 + continue + elif test "$rmforce" = yes; then + continue + fi + + rmfiles="$file" + + case $name in + *.la) + # Possibly a libtool archive, so verify it. + if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + . $dir/$name + + # Delete the libtool libraries and symlinks. + for n in $library_names; do + rmfiles="$rmfiles $objdir/$n" + done + test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library" + test "$mode" = clean && rmfiles="$rmfiles $objdir/$name $objdir/${name}i" + + if test "$mode" = uninstall; then + if test -n "$library_names"; then + # Do each command in the postuninstall commands. + cmds=$postuninstall_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" + if test "$?" -ne 0 && test "$rmforce" != yes; then + exit_status=1 + fi + done + IFS="$save_ifs" + fi + + if test -n "$old_library"; then + # Do each command in the old_postuninstall commands. + cmds=$old_postuninstall_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" + if test "$?" -ne 0 && test "$rmforce" != yes; then + exit_status=1 + fi + done + IFS="$save_ifs" + fi + # FIXME: should reinstall the best remaining shared library. + fi + fi + ;; + + *.lo) + # Possibly a libtool object, so verify it. + if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + + # Read the .lo file + . $dir/$name + + # Add PIC object to the list of files to remove. + if test -n "$pic_object" \ + && test "$pic_object" != none; then + rmfiles="$rmfiles $dir/$pic_object" + fi + + # Add non-PIC object to the list of files to remove. + if test -n "$non_pic_object" \ + && test "$non_pic_object" != none; then + rmfiles="$rmfiles $dir/$non_pic_object" + fi + fi + ;; + + *) + if test "$mode" = clean ; then + noexename=$name + case $file in + *.exe) + file=`$echo $file|${SED} 's,.exe$,,'` + noexename=`$echo $name|${SED} 's,.exe$,,'` + # $file with .exe has already been added to rmfiles, + # add $file without .exe + rmfiles="$rmfiles $file" + ;; + esac + # Do a test to see if this is a libtool program. + if (${SED} -e '4q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + relink_command= + . $dir/$noexename + + # note $name still contains .exe if it was in $file originally + # as does the version of $file that was added into $rmfiles + rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}" + if test "$fast_install" = yes && test -n "$relink_command"; then + rmfiles="$rmfiles $objdir/lt-$name" + fi + if test "X$noexename" != "X$name" ; then + rmfiles="$rmfiles $objdir/lt-${noexename}.c" + fi + fi + fi + ;; + esac + $show "$rm $rmfiles" + $run $rm $rmfiles || exit_status=1 + done + objdir="$origobjdir" + + # Try to remove the ${objdir}s in the directories where we deleted files + for dir in $rmdirs; do + if test -d "$dir"; then + $show "rmdir $dir" + $run rmdir $dir >/dev/null 2>&1 + fi + done + + exit $exit_status + ;; + + "") + $echo "$modename: you must specify a MODE" 1>&2 + $echo "$generic_help" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + if test -z "$exec_cmd"; then + $echo "$modename: invalid operation mode \`$mode'" 1>&2 + $echo "$generic_help" 1>&2 + exit $EXIT_FAILURE + fi +fi # test -z "$show_help" + +if test -n "$exec_cmd"; then + eval exec $exec_cmd + exit $EXIT_FAILURE +fi + +# We need to display help for each of the modes. +case $mode in +"") $echo \ +"Usage: $modename [OPTION]... [MODE-ARG]... + +Provide generalized library-building support services. + + --config show all configuration variables + --debug enable verbose shell tracing +-n, --dry-run display commands without modifying any files + --features display basic configuration information and exit + --finish same as \`--mode=finish' + --help display this help message and exit + --mode=MODE use operation mode MODE [default=inferred from MODE-ARGS] + --quiet same as \`--silent' + --silent don't print informational messages + --tag=TAG use configuration variables from tag TAG + --version print version information + +MODE must be one of the following: + + clean remove files from the build directory + compile compile a source file into a libtool object + execute automatically set library path, then run a program + finish complete the installation of libtool libraries + install install libraries or executables + link create a library or an executable + uninstall remove libraries from an installed directory + +MODE-ARGS vary depending on the MODE. Try \`$modename --help --mode=MODE' for +a more detailed description of MODE. + +Report bugs to ." + exit $EXIT_SUCCESS + ;; + +clean) + $echo \ +"Usage: $modename [OPTION]... --mode=clean RM [RM-OPTION]... FILE... + +Remove files from the build directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, object or program, all the files associated +with it are deleted. Otherwise, only FILE itself is deleted using RM." + ;; + +compile) + $echo \ +"Usage: $modename [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE + +Compile a source file into a libtool library object. + +This mode accepts the following additional options: + + -o OUTPUT-FILE set the output file name to OUTPUT-FILE + -prefer-pic try to building PIC objects only + -prefer-non-pic try to building non-PIC objects only + -static always build a \`.o' file suitable for static linking + +COMPILE-COMMAND is a command to be used in creating a \`standard' object file +from the given SOURCEFILE. + +The output file name is determined by removing the directory component from +SOURCEFILE, then substituting the C source code suffix \`.c' with the +library object suffix, \`.lo'." + ;; + +execute) + $echo \ +"Usage: $modename [OPTION]... --mode=execute COMMAND [ARGS]... + +Automatically set library path, then run a program. + +This mode accepts the following additional options: + + -dlopen FILE add the directory containing FILE to the library path + +This mode sets the library path environment variable according to \`-dlopen' +flags. + +If any of the ARGS are libtool executable wrappers, then they are translated +into their corresponding uninstalled binary, and any of their required library +directories are added to the library path. + +Then, COMMAND is executed, with ARGS as arguments." + ;; + +finish) + $echo \ +"Usage: $modename [OPTION]... --mode=finish [LIBDIR]... + +Complete the installation of libtool libraries. + +Each LIBDIR is a directory that contains libtool libraries. + +The commands that this mode executes may require superuser privileges. Use +the \`--dry-run' option if you just want to see what would be executed." + ;; + +install) + $echo \ +"Usage: $modename [OPTION]... --mode=install INSTALL-COMMAND... + +Install executables or libraries. + +INSTALL-COMMAND is the installation command. The first component should be +either the \`install' or \`cp' program. + +The rest of the components are interpreted as arguments to that command (only +BSD-compatible install options are recognized)." + ;; + +link) + $echo \ +"Usage: $modename [OPTION]... --mode=link LINK-COMMAND... + +Link object files or libraries together to form another library, or to +create an executable program. + +LINK-COMMAND is a command using the C compiler that you would use to create +a program from several object files. + +The following components of LINK-COMMAND are treated specially: + + -all-static do not do any dynamic linking at all + -avoid-version do not add a version suffix if possible + -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime + -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols + -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) + -export-symbols SYMFILE + try to export only the symbols listed in SYMFILE + -export-symbols-regex REGEX + try to export only the symbols matching REGEX + -LLIBDIR search LIBDIR for required installed libraries + -lNAME OUTPUT-FILE requires the installed library libNAME + -module build a library that can dlopened + -no-fast-install disable the fast-install mode + -no-install link a not-installable executable + -no-undefined declare that a library does not refer to external symbols + -o OUTPUT-FILE create OUTPUT-FILE from the specified objects + -objectlist FILE Use a list of object files found in FILE to specify objects + -precious-files-regex REGEX + don't remove output files matching REGEX + -release RELEASE specify package release information + -rpath LIBDIR the created library will eventually be installed in LIBDIR + -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries + -static do not do any dynamic linking of libtool libraries + -version-info CURRENT[:REVISION[:AGE]] + specify library version info [each variable defaults to 0] + +All other options (arguments beginning with \`-') are ignored. + +Every other argument is treated as a filename. Files ending in \`.la' are +treated as uninstalled libtool libraries, other files are standard or library +object files. + +If the OUTPUT-FILE ends in \`.la', then a libtool library is created, +only library objects (\`.lo' files) may be specified, and \`-rpath' is +required, except when creating a convenience library. + +If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created +using \`ar' and \`ranlib', or on Windows using \`lib'. + +If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file +is created, otherwise an executable program is created." + ;; + +uninstall) + $echo \ +"Usage: $modename [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... + +Remove libraries from an installation directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, all the files associated with it are deleted. +Otherwise, only FILE itself is deleted using RM." + ;; + +*) + $echo "$modename: invalid operation mode \`$mode'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + ;; +esac + +$echo +$echo "Try \`$modename --help' for more information about other modes." + +exit $EXIT_SUCCESS + +# The TAGs below are defined such that we never get into a situation +# in which we disable both kinds of libraries. Given conflicting +# choices, we go for a static library, that is the most portable, +# since we can't tell whether shared libraries were disabled because +# the user asked for that or because the platform doesn't support +# them. This is particularly important on AIX, because we don't +# support having both static and shared libraries enabled at the same +# time on that platform, so we default to a shared-only configuration. +# If a disable-shared tag is given, we'll fallback to a static-only +# configuration. But we'll never go from static-only to shared-only. + +# ### BEGIN LIBTOOL TAG CONFIG: disable-shared +build_libtool_libs=no +build_old_libs=yes +# ### END LIBTOOL TAG CONFIG: disable-shared + +# ### BEGIN LIBTOOL TAG CONFIG: disable-static +build_old_libs=`case $build_libtool_libs in yes) $echo no;; *) $echo yes;; esac` +# ### END LIBTOOL TAG CONFIG: disable-static + +# Local Variables: +# mode:shell-script +# sh-indentation:2 +# End: diff --git a/missing b/missing new file mode 100644 index 0000000..6a37006 --- /dev/null +++ b/missing @@ -0,0 +1,336 @@ +#! /bin/sh +# Common stub for a few missing GNU programs while installing. +# Copyright (C) 1996, 1997, 1999, 2000, 2002 Free Software Foundation, Inc. +# Originally by Fran,cois Pinard , 1996. + +# 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, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +if test $# -eq 0; then + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 +fi + +run=: + +# In the cases where this matters, `missing' is being run in the +# srcdir already. +if test -f configure.ac; then + configure_ac=configure.ac +else + configure_ac=configure.in +fi + +case "$1" in +--run) + # Try to run requested program, and just exit if it succeeds. + run= + shift + "$@" && exit 0 + ;; +esac + +# If it does not exist, or fails to run (possibly an outdated version), +# try to emulate it. +case "$1" in + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an +error status if there is no known handling for PROGRAM. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + --run try to run the given command, and emulate it if it fails + +Supported PROGRAM values: + aclocal touch file \`aclocal.m4' + autoconf touch file \`configure' + autoheader touch file \`config.h.in' + automake touch all \`Makefile.in' files + bison create \`y.tab.[ch]', if possible, from existing .[ch] + flex create \`lex.yy.c', if possible, from existing .c + help2man touch the output file + lex create \`lex.yy.c', if possible, from existing .c + makeinfo touch the output file + tar try tar, gnutar, gtar, then tar without non-portable flags + yacc create \`y.tab.[ch]', if possible, from existing .[ch]" + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing 0.4 - GNU automake" + ;; + + -*) + echo 1>&2 "$0: Unknown \`$1' option" + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 + ;; + + aclocal*) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`acinclude.m4' or \`${configure_ac}'. You might want + to install the \`Automake' and \`Perl' packages. Grab them from + any GNU archive site." + touch aclocal.m4 + ;; + + autoconf) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`${configure_ac}'. You might want to install the + \`Autoconf' and \`GNU m4' packages. Grab them from any GNU + archive site." + touch configure + ;; + + autoheader) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`acconfig.h' or \`${configure_ac}'. You might want + to install the \`Autoconf' and \`GNU m4' packages. Grab them + from any GNU archive site." + files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` + test -z "$files" && files="config.h" + touch_files= + for f in $files; do + case "$f" in + *:*) touch_files="$touch_files "`echo "$f" | + sed -e 's/^[^:]*://' -e 's/:.*//'`;; + *) touch_files="$touch_files $f.in";; + esac + done + touch $touch_files + ;; + + automake*) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. + You might want to install the \`Automake' and \`Perl' packages. + Grab them from any GNU archive site." + find . -type f -name Makefile.am -print | + sed 's/\.am$/.in/' | + while read f; do touch "$f"; done + ;; + + autom4te) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is needed, and you do not seem to have it handy on your + system. You might have modified some files without having the + proper tools for further handling them. + You can get \`$1Help2man' as part of \`Autoconf' from any GNU + archive site." + + file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'` + test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo "#! /bin/sh" + echo "# Created by GNU Automake missing as a replacement of" + echo "# $ $@" + echo "exit 0" + chmod +x $file + exit 1 + fi + ;; + + bison|yacc) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a \`.y' file. You may need the \`Bison' package + in order for those modifications to take effect. You can get + \`Bison' from any GNU archive site." + rm -f y.tab.c y.tab.h + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.y) + SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.c + fi + SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.h + fi + ;; + esac + fi + if [ ! -f y.tab.h ]; then + echo >y.tab.h + fi + if [ ! -f y.tab.c ]; then + echo 'main() { return 0; }' >y.tab.c + fi + ;; + + lex|flex) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a \`.l' file. You may need the \`Flex' package + in order for those modifications to take effect. You can get + \`Flex' from any GNU archive site." + rm -f lex.yy.c + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.l) + SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" lex.yy.c + fi + ;; + esac + fi + if [ ! -f lex.yy.c ]; then + echo 'main() { return 0; }' >lex.yy.c + fi + ;; + + help2man) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a dependency of a manual page. You may need the + \`Help2man' package in order for those modifications to take + effect. You can get \`Help2man' from any GNU archive site." + + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'` + fi + if [ -f "$file" ]; then + touch $file + else + test -z "$file" || exec >$file + echo ".ab help2man is required to generate this page" + exit 1 + fi + ;; + + makeinfo) + if test -z "$run" && (makeinfo --version) > /dev/null 2>&1; then + # We have makeinfo, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a \`.texi' or \`.texinfo' file, or any other file + indirectly affecting the aspect of the manual. The spurious + call might also be the consequence of using a buggy \`make' (AIX, + DU, IRIX). You might want to install the \`Texinfo' package or + the \`GNU make' package. Grab either from any GNU archive site." + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` + file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file` + fi + touch $file + ;; + + tar) + shift + if test -n "$run"; then + echo 1>&2 "ERROR: \`tar' requires --run" + exit 1 + fi + + # We have already tried tar in the generic part. + # Look for gnutar/gtar before invocation to avoid ugly error + # messages. + if (gnutar --version > /dev/null 2>&1); then + gnutar "$@" && exit 0 + fi + if (gtar --version > /dev/null 2>&1); then + gtar "$@" && exit 0 + fi + firstarg="$1" + if shift; then + case "$firstarg" in + *o*) + firstarg=`echo "$firstarg" | sed s/o//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + case "$firstarg" in + *h*) + firstarg=`echo "$firstarg" | sed s/h//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + fi + + echo 1>&2 "\ +WARNING: I can't seem to be able to run \`tar' with the given arguments. + You may want to install GNU tar or Free paxutils, or check the + command line arguments." + exit 1 + ;; + + *) + echo 1>&2 "\ +WARNING: \`$1' is needed, and you do not seem to have it handy on your + system. You might have modified some files without having the + proper tools for further handling them. Check the \`README' file, + it often tells you about the needed prerequirements for installing + this package. You may also peek at any GNU archive site, in case + some other package would contain this missing \`$1' program." + exit 1 + ;; +esac + +exit 0 diff --git a/mkinstalldirs b/mkinstalldirs new file mode 100644 index 0000000..7e4ce6f --- /dev/null +++ b/mkinstalldirs @@ -0,0 +1,40 @@ +#! /bin/sh +# mkinstalldirs --- make directory hierarchy +# Author: Noah Friedman +# Created: 1993-05-16 +# Public domain + +# $Id: mkinstalldirs 678 2004-03-05 14:55:29Z laforge $ + +errstatus=0 + +for file +do + set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` + shift + + pathcomp= + for d + do + pathcomp="$pathcomp$d" + case "$pathcomp" in + -* ) pathcomp=./$pathcomp ;; + esac + + if test ! -d "$pathcomp"; then + echo "mkdir $pathcomp" + + mkdir "$pathcomp" || lasterr=$? + + if test ! -d "$pathcomp"; then + errstatus=$lasterr + fi + fi + + pathcomp="$pathcomp/" + done +done + +exit $errstatus + +# mkinstalldirs ends here diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..ae3f429 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,8 @@ +bin_PROGRAMS = conntrack +conntrack_SOURCES = conntrack.c libct.c + +INCLUDES= $(all_includes) -I$(top_srcdir)/include -I${KERNELDIR} +conntrack_LDFLAGS = $(all_libraries) -rdynamic + +#AM_CFLAGS = -g +#LINKOPTS=-ldl -lnfnetlink -lctnetlink -rdynamic diff --git a/src/conntrack.c b/src/conntrack.c index 2c716f7..ed97a86 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -46,7 +46,7 @@ #include "libct_proto.h" #define PROGNAME "conntrack" -#define VERSION "0.25" +#define VERSION "0.50" #if 0 #define DEBUGP printf @@ -78,9 +78,15 @@ enum action { CT_EVENT = (1 << CT_EVENT_BIT), CT_ACTION_BIT = 6, - CT_ACTION = (1 << CT_ACTION_BIT) + CT_ACTION = (1 << CT_ACTION_BIT), + + CT_VERSION_BIT = 7, + CT_VERSION = (1 << CT_VERSION_BIT), + + CT_HELP_BIT = 8, + CT_HELP = (1 << CT_HELP_BIT), }; -#define NUMBER_OF_CMD 7 +#define NUMBER_OF_CMD 9 enum options { CT_OPT_ORIG_SRC_BIT = 0, @@ -102,28 +108,29 @@ enum options { CT_OPT_PROTO_BIT = 4, CT_OPT_PROTO = (1 << CT_OPT_PROTO_BIT), - CT_OPT_ID_BIT = 5, - CT_OPT_ID = (1 << CT_OPT_ID_BIT), - - CT_OPT_TIMEOUT_BIT = 6, + CT_OPT_TIMEOUT_BIT = 5, CT_OPT_TIMEOUT = (1 << CT_OPT_TIMEOUT_BIT), - CT_OPT_STATUS_BIT = 7, + CT_OPT_STATUS_BIT = 6, CT_OPT_STATUS = (1 << CT_OPT_STATUS_BIT), - CT_OPT_ZERO_BIT = 8, + CT_OPT_ZERO_BIT = 7, CT_OPT_ZERO = (1 << CT_OPT_ZERO_BIT), - CT_OPT_DUMP_MASK_BIT = 9, + CT_OPT_DUMP_MASK_BIT = 8, CT_OPT_DUMP_MASK = (1 << CT_OPT_DUMP_MASK_BIT), + CT_OPT_GROUP_MASK_BIT = 9, + CT_OPT_GROUP_MASK = (1 << CT_OPT_GROUP_MASK_BIT), + CT_OPT_EVENT_MASK_BIT = 10, CT_OPT_EVENT_MASK = (1 << CT_OPT_EVENT_MASK_BIT), + }; #define NUMBER_OF_OPT 11 static const char optflags[NUMBER_OF_OPT] -= { 's', 'd', 'r', 'q', 'p', 'i', 't', 'u', 'z','m','g'}; += { 's', 'd', 'r', 'q', 'p', 't', 'u', 'z','m','g','e'}; static struct option original_opts[] = { {"dump", 2, 0, 'L'}, @@ -133,17 +140,19 @@ static struct option original_opts[] = { {"flush", 1, 0, 'F'}, {"event", 1, 0, 'E'}, {"action", 1, 0, 'A'}, + {"version", 0, 0, 'V'}, + {"help", 0, 0, 'h'}, {"orig-src", 1, 0, 's'}, {"orig-dst", 1, 0, 'd'}, {"reply-src", 1, 0, 'r'}, {"reply-dst", 1, 0, 'q'}, {"protonum", 1, 0, 'p'}, {"timeout", 1, 0, 't'}, - {"id", 1, 0, 'i'}, {"status", 1, 0, 'u'}, {"zero", 0, 0, 'z'}, {"dump-mask", 1, 0, 'm'}, {"groups", 1, 0, 'g'}, + {"event-mask", 1, 0, 'e'}, {0, 0, 0, 0} }; @@ -164,19 +173,24 @@ static unsigned int global_option_offset = 0; static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = /* Well, it's better than "Re: Linux vs FreeBSD" */ { - /* -s -d -r -q -p -i -t -u -z -m -g*/ -/*LIST*/ {'x','x','x','x','x','x','x','x',' ','x','x'}, -/*CREATE*/ {'+','+','+','+','+','x','+','+','x','x','x'}, -/*DELETE*/ {' ',' ',' ',' ',' ','+','x','x','x','x','x'}, -/*GET*/ {' ',' ',' ',' ','+','+','x','x','x','x','x'}, + /* -s -d -r -q -p -t -u -z -m -g -e */ +/*LIST*/ {'x','x','x','x','x','x','x',' ','x','x','x'}, +/*CREATE*/ {'+','+','+','+','+','+','+','x','x','x','x'}, +/*DELETE*/ {' ',' ',' ',' ',' ','x','x','x','x','x','x'}, +/*GET*/ {' ',' ',' ',' ','+','x','x','x','x','x','x'}, /*FLUSH*/ {'x','x','x','x','x','x','x','x','x','x','x'}, -/*EVENT*/ {'x','x','x','x','x','x','x','x','x','x',' '}, -/*ACTION*/ {'x','x','x','x','x','x','x','x',' ',' ','x'}, +/*EVENT*/ {'x','x','x','x','x','x','x','x','x',' ','x'}, +/*ACTION*/ {'x','x','x','x','x','x','x','x',' ','x',' '}, +/*VERSION*/ {'x','x','x','x','x','x','x','x','x','x','x'}, +/*HELP*/ {'x','x','x','x','x','x','x','x','x','x','x'}, }; +/* FIXME: hardcoded!, this must be defined during compilation time */ +char *lib_dir = CONNTRACK_LIB_DIR; + LIST_HEAD(proto_list); -char *proto2str[] = { +char *proto2str[IPPROTO_MAX] = { [IPPROTO_TCP] = "tcp", [IPPROTO_UDP] = "udp", [IPPROTO_ICMP] = "icmp", @@ -249,7 +263,7 @@ generic_opt_check(int command, int options) } } if (legal == -1) - exit_error(PARAMETER_PROBLEM, "Illegal option `-%c'" + exit_error(PARAMETER_PROBLEM, "Illegal option `-%c' " "with this command\n", optflags[i]); } } @@ -280,7 +294,7 @@ merge_options(struct option *oldopts, const struct option *newopts, static void dump_tuple(struct ip_conntrack_tuple *tp) { - fprintf(stderr, "tuple %p: %u %u.%u.%u.%u:%hu -> %u.%u.%u.%u:%hu\n", + fprintf(stdout, "tuple %p: %u %u.%u.%u.%u:%hu -> %u.%u.%u.%u:%hu\n", tp, tp->dst.protonum, NIPQUAD(tp->src.ip), ntohs(tp->src.u.all), NIPQUAD(tp->dst.ip), ntohs(tp->dst.u.all)); @@ -291,64 +305,67 @@ void not_implemented_yet() exit_error(OTHER_PROBLEM, "Sorry, not implemented yet :(\n"); } -static int -do_parse_status(const char *str, size_t strlen, unsigned int *status) -{ - if (strncasecmp(str, "ASSURED", strlen) == 0) - *status |= IPS_ASSURED; - else if (strncasecmp(str, "SEEN_REPLY", strlen) == 0) - *status |= IPS_SEEN_REPLY; - else if (strncasecmp(str, "UNSET", strlen) == 0) - *status |= 0; - else - return 0; - return 1; -} -static void -parse_status(const char *arg, unsigned int *status) -{ - const char *comma; - - while ((comma = strchr(arg, ',')) != NULL) { - if (comma == arg || !do_parse_status(arg, comma-arg, status)) - exit_error(PARAMETER_PROBLEM, "Bad status `%s'", arg); - arg = comma+1; - } - - if (strlen(arg) == 0 || !do_parse_status(arg, strlen(arg), status)) - exit_error(PARAMETER_PROBLEM, "Bad status `%s'", arg); -} +#define PARSE_STATUS 0 +#define PARSE_GROUP 1 +#define PARSE_EVENT 2 +#define PARSE_DUMP 3 +#define PARSE_MAX PARSE_DUMP+1 + +static struct parse_parameter { + char *parameter[10]; + size_t size; + unsigned int value[10]; +} parse_array[PARSE_MAX] = { + { {"ASSURED", "SEEN_REPLY", "UNSET"}, + 3, + { IPS_ASSURED, IPS_SEEN_REPLY, 0} }, + { {"ALL", "TCP", "UDP", "ICMP"}, + 4, + {~0U, NFGRP_IPV4_CT_TCP, NFGRP_IPV4_CT_UDP, NFGRP_IPV4_CT_ICMP} }, + { {"ALL", "NEW", "RELATED", "DESTROY", "REFRESH", "STATUS", + "PROTOINFO", "HELPER", "HELPINFO", "NATINFO"}, + 10, + {~0U, IPCT_NEW, IPCT_RELATED, IPCT_DESTROY, IPCT_REFRESH, IPCT_STATUS, + IPCT_PROTOINFO, IPCT_HELPER, IPCT_HELPINFO, IPCT_NATINFO} }, + { {"ALL", "TUPLE", "STATUS", "TIMEOUT", "PROTOINFO", "HELPINFO", + "COUNTERS", "MARK"}, 8, + {~0U, DUMP_TUPLE, DUMP_STATUS, DUMP_TIMEOUT, DUMP_PROTOINFO, + DUMP_HELPINFO, DUMP_COUNTERS, DUMP_MARK} } +}; static int -do_parse_group(const char *str, size_t strlen, unsigned int *group) +do_parse_parameter(const char *str, size_t strlen, unsigned int *value, + int parse_type) { - if (strncasecmp(str, "ALL", strlen) == 0) - *group |= ~0U; - else if (strncasecmp(str, "TCP", strlen) == 0) - *group |= NFGRP_IPV4_CT_TCP; - else if (strncasecmp(str, "UDP", strlen) == 0) - *group |= NFGRP_IPV4_CT_UDP; - else if (strncasecmp(str, "ICMP", strlen) == 0) - *group |= NFGRP_IPV4_CT_ICMP; - else - return 0; - return 1; + int i, ret = 0; + struct parse_parameter *p = &parse_array[parse_type]; + + for (i = 0; i < p->size; i++) + if (strncasecmp(str, p->parameter[i], strlen) == 0) { + *value |= p->value[i]; + ret = 1; + break; + } + + return ret; } static void -parse_group(const char *arg, unsigned int *group) +parse_parameter(const char *arg, unsigned int *status, int parse_type) { const char *comma; while ((comma = strchr(arg, ',')) != NULL) { - if (comma == arg || !do_parse_group(arg, comma-arg, group)) - exit_error(PARAMETER_PROBLEM, "Bad status `%s'", arg); + if (comma == arg + || !do_parse_parameter(arg, comma-arg, status, parse_type)) + exit_error(PARAMETER_PROBLEM,"Bad parameter `%s'", arg); arg = comma+1; } - if (strlen(arg) == 0 || !do_parse_group(arg, strlen(arg), group)) - exit_error(PARAMETER_PROBLEM, "Bad status `%s'", arg); + if (strlen(arg) == 0 + || !do_parse_parameter(arg, strlen(arg), status, parse_type)) + exit_error(PARAMETER_PROBLEM, "Bad parameter `%s'", arg); } unsigned int check_type(int argc, char *argv[]) @@ -442,27 +459,30 @@ int iptables_insmod(const char *modname, const char *modprobe) } void usage(char *prog) { -fprintf(stderr, "Tool to manipulate conntrack and expectations. Version %s\n", VERSION); -fprintf(stderr, "Usage: %s [commands] [options]\n", prog); -fprintf(stderr, "\n"); -fprintf(stderr, "Commands:\n"); -fprintf(stderr, "-L table List conntrack or expectation table\n"); -fprintf(stderr, "-G table [options] Get conntrack or expectation\n"); -fprintf(stderr, "-D table [options] Delete conntrack or expectation\n"); -fprintf(stderr, "-I table [options] Create a conntrack or expectation\n"); -fprintf(stderr, "-E table Show events\n"); -fprintf(stderr, "-F table Flush table\n"); -fprintf(stderr, "\n"); -fprintf(stderr, "Options:\n"); -fprintf(stderr, "--orig-src Source address from original direction\n"); -fprintf(stderr, "--orig-dst Destination address from original direction\n"); -fprintf(stderr, "--reply-src Source addres from reply direction\n"); -fprintf(stderr, "--reply-dst Destination address from reply direction\n"); -fprintf(stderr, "-p Layer 4 Protocol\n"); -fprintf(stderr, "-t Timeout\n"); -fprintf(stderr, "-i Conntrack ID\n"); -fprintf(stderr, "-u Status\n"); -fprintf(stderr, "-z Zero Counters\n"); +fprintf(stdout, "Tool to manipulate conntrack and expectations. Version %s\n", VERSION); +fprintf(stdout, "Usage: %s [commands] [options]\n", prog); +fprintf(stdout, "\n"); +fprintf(stdout, "Commands:\n"); +fprintf(stdout, "-L [table] [-z] List conntrack or expectation table\n"); +fprintf(stdout, "-G [table] parameters Get conntrack or expectation\n"); +fprintf(stdout, "-D [table] parameters Delete conntrack or expectation\n"); +fprintf(stdout, "-I [table] parameters Create a conntrack or expectation\n"); +fprintf(stdout, "-E [table] [options] Show events\n"); +fprintf(stdout, "-F [table] Flush table\n"); +fprintf(stdout, "-A [table] [options] Set action\n"); +fprintf(stdout, "\n"); +fprintf(stdout, "Options:\n"); +fprintf(stdout, "--orig-src ip Source address from original direction\n"); +fprintf(stdout, "--orig-dst ip Destination address from original direction\n"); +fprintf(stdout, "--reply-src ip Source addres from reply direction\n"); +fprintf(stdout, "--reply-dst ip Destination address from reply direction\n"); +fprintf(stdout, "-p proto Layer 4 Protocol\n"); +fprintf(stdout, "-t timeout Set timeout\n"); +fprintf(stdout, "-u status Set status\n"); +fprintf(stdout, "-m dumpmask Set dump mask\n"); +fprintf(stdout, "-g groupmask Set group mask\n"); +fprintf(stdout, "-e eventmask Set event mask\n"); +fprintf(stdout, "-z Zero Counters\n"); } int main(int argc, char *argv[]) @@ -473,11 +493,11 @@ int main(int argc, char *argv[]) struct ctproto_handler *h = NULL; union ip_conntrack_proto proto; unsigned long timeout = 0; - unsigned int status = 0; + unsigned int status = 0, group_mask = 0; unsigned long id = 0; - unsigned int type = 0, mask = 0, extra_flags = 0, event_mask = 0; + unsigned int type = 0, dump_mask = 0, extra_flags = 0, event_mask = 0; int res = 0, retry = 2; - + memset(&proto, 0, sizeof(union ip_conntrack_proto)); memset(&orig, 0, sizeof(struct ip_conntrack_tuple)); memset(&reply, 0, sizeof(struct ip_conntrack_tuple)); @@ -485,7 +505,7 @@ int main(int argc, char *argv[]) reply.dst.dir = IP_CT_DIR_REPLY; while ((c = getopt_long(argc, argv, - "L::I::D::G::E::A::s:d:r:q:p:i:t:u:m:g:z", + "L::I::D::G::E::A::F::hVs:d:r:q:p:t:u:m:g:e:z", opts, NULL)) != -1) { switch(c) { case 'L': @@ -515,12 +535,19 @@ int main(int argc, char *argv[]) case 'A': command |= CT_ACTION; type = check_type(argc, argv); + break; + case 'V': + command |= CT_VERSION; + break; + case 'h': + command |= CT_HELP; + break; case 'm': if (!optarg) continue; options |= CT_OPT_DUMP_MASK; - mask = atoi(optarg); + parse_parameter(optarg, &dump_mask, PARSE_DUMP); break; case 's': options |= CT_OPT_ORIG_SRC; @@ -552,10 +579,6 @@ int main(int argc, char *argv[]) opts = merge_options(opts, h->opts, &h->option_offset); break; - case 'i': - options |= CT_OPT_ID; - id = atoi(optarg); - break; case 't': options |= CT_OPT_TIMEOUT; if (optarg) @@ -567,14 +590,18 @@ int main(int argc, char *argv[]) continue; options |= CT_OPT_STATUS; - parse_status(optarg, &status); + parse_parameter(optarg, &status, PARSE_STATUS); /* Just insert confirmed conntracks */ status |= IPS_CONFIRMED; break; } case 'g': + options |= CT_OPT_GROUP_MASK; + parse_parameter(optarg, &group_mask, PARSE_GROUP); + break; + case 'e': options |= CT_OPT_EVENT_MASK; - parse_group(optarg, &event_mask); + parse_parameter(optarg, &event_mask, PARSE_EVENT); break; case 'z': options |= CT_OPT_ZERO; @@ -611,16 +638,14 @@ int main(int argc, char *argv[]) break; case CT_CREATE: - fprintf(stderr, "create\n"); if (type == 0) - create_conntrack(&orig, &reply, timeout, - &proto, status); + res = create_conntrack(&orig, &reply, timeout, + &proto, status); else not_implemented_yet(); break; case CT_DELETE: - fprintf(stderr, "delete\n"); if (type == 0) { if (options & CT_OPT_ORIG) res =delete_conntrack(&orig, CTA_ORIG, @@ -633,7 +658,6 @@ int main(int argc, char *argv[]) break; case CT_GET: - fprintf(stderr, "get\n"); if (type == 0) { if (options & CT_OPT_ORIG) res = get_conntrack(&orig, CTA_ORIG, @@ -646,26 +670,35 @@ int main(int argc, char *argv[]) break; case CT_FLUSH: - not_implemented_yet(); + if (type == 0) + res = flush_conntrack(); + else + not_implemented_yet(); break; case CT_EVENT: if (type == 0) { - if (options & CT_OPT_EVENT_MASK) - res = event_conntrack(event_mask); + if (options & CT_OPT_GROUP_MASK) + res = event_conntrack(group_mask); else res = event_conntrack(~0U); } else - /* and surely it won't ever... */ not_implemented_yet(); case CT_ACTION: if (type == 0) if (options & CT_OPT_DUMP_MASK) - res = set_dump_mask(mask); + res = set_mask(dump_mask, 0); + else if (options & CT_OPT_EVENT_MASK) + res = set_mask(event_mask, 1); break; - - default: + case CT_VERSION: + fprintf(stdout, "%s v%s\n", PROGNAME, VERSION); + break; + case CT_HELP: + usage(argv[0]); + break; + default: usage(argv[0]); break; } @@ -684,5 +717,5 @@ int main(int argc, char *argv[]) } if (res == -1) - fprintf(stderr, "Operations failed\n"); + fprintf(stderr, "Operation failed\n"); } diff --git a/src/libct.c b/src/libct.c index 143901b..d44b920 100644 --- a/src/libct.c +++ b/src/libct.c @@ -1,3 +1,11 @@ +/* + * (C) 2005 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 #include #include @@ -16,9 +24,18 @@ #define DEBUGP #endif +extern char *lib_dir; extern struct list_head proto_list; extern char *proto2str[]; +static void print_status(unsigned int status) +{ + if (status & IPS_ASSURED) + fprintf(stdout, "[ASSURED] "); + if (!(status & IPS_SEEN_REPLY)) + fprintf(stdout, "[UNREPLIED] "); +} + static int handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void *arg) { struct nfgenmsg *nfmsg; @@ -52,49 +69,48 @@ static int handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void *arg) switch(attr->nfa_type) { case CTA_ORIG: orig = NFA_DATA(attr); - printf("src=%u.%u.%u.%u dst=%u.%u.%u.%u ", + fprintf(stdout, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ", NIPQUAD(orig->src.ip), NIPQUAD(orig->dst.ip)); h = findproto(proto2str[orig->dst.protonum]); - if (h && h->print) - h->print(orig); + if (h && h->print_tuple) + h->print_tuple(orig); break; case CTA_RPLY: reply = NFA_DATA(attr); - printf("src=%u.%u.%u.%u dst=%u.%u.%u.%u ", + fprintf(stdout, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ", NIPQUAD(reply->src.ip), NIPQUAD(reply->dst.ip)); h = findproto(proto2str[reply->dst.protonum]); - if (h && h->print) - h->print(reply); + if (h && h->print_tuple) + h->print_tuple(reply); break; case CTA_STATUS: status = NFA_DATA(attr); - printf("status=%u ", *status); + print_status(*status); break; case CTA_PROTOINFO: proto = NFA_DATA(attr); - if (proto2str[proto->num_proto]) - printf("%s %d ", proto2str[proto->num_proto], proto->num_proto); - else - printf("unknown %d ", proto->num_proto); + if (proto2str[proto->num_proto]) { + fprintf(stdout, "%s %d ", proto2str[proto->num_proto], proto->num_proto); + h = findproto(proto2str[proto->num_proto]); + if (h && h->print_proto) + h->print_proto(&proto->proto); + } else + fprintf(stdout, "unknown %d ", proto->num_proto); break; case CTA_TIMEOUT: timeout = NFA_DATA(attr); - printf("timeout=%lu ", *timeout); + fprintf(stdout, "timeout=%lu ", *timeout); break; -/* case CTA_ID: - id = NFA_DATA(attr); - printf(" id:%lu ", *id); - break;*/ case CTA_MARK: mark = NFA_DATA(attr); - printf("mark=%lu ", *mark); + fprintf(stdout, "mark=%lu ", *mark); break; case CTA_COUNTERS: ctr = NFA_DATA(attr); - printf("orig_packets=%lu orig_bytes=%lu, " - "reply_packets=%lu reply_bytes=%lu ", + fprintf(stdout, "orig_packets=%llu orig_bytes=%llu, " + "reply_packets=%llu reply_bytes=%llu ", ctr->orig.packets, ctr->orig.bytes, ctr->reply.packets, ctr->reply.bytes); break; @@ -103,7 +119,7 @@ static int handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void *arg) DEBUGP("nfa->nfa_len: %d\n", attr->nfa_len); attr = NFA_NEXT(attr, attrlen); } - printf("\n"); + fprintf(stdout, "\n"); return 0; } @@ -154,55 +170,54 @@ static int event_handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, DEBUGP("size:%d\n", nlh->nlmsg_len); - printf("type: [%s] ", typemsg2str(type, nlh->nlmsg_flags)); + fprintf(stdout, "[%s] ", typemsg2str(type, nlh->nlmsg_flags)); while (NFA_OK(attr, attrlen)) { switch(attr->nfa_type) { case CTA_ORIG: orig = NFA_DATA(attr); - printf("src=%u.%u.%u.%u dst=%u.%u.%u.%u ", + fprintf(stdout, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ", NIPQUAD(orig->src.ip), NIPQUAD(orig->dst.ip)); h = findproto(proto2str[orig->dst.protonum]); - if (h && h->print) - h->print(orig); + if (h && h->print_tuple) + h->print_tuple(orig); break; case CTA_RPLY: reply = NFA_DATA(attr); - printf("src=%u.%u.%u.%u dst=%u.%u.%u.%u ", + fprintf(stdout, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ", NIPQUAD(reply->src.ip), NIPQUAD(reply->dst.ip)); h = findproto(proto2str[reply->dst.protonum]); - if (h && h->print) - h->print(reply); + if (h && h->print_tuple) + h->print_tuple(reply); break; case CTA_STATUS: status = NFA_DATA(attr); - printf("status:%u ", *status); + print_status(*status); break; case CTA_PROTOINFO: proto = NFA_DATA(attr); - if (proto2str[proto->num_proto]) - printf("%s %d ", proto2str[proto->num_proto], proto->num_proto); - else - printf("unknown %d ", proto->num_proto); + if (proto2str[proto->num_proto]) { + fprintf(stdout, "%s %d ", proto2str[proto->num_proto], proto->num_proto); + h = findproto(proto2str[proto->num_proto]); + if (h && h->print_proto) + h->print_proto(&proto->proto); + } else + fprintf(stdout, "unknown %d ", proto->num_proto); break; case CTA_TIMEOUT: timeout = NFA_DATA(attr); - printf("timeout:%lu ", *timeout); + fprintf(stdout, "timeout:%lu ", *timeout); break; -/* case CTA_ID: - id = NFA_DATA(attr); - printf(" id:%lu ", *id); - break;*/ case CTA_MARK: mark = NFA_DATA(attr); - printf("mark=%lu ", *mark); + fprintf(stdout, "mark=%lu ", *mark); break; case CTA_COUNTERS: ctr = NFA_DATA(attr); - printf("orig_packets=%lu orig_bytes=%lu, " - "reply_packets=%lu reply_bytes=%lu ", + fprintf(stdout, "orig_packets=%llu orig_bytes=%llu, " + "reply_packets=%llu reply_bytes=%llu ", ctr->orig.packets, ctr->orig.bytes, ctr->reply.packets, ctr->reply.bytes); break; @@ -211,7 +226,7 @@ static int event_handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, DEBUGP("nfa->nfa_len: %d\n", attr->nfa_len); attr = NFA_NEXT(attr, attrlen); } - printf("\n"); + fprintf(stdout, "\n"); return 0; } @@ -246,32 +261,32 @@ static int expect_handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void * switch(attr->nfa_type) { case CTA_EXP_TUPLE: exp = NFA_DATA(attr); - printf("src=%u.%u.%u.%u dst=%u.%u.%u.%u ", + fprintf(stdout, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ", NIPQUAD(exp->src.ip), NIPQUAD(exp->dst.ip)); h = findproto(proto2str[exp->dst.protonum]); - if (h && h->print) - h->print(exp); + if (h && h->print_tuple) + h->print_tuple(exp); break; case CTA_EXP_MASK: mask = NFA_DATA(attr); - printf("src=%u.%u.%u.%u dst=%u.%u.%u.%u ", + fprintf(stdout, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ", NIPQUAD(mask->src.ip), NIPQUAD(mask->dst.ip)); h = findproto(proto2str[mask->dst.protonum]); - if (h && h->print) - h->print(mask); + if (h && h->print_tuple) + h->print_tuple(mask); break; case CTA_EXP_TIMEOUT: timeout = NFA_DATA(attr); - printf("timeout:%lu ", *timeout); + fprintf(stdout, "timeout:%lu ", *timeout); break; } DEBUGP("nfa->nfa_type: %d\n", attr->nfa_type); DEBUGP("nfa->nfa_len: %d\n", attr->nfa_len); attr = NFA_NEXT(attr, attrlen); } - printf("\n"); + fprintf(stdout, "\n"); return 0; } @@ -288,13 +303,11 @@ int create_conntrack(struct ip_conntrack_tuple *orig, cta.num_proto = orig->dst.protonum; memcpy(&cta.proto, proto, sizeof(*proto)); - if (ctnl_open(&cth, 0) < 0) { - printf("error\n"); - exit(0); - } + if (ctnl_open(&cth, 0) < 0) + return -1; /* FIXME: please unify returns values... */ - if (ctnl_new_conntrack(&cth, orig, reply, timeout, proto, status) < 0) + if (ctnl_new_conntrack(&cth, orig, reply, timeout, &cta, status) < 0) return -1; if (ctnl_close(&cth) < 0) @@ -304,8 +317,7 @@ int create_conntrack(struct ip_conntrack_tuple *orig, } int delete_conntrack(struct ip_conntrack_tuple *tuple, - enum ctattr_type_t t, - unsigned long id) + enum ctattr_type_t t) { struct nfattr *cda[CTA_MAX]; struct ctnl_handle cth; @@ -314,7 +326,7 @@ int delete_conntrack(struct ip_conntrack_tuple *tuple, return -1; /* FIXME: please unify returns values... */ - if (ctnl_del_conntrack(&cth, tuple, t, id) < 0) + if (ctnl_del_conntrack(&cth, tuple, t) < 0) return -1; if (ctnl_close(&cth) < 0) @@ -341,7 +353,7 @@ int get_conntrack(struct ip_conntrack_tuple *tuple, ctnl_register_handler(&cth, &h); /* FIXME!!!! get_conntrack_handler returns -100 */ - if (ctnl_get_conntrack(&cth, tuple, t, id) != -100) + if (ctnl_get_conntrack(&cth, tuple, t) != -100) return -1; if (ctnl_close(&cth) < 0) @@ -413,6 +425,10 @@ struct ctproto_handler *findproto(char *name) if (!name) return handler; + lib_dir = getenv("CONNTRACK_LIB_DIR"); + if (!lib_dir) + lib_dir = CONNTRACK_LIB_DIR; + list_for_each(i, &proto_list) { cur = (struct ctproto_handler *) i; if (strcmp(cur->name, name) == 0) { @@ -422,13 +438,13 @@ struct ctproto_handler *findproto(char *name) } if (!handler) { - char path[sizeof("extensions/libct_proto_.so") - + strlen(name)]; - sprintf(path, "extensions/libct_proto_%s.so", name); + char path[sizeof("libct_proto_.so") + + strlen(name) + strlen(lib_dir)]; + sprintf(path, "%s/libct_proto_%s.so", lib_dir, name); if (dlopen(path, RTLD_NOW)) handler = findproto(name); -/* else - fprintf (stderr, "%s\n", dlerror());*/ + else + DEBUGP(stderr, "%s\n", dlerror()); } return handler; @@ -466,16 +482,44 @@ int dump_expect_list() return 0; } -int set_dump_mask(unsigned int mask) +int set_mask(unsigned int mask, int type) { struct ctnl_handle cth; + enum ctattr_type_t cta_type; + + switch(type) { + case 0: + cta_type = CTA_DUMPMASK; + break; + case 1: + cta_type = CTA_EVENTMASK; + break; + default: + return -1; + } if (ctnl_open(&cth, 0) < 0) return -1; - if (ctnl_set_dumpmask(&cth, mask) < 0) + if (ctnl_set_mask(&cth, mask, cta_type) < 0) + return -1; + + if (ctnl_close(&cth) < 0) return -1; + + return 0; +} + +int flush_conntrack() +{ + struct ctnl_handle cth; + if (ctnl_open(&cth, 0) < 0) + return -1; + + if (ctnl_flush_conntrack(&cth) < 0) + return -1; + if (ctnl_close(&cth) < 0) return -1; diff --git a/test.sh b/test.sh new file mode 100644 index 0000000..dd67a83 --- /dev/null +++ b/test.sh @@ -0,0 +1,67 @@ +CONNTRACK=conntrack + +SRC=1.1.1.1 +DST=2.2.2.2 +SPORT=1980 +DPORT=2005 + +case $1 in + dump) + # Setting dump mask + echo "dump mask set to TUPLE" + $CONNTRACK -A -m TUPLE + $CONNTRACK -L + echo "Press any key to continue..." + read + echo "dump mask set to TUPLE,COUNTERS" + $CONNTRACK -A -m TUPLE,COUNTERS + $CONNTRACK -L + echo "Press any key to continue..." + read + echo "dump mask set to ALL" + $CONNTRACK -A -m ALL + $CONNTRACK -L + echo "Press any key to continue..." + read + ;; + new) + echo "creating a new conntrack" + $CONNTRACK -I --orig-src $SRC --orig-dst $DST \ + --reply-src $DST --reply-dst $SRC -p tcp \ + --orig-port-src $SPORT --orig-port-dst $DPORT \ + --reply-port-src $DPORT --reply-port-dst $SPORT \ + --state LISTEN -u SEEN_REPLY -t 50 + ;; + + change) + echo "change a conntrack" + $CONNTRACK -I --orig-src $SRC --orig-dst $DST \ + --reply-src $DST --reply-dst $SRC -p tcp \ + --orig-port-src $SPORT --orig-port-dst $DPORT \ + --reply-port-src $DPORT --reply-port-dst $SPORT \ + --state TIME_WAIT -u ASSURED -t 500 + ;; + delete) + # 66.111.58.52 dst=85.136.125.64 sport=22 dport=60239 + $CONNTRACK -D conntrack --orig-src 66.111.58.1 \ + --orig-dst 85.136.125.64 -p tcp --orig-port-src 22 \ + --orig-port-dst 60239 + ;; + output) + proc=$(cat /proc/net/ip_conntrack | wc -l) + netl=$($CONNTRACK -L | wc -l) + count=$(cat /proc/sys/net/ipv4/netfilter/ip_conntrack_count) + if [ $proc -ne $netl ]; then + echo "proc is $proc and netl is $netl and count is $count" + else + if [ $proc -ne $count ]; then + echo "proc is $proc and netl is $netl and count is $count" + else + echo "now $proc" + fi + fi + ;; + *) + echo "Usage: $0 [dump|new|change|delete|output]" + ;; +esac -- cgit v1.2.3 From b48c2c0e44ea8e2e84ee84a313f5ab4a1add0dfd 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: Wed, 11 May 2005 23:55:16 +0000 Subject: Simplify event_handler --- src/libct.c | 86 +------------------------------------------------------------ 1 file changed, 1 insertion(+), 85 deletions(-) (limited to 'src') diff --git a/src/libct.c b/src/libct.c index d44b920..cb0fabb 100644 --- a/src/libct.c +++ b/src/libct.c @@ -142,93 +142,9 @@ static char *typemsg2str(type, flags) static int event_handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void *arg) { - struct nfgenmsg *nfmsg; - struct nfattr *nfa; - int min_len = 0; - struct ctproto_handler *h = NULL; int type = NFNL_MSG_TYPE(nlh->nlmsg_type); - struct nfattr *attr = NFM_NFA(NLMSG_DATA(nlh)); - int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); - - struct ip_conntrack_tuple *orig, *reply; - struct cta_counters *ctr; - unsigned long *status, *timeout, *mark; - struct cta_proto *proto; - unsigned long *id; - - DEBUGP("netlink header\n"); - DEBUGP("len: %d type: %d flags: %d seq: %d pid: %d\n", - nlh->nlmsg_len, nlh->nlmsg_type, nlh->nlmsg_flags, - nlh->nlmsg_seq, nlh->nlmsg_pid); - - nfmsg = NLMSG_DATA(nlh); - DEBUGP("nfmsg->nfgen_family: %d\n", nfmsg->nfgen_family); - - min_len = sizeof(struct nfgenmsg); - if (nlh->nlmsg_len < min_len) - return -EINVAL; - - DEBUGP("size:%d\n", nlh->nlmsg_len); - fprintf(stdout, "[%s] ", typemsg2str(type, nlh->nlmsg_flags)); - - while (NFA_OK(attr, attrlen)) { - switch(attr->nfa_type) { - case CTA_ORIG: - orig = NFA_DATA(attr); - fprintf(stdout, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ", - NIPQUAD(orig->src.ip), - NIPQUAD(orig->dst.ip)); - h = findproto(proto2str[orig->dst.protonum]); - if (h && h->print_tuple) - h->print_tuple(orig); - break; - case CTA_RPLY: - reply = NFA_DATA(attr); - fprintf(stdout, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ", - NIPQUAD(reply->src.ip), - NIPQUAD(reply->dst.ip)); - h = findproto(proto2str[reply->dst.protonum]); - if (h && h->print_tuple) - h->print_tuple(reply); - break; - case CTA_STATUS: - status = NFA_DATA(attr); - print_status(*status); - break; - case CTA_PROTOINFO: - proto = NFA_DATA(attr); - if (proto2str[proto->num_proto]) { - fprintf(stdout, "%s %d ", proto2str[proto->num_proto], proto->num_proto); - h = findproto(proto2str[proto->num_proto]); - if (h && h->print_proto) - h->print_proto(&proto->proto); - } else - fprintf(stdout, "unknown %d ", proto->num_proto); - break; - case CTA_TIMEOUT: - timeout = NFA_DATA(attr); - fprintf(stdout, "timeout:%lu ", *timeout); - break; - case CTA_MARK: - mark = NFA_DATA(attr); - fprintf(stdout, "mark=%lu ", *mark); - break; - case CTA_COUNTERS: - ctr = NFA_DATA(attr); - fprintf(stdout, "orig_packets=%llu orig_bytes=%llu, " - "reply_packets=%llu reply_bytes=%llu ", - ctr->orig.packets, ctr->orig.bytes, - ctr->reply.packets, ctr->reply.bytes); - break; - } - DEBUGP("nfa->nfa_type: %d\n", attr->nfa_type); - DEBUGP("nfa->nfa_len: %d\n", attr->nfa_len); - attr = NFA_NEXT(attr, attrlen); - } - fprintf(stdout, "\n"); - - return 0; + return handler(sock, nlh, arg); } static int expect_handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void *arg) -- cgit v1.2.3 From a75bb977ff16c9f3b3bdccdcd4173e9ef033463f 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, 15 May 2005 14:23:16 +0000 Subject: Completed some stuff related to protocol helpers: o final_check o help o ICMP support --- extensions/Makefile.am | 3 ++- extensions/libct_proto_tcp.c | 25 +++++++++++++++++++++++++ extensions/libct_proto_udp.c | 24 ++++++++++++++++++++++++ include/libct_proto.h | 2 ++ src/conntrack.c | 20 ++++++++++++++++++-- test.sh | 7 ++++++- 6 files changed, 77 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/extensions/Makefile.am b/extensions/Makefile.am index ae78346..ab29a6d 100644 --- a/extensions/Makefile.am +++ b/extensions/Makefile.am @@ -8,7 +8,8 @@ INCLUDES=-I../include -I/lib/modules/$(shell (uname -r))/build/include CFLAGS=-fPIC -Wall LIBS= -lib_LTLIBRARIES = libct_proto_tcp.la libct_proto_udp.la +lib_LTLIBRARIES = libct_proto_tcp.la libct_proto_udp.la libct_proto_icmp.la libct_proto_tcp_la_SOURCES = libct_proto_tcp.c libct_proto_udp_la_SOURCES = libct_proto_udp.c +libct_proto_icmp_la_SOURCES = libct_proto_icmp.c diff --git a/extensions/libct_proto_tcp.c b/extensions/libct_proto_tcp.c index 58005b0..a2243dc 100644 --- a/extensions/libct_proto_tcp.c +++ b/extensions/libct_proto_tcp.c @@ -54,6 +54,15 @@ static const char *states[] = { "LISTEN" }; +void help() +{ + fprintf(stdout, "--orig-port-src original source port\n"); + fprintf(stdout, "--orig-port-dst original destination port\n"); + fprintf(stdout, "--reply-port-src reply source port\n"); + fprintf(stdout, "--reply-port-dst reply destination port\n"); + fprintf(stdout, "--state TCP state, fe. ESTABLISHED\n"); +} + int parse(char c, char *argv[], struct ip_conntrack_tuple *orig, struct ip_conntrack_tuple *reply, @@ -104,6 +113,20 @@ int parse(char c, char *argv[], return 1; } +int final_check(unsigned int flags) +{ + if (!(flags & ORIG_SPORT)) + return 0; + else if (!(flags & ORIG_DPORT)) + return 0; + else if (!(flags & REPL_SPORT)) + return 0; + else if (!(flags & REPL_DPORT)) + return 0; + + return 1; +} + void print_tuple(struct ip_conntrack_tuple *t) { fprintf(stdout, "sport=%d dport=%d ", ntohs(t->src.u.tcp.port), @@ -121,6 +144,8 @@ static struct ctproto_handler tcp = { .parse = parse, .print_tuple = print_tuple, .print_proto = print_proto, + .final_check = final_check, + .help = help, .opts = opts }; diff --git a/extensions/libct_proto_udp.c b/extensions/libct_proto_udp.c index 5675a05..8e20bd5 100644 --- a/extensions/libct_proto_udp.c +++ b/extensions/libct_proto_udp.c @@ -37,6 +37,14 @@ enum udp_param_flags { REPL_DPORT = (1 << REPL_DPORT_BIT), }; +void help() +{ + fprintf(stdout, "--orig-port-src original source port\n"); + fprintf(stdout, "--orig-port-dst original destination port\n"); + fprintf(stdout, "--reply-port-src reply source port\n"); + fprintf(stdout, "--reply-port-dst reply destination port\n"); +} + int parse(char c, char *argv[], struct ip_conntrack_tuple *orig, struct ip_conntrack_tuple *reply, @@ -72,6 +80,20 @@ int parse(char c, char *argv[], return 1; } +int final_check(unsigned int flags) +{ + if (!(flags & ORIG_SPORT)) + return 0; + else if (!(flags & ORIG_DPORT)) + return 0; + else if (!(flags & REPL_SPORT)) + return 0; + else if (!(flags & REPL_DPORT)) + return 0; + + return 1; +} + void print_tuple(struct ip_conntrack_tuple *t) { fprintf(stdout, "sport=%d dport=%d ", ntohs(t->src.u.udp.port), @@ -83,6 +105,8 @@ static struct ctproto_handler udp = { .protonum = 17, .parse = parse, .print_tuple = print_tuple, + .final_check = final_check, + .help = help, .opts = opts }; diff --git a/include/libct_proto.h b/include/libct_proto.h index de632b2..6df03e7 100644 --- a/include/libct_proto.h +++ b/include/libct_proto.h @@ -24,6 +24,8 @@ struct ctproto_handler { int (*final_check)(unsigned int flags); + void (*help)(); + struct option *opts; unsigned int option_offset; diff --git a/src/conntrack.c b/src/conntrack.c index ed97a86..676049e 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -46,7 +46,7 @@ #include "libct_proto.h" #define PROGNAME "conntrack" -#define VERSION "0.50" +#define VERSION "0.60" #if 0 #define DEBUGP printf @@ -182,7 +182,7 @@ static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = /*EVENT*/ {'x','x','x','x','x','x','x','x','x',' ','x'}, /*ACTION*/ {'x','x','x','x','x','x','x','x',' ','x',' '}, /*VERSION*/ {'x','x','x','x','x','x','x','x','x','x','x'}, -/*HELP*/ {'x','x','x','x','x','x','x','x','x','x','x'}, +/*HELP*/ {'x','x','x','x',' ','x','x','x','x','x','x'}, }; /* FIXME: hardcoded!, this must be defined during compilation time */ @@ -203,6 +203,13 @@ enum exittype { VERSION_PROBLEM }; +void extension_help(struct ctproto_handler *h) +{ + fprintf(stdout, "\n"); + fprintf(stdout, "Proto `%s' help:\n", h->name); + h->help(); +} + void exit_tryhelp(int status) { @@ -624,6 +631,13 @@ int main(int argc, char *argv[]) generic_opt_check(command, options); + if (!(command & CT_HELP) + && h && h->final_check && !h->final_check(extra_flags)) { + usage(argv[0]); + extension_help(h); + exit_error(PARAMETER_PROBLEM, "Missing protocol arguments!\n"); + } + while (retry > 0) { retry--; switch(command) { @@ -697,6 +711,8 @@ int main(int argc, char *argv[]) break; case CT_HELP: usage(argv[0]); + if (options & CT_OPT_PROTO) + extension_help(h); break; default: usage(argv[0]); diff --git a/test.sh b/test.sh index dd67a83..379f950 100644 --- a/test.sh +++ b/test.sh @@ -32,7 +32,12 @@ case $1 in --reply-port-src $DPORT --reply-port-dst $SPORT \ --state LISTEN -u SEEN_REPLY -t 50 ;; - + get) + echo "getting a conntrack" + $CONNTRACK -G --orig-src $SRC --orig-dst $DST \ + -p tcp --orig-port-src $SPORT --orig-port-dst $DPORT \ + --reply-port-src $DPORT --reply-port-dst $SPORT + ;; change) echo "change a conntrack" $CONNTRACK -I --orig-src $SRC --orig-dst $DST \ -- cgit v1.2.3 From 5c14f27ef46e65317ca4da8657f7c1a1a91da4c4 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: Tue, 17 May 2005 11:38:37 +0000 Subject: o Added descriptive error messages. o Fix wrong flags check in [tcp|udp] proto helpers. --- ChangeLog | 10 +++++ TODO | 13 +++--- extensions/libct_proto_tcp.c | 14 +++--- extensions/libct_proto_udp.c | 14 +++--- src/conntrack.c | 37 +++++++++++++-- src/libct.c | 105 +++++++++++++++++++++++-------------------- test.sh | 8 ++-- 7 files changed, 121 insertions(+), 80 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 147f8d6..a1c11e3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -21,3 +21,13 @@ o Autoconf stuff for conntrack + some pablo's modifications. o Fixed packet counters formatting (use %llu instead of %lu) + +2005-05-16 + + o Implemented ICMP proto helper + o Added help() and final_check() functions for proto helpers. + +2005-05-17 + + o Added descriptive error messages. + o Fix wrong flags check in [tcp|udp] proto helpers. diff --git a/TODO b/TODO index 4b1654f..f94fb9c 100644 --- a/TODO +++ b/TODO @@ -1,12 +1,15 @@ +X = done +N = forget it + user space tool --------------- [X] Proper Makefiles [X] Modify Event Display (-E conntrack). Extensions: -[ ] ICMP library +[X] ICMP library [X] finish TCP: protocol specific stuff: --state, etc... -[ ] finish UDP, TCP, ICMP: help +[X] finish UDP, TCP, ICMP: help nfnetlink_conntrack: -------------------- @@ -15,11 +18,11 @@ Now: [X] Error handling (nlerrmsg) [X] Use id's to identify conntracks [ ] Split NEW and CHANGE -[ ] Split DUMP and GET -[ ] Kill Change API. Move locks to ip_conntrack_[protocol|helper]. +[N] Split DUMP and GET +[N] Kill Change API. Move locks to ip_conntrack_[protocol|helper]. [X] implement conntrack FLUSH Later: -[ ] convert CTA_SOMETHING-1 to CTA_SOMETHING, annoying! +[N] convert CTA_SOMETHING-1 to CTA_SOMETHING, annoying! [ ] NAT handlings [ ] Expectations diff --git a/extensions/libct_proto_tcp.c b/extensions/libct_proto_tcp.c index a2243dc..4cddf53 100644 --- a/extensions/libct_proto_tcp.c +++ b/extensions/libct_proto_tcp.c @@ -115,16 +115,12 @@ int parse(char c, char *argv[], int final_check(unsigned int flags) { - if (!(flags & ORIG_SPORT)) - return 0; - else if (!(flags & ORIG_DPORT)) - return 0; - else if (!(flags & REPL_SPORT)) - return 0; - else if (!(flags & REPL_DPORT)) - return 0; + if ((flags & ORIG_SPORT) && (flags & ORIG_DPORT)) + return 1; + else if ((flags & REPL_SPORT) && (flags & REPL_DPORT)) + return 1; - return 1; + return 0; } void print_tuple(struct ip_conntrack_tuple *t) diff --git a/extensions/libct_proto_udp.c b/extensions/libct_proto_udp.c index 8e20bd5..0088cc5 100644 --- a/extensions/libct_proto_udp.c +++ b/extensions/libct_proto_udp.c @@ -82,16 +82,12 @@ int parse(char c, char *argv[], int final_check(unsigned int flags) { - if (!(flags & ORIG_SPORT)) - return 0; - else if (!(flags & ORIG_DPORT)) - return 0; - else if (!(flags & REPL_SPORT)) - return 0; - else if (!(flags & REPL_DPORT)) - return 0; + if ((flags & ORIG_SPORT) && (flags & ORIG_DPORT)) + return 1; + else if ((flags & REPL_SPORT) && (flags & REPL_DPORT)) + return 1; - return 1; + return 0; } void print_tuple(struct ip_conntrack_tuple *t) diff --git a/src/conntrack.c b/src/conntrack.c index 676049e..11a6b54 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include "libctnetlink.h" @@ -46,7 +47,7 @@ #include "libct_proto.h" #define PROGNAME "conntrack" -#define VERSION "0.60" +#define VERSION "0.62" #if 0 #define DEBUGP printf @@ -299,6 +300,36 @@ merge_options(struct option *oldopts, const struct option *newopts, return merge; } +/* From linux/errno.h */ +#define ENOTSUPP 524 /* Operation is not supported */ + +/* Translates errno numbers into more human-readable form than strerror. */ +const char * +err2str(int err, enum action command) +{ + unsigned int i; + struct table_struct { + enum action act; + int err; + const char *message; + } table [] = + { { CT_LIST, -ENOTSUPP, "function not implemented" }, + { 0xFFFF, -EINVAL, "invalid parameters" }, + { CT_CREATE|CT_GET|CT_DELETE, -ENOENT, + "such conntrack doesn't exist" }, + { CT_CREATE|CT_GET, -ENOMEM, "not enough memory" }, + { CT_GET, -EAFNOSUPPORT, "protocol not supported" }, + { CT_CREATE, -ETIME, "conntrack has expired" }, + }; + + for (i = 0; i < sizeof(table)/sizeof(struct table_struct); i++) { + if ((table[i].act & command) && table[i].err == err) + return table[i].message; + } + + return strerror(err); +} + static void dump_tuple(struct ip_conntrack_tuple *tp) { fprintf(stdout, "tuple %p: %u %u.%u.%u.%u:%hu -> %u.%u.%u.%u:%hu\n", @@ -732,6 +763,6 @@ int main(int argc, char *argv[]) global_option_offset = 0; } - if (res == -1) - fprintf(stderr, "Operation failed\n"); + if (res < 0) + fprintf(stderr, "Operation failed: %s\n", err2str(res, command)); } diff --git a/src/libct.c b/src/libct.c index cb0fabb..b40b818 100644 --- a/src/libct.c +++ b/src/libct.c @@ -216,18 +216,19 @@ int create_conntrack(struct ip_conntrack_tuple *orig, struct cta_proto cta; struct nfattr *cda[CTA_MAX]; struct ctnl_handle cth; + int ret; cta.num_proto = orig->dst.protonum; memcpy(&cta.proto, proto, sizeof(*proto)); - if (ctnl_open(&cth, 0) < 0) - return -1; + if ((ret = ctnl_open(&cth, 0)) < 0) + return ret; - /* FIXME: please unify returns values... */ - if (ctnl_new_conntrack(&cth, orig, reply, timeout, &cta, status) < 0) - return -1; + if ((ret = ctnl_new_conntrack(&cth, orig, reply, timeout, &cta, + status)) < 0) + return ret; - if (ctnl_close(&cth) < 0) - return -1; + if ((ret = ctnl_close(&cth)) < 0) + return ret; return 0; } @@ -237,16 +238,16 @@ int delete_conntrack(struct ip_conntrack_tuple *tuple, { struct nfattr *cda[CTA_MAX]; struct ctnl_handle cth; + int ret; - if (ctnl_open(&cth, 0) < 0) - return -1; + if ((ret = ctnl_open(&cth, 0)) < 0) + return ret; - /* FIXME: please unify returns values... */ - if (ctnl_del_conntrack(&cth, tuple, t) < 0) - return -1; + if ((ret = ctnl_del_conntrack(&cth, tuple, t)) < 0) + return ret; - if (ctnl_close(&cth) < 0) - return -1; + if ((ret = ctnl_close(&cth)) < 0) + return ret; return 0; } @@ -262,18 +263,19 @@ int get_conntrack(struct ip_conntrack_tuple *tuple, .type = 0, .handler = handler }; + int ret; - if (ctnl_open(&cth, 0) < 0) - return -1; + if ((ret = ctnl_open(&cth, 0)) < 0) + return ret; ctnl_register_handler(&cth, &h); /* FIXME!!!! get_conntrack_handler returns -100 */ - if (ctnl_get_conntrack(&cth, tuple, t) != -100) - return -1; + if ((ret = ctnl_get_conntrack(&cth, tuple, t)) != -100) + return ret; - if (ctnl_close(&cth) < 0) - return -1; + if ((ret = ctnl_close(&cth)) < 0) + return ret; return 0; } @@ -287,8 +289,8 @@ int dump_conntrack_table(int zero) .handler = handler }; - if (ctnl_open(&cth, 0) < 0) - return -1; + if ((ret = ctnl_open(&cth, 0)) < 0) + return ret; ctnl_register_handler(&cth, &h); @@ -298,10 +300,10 @@ int dump_conntrack_table(int zero) ret = ctnl_list_conntrack(&cth, AF_INET); if (ret != -100) - return -1; + return ret; - if (ctnl_close(&cth) < 0) - return -1; + if ((ret = ctnl_close(&cth)) < 0) + return ret; return 0; } @@ -317,17 +319,18 @@ int event_conntrack(unsigned int event_mask) .type = 2, /* destroy */ .handler = event_handler }; + int ret; - if (ctnl_open(&cth, event_mask) < 0) - return -1; + if ((ret = ctnl_open(&cth, event_mask)) < 0) + return ret; ctnl_register_handler(&cth, &hnew); ctnl_register_handler(&cth, &hdestroy); - if (ctnl_event_conntrack(&cth, AF_INET) < 0) - return -1; + if ((ret = ctnl_event_conntrack(&cth, AF_INET)) < 0) + return ret; - if (ctnl_close(&cth) < 0) - return -1; + if ((ret = ctnl_close(&cth)) < 0) + return ret; return 0; } @@ -383,17 +386,18 @@ int dump_expect_list() .type = 0, /* Hm... really? */ .handler = expect_handler }; + int ret; - if (ctnl_open(&cth, 0) < 0) - return -1; + if ((ret = ctnl_open(&cth, 0)) < 0) + return ret; ctnl_register_handler(&cth, &h); - if (ctnl_list_expect(&cth, AF_INET) != -100) - return -1; + if ((ret = ctnl_list_expect(&cth, AF_INET)) != -100) + return ret; - if (ctnl_close(&cth) < 0) - return -1; + if ((ret = ctnl_close(&cth)) < 0) + return ret; return 0; } @@ -402,6 +406,7 @@ int set_mask(unsigned int mask, int type) { struct ctnl_handle cth; enum ctattr_type_t cta_type; + int ret; switch(type) { case 0: @@ -411,17 +416,18 @@ int set_mask(unsigned int mask, int type) cta_type = CTA_EVENTMASK; break; default: + /* Shouldn't happen */ return -1; } - if (ctnl_open(&cth, 0) < 0) - return -1; + if ((ret = ctnl_open(&cth, 0)) < 0) + return ret; - if (ctnl_set_mask(&cth, mask, cta_type) < 0) - return -1; + if ((ret = ctnl_set_mask(&cth, mask, cta_type)) < 0) + return ret; - if (ctnl_close(&cth) < 0) - return -1; + if ((ret = ctnl_close(&cth)) < 0) + return ret; return 0; } @@ -429,15 +435,16 @@ int set_mask(unsigned int mask, int type) int flush_conntrack() { struct ctnl_handle cth; + int ret; - if (ctnl_open(&cth, 0) < 0) - return -1; + if ((ret = ctnl_open(&cth, 0)) < 0) + return ret; - if (ctnl_flush_conntrack(&cth) < 0) - return -1; + if ((ret = ctnl_flush_conntrack(&cth)) < 0) + return ret; - if (ctnl_close(&cth) < 0) - return -1; + if ((ret = ctnl_close(&cth)) < 0) + return ret; return 0; } diff --git a/test.sh b/test.sh index 379f950..5999a8f 100644 --- a/test.sh +++ b/test.sh @@ -44,13 +44,11 @@ case $1 in --reply-src $DST --reply-dst $SRC -p tcp \ --orig-port-src $SPORT --orig-port-dst $DPORT \ --reply-port-src $DPORT --reply-port-dst $SPORT \ - --state TIME_WAIT -u ASSURED -t 500 + --state TIME_WAIT -u ASSURED,SEEN_REPLY -t 500 ;; delete) - # 66.111.58.52 dst=85.136.125.64 sport=22 dport=60239 - $CONNTRACK -D conntrack --orig-src 66.111.58.1 \ - --orig-dst 85.136.125.64 -p tcp --orig-port-src 22 \ - --orig-port-dst 60239 + $CONNTRACK -D --orig-src $SRC --orig-dst $DST \ + -p tcp --orig-port-src $SPORT --orig-port-dst $DPORT ;; output) proc=$(cat /proc/net/ip_conntrack | wc -l) -- cgit v1.2.3 From 5fad15147b25cd6bbac5ef7ca8d6c3d885d42412 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, 22 May 2005 17:23:37 +0000 Subject: Fix wrong handler number in expectation dumping --- src/libct.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/libct.c b/src/libct.c index b40b818..d40c7f1 100644 --- a/src/libct.c +++ b/src/libct.c @@ -383,7 +383,7 @@ int dump_expect_list() { struct ctnl_handle cth; struct ctnl_msg_handler h = { - .type = 0, /* Hm... really? */ + .type = 5, /* Hm... really? */ .handler = expect_handler }; int ret; -- cgit v1.2.3 From e8c0b55fc1aac2238419cf6119930559d5c3119b Mon Sep 17 00:00:00 2001 From: "/C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=laforge/emailAddress=laforge@netfilter.org" Date: Fri, 24 Jun 2005 16:28:24 +0000 Subject: o Fixed syntax error (tab/space issue) in help message o Fixed getopt handling on big endian machines o Fixed possible future read-over-end-of-array in TCP extension o Add manpage o Add missing space at output of libct_proto_icmp.c o Add status bits that were introduced in 2.6.11 o Add SCTP extension o Add support for expect creation o Bump version number to 0.63 --- AUTHORS | 1 + ChangeLog | 11 +++ configure.in | 2 +- conntrack.8 | 152 ++++++++++++++++++++++++++++++++++++++ extensions/Makefile.am | 4 +- extensions/libct_proto_icmp.c | 2 +- extensions/libct_proto_icmp.man | 10 +++ extensions/libct_proto_sctp.c | 160 ++++++++++++++++++++++++++++++++++++++++ extensions/libct_proto_tcp.c | 18 +++-- extensions/libct_proto_tcp.man | 16 ++++ extensions/libct_proto_udp.man | 13 ++++ src/conntrack.c | 86 +++++++++++++++------ src/libct.c | 25 ++++++- 13 files changed, 468 insertions(+), 32 deletions(-) create mode 100644 conntrack.8 create mode 100644 extensions/libct_proto_icmp.man create mode 100644 extensions/libct_proto_sctp.c create mode 100644 extensions/libct_proto_tcp.man create mode 100644 extensions/libct_proto_udp.man (limited to 'src') diff --git a/AUTHORS b/AUTHORS index 2cc79e0..d1cb6fa 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1 +1,2 @@ Pablo Neira Ayuso +Harald Welte diff --git a/ChangeLog b/ChangeLog index a1c11e3..688b0cc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2005-05-23 + + o Fixed syntax error (tab/space issue) in help message + o Fixed getopt handling on big endian machines + o Fixed possible future read-over-end-of-array in TCP extension + o Add manpage + o Add missing space at output of libct_proto_icmp.c + o Add status bits that were introduced in 2.6.11 + o Add SCTP extension + o Add support for expect creation + o Bump version number to 0.63 2005-04-25 o Added support for mask based event dumping diff --git a/configure.in b/configure.in index 468e759..efdacf1 100644 --- a/configure.in +++ b/configure.in @@ -2,7 +2,7 @@ AC_INIT AC_CANONICAL_SYSTEM -AM_INIT_AUTOMAKE(conntrack, 0.50) +AM_INIT_AUTOMAKE(conntrack, 0.63) AM_CONFIG_HEADER(config.h) AC_PROG_CC diff --git a/conntrack.8 b/conntrack.8 new file mode 100644 index 0000000..5ba8494 --- /dev/null +++ b/conntrack.8 @@ -0,0 +1,152 @@ +.TH CONNTRACK 8 "Jun 23, 2005" "" "" + +.\" Man page written by Harald Welte . diff --git a/extensions/Makefile.am b/extensions/Makefile.am index ab29a6d..ecd3a91 100644 --- a/extensions/Makefile.am +++ b/extensions/Makefile.am @@ -8,8 +8,10 @@ INCLUDES=-I../include -I/lib/modules/$(shell (uname -r))/build/include CFLAGS=-fPIC -Wall LIBS= -lib_LTLIBRARIES = libct_proto_tcp.la libct_proto_udp.la libct_proto_icmp.la +lib_LTLIBRARIES = libct_proto_tcp.la libct_proto_udp.la libct_proto_icmp.la \ + libct_proto_sctp.la libct_proto_tcp_la_SOURCES = libct_proto_tcp.c libct_proto_udp_la_SOURCES = libct_proto_udp.c libct_proto_icmp_la_SOURCES = libct_proto_icmp.c +libct_proto_sctp_la_SOURCES = libct_proto_sctp.c diff --git a/extensions/libct_proto_icmp.c b/extensions/libct_proto_icmp.c index 43ffa30..6a2db92 100644 --- a/extensions/libct_proto_icmp.c +++ b/extensions/libct_proto_icmp.c @@ -81,7 +81,7 @@ int final_check(unsigned int flags) void print_tuple(struct ip_conntrack_tuple *t) { - fprintf(stdout, "type=%d code=%d id=%d", t->dst.u.icmp.type, + fprintf(stdout, "type=%d code=%d id=%d ", t->dst.u.icmp.type, t->dst.u.icmp.code, t->src.u.icmp.id); } diff --git a/extensions/libct_proto_icmp.man b/extensions/libct_proto_icmp.man new file mode 100644 index 0000000..3b860d0 --- /dev/null +++ b/extensions/libct_proto_icmp.man @@ -0,0 +1,10 @@ +This module matches on ICMP-specific fields. +.TP +.BI "--icmp-type " "TYPE" +ICMP Type. Has to be specified numerically. +.TP +.BI "--icmp-code " "CODE" +ICMP Code. Has to be specified numerically. +.TP +.BI "--icmp-id " "ID" +ICMP Id. Has to be specified numerically. diff --git a/extensions/libct_proto_sctp.c b/extensions/libct_proto_sctp.c new file mode 100644 index 0000000..b84c2ba --- /dev/null +++ b/extensions/libct_proto_sctp.c @@ -0,0 +1,160 @@ +/* + * (C) 2005 by Harald Welte + * + * 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 +#include +#include +#include +#include /* For htons */ +#include +#include +#include "libct_proto.h" + +static struct option opts[] = { + {"orig-port-src", 1, 0, '1'}, + {"orig-port-dst", 1, 0, '2'}, + {"reply-port-src", 1, 0, '3'}, + {"reply-port-dst", 1, 0, '4'}, + {"state", 1, 0, '5'}, + {0, 0, 0, 0} +}; + +enum sctp_param_flags { + ORIG_SPORT_BIT = 0, + ORIG_SPORT = (1 << ORIG_SPORT_BIT), + + ORIG_DPORT_BIT = 1, + ORIG_DPORT = (1 << ORIG_DPORT_BIT), + + REPL_SPORT_BIT = 2, + REPL_SPORT = (1 << REPL_SPORT_BIT), + + REPL_DPORT_BIT = 3, + REPL_DPORT = (1 << REPL_DPORT_BIT), + + STATE_BIT = 4, + STATE = (1 << STATE_BIT) +}; + +static const char *states[] = { + "NONE", + "CLOSED", + "COOKIE_WAIT", + "COOKIE_ECHOED", + "ESTABLISHED", + "SHUTDOWN_SENT", + "SHUTDOWN_RECV", + "SHUTDOWN_ACK_SENT", +}; + +static void help() +{ + fprintf(stdout, "--orig-port-src original source port\n"); + fprintf(stdout, "--orig-port-dst original destination port\n"); + fprintf(stdout, "--reply-port-src reply source port\n"); + fprintf(stdout, "--reply-port-dst reply destination port\n"); + fprintf(stdout, "--state SCTP state, eg. ESTABLISHED\n"); +} + +static int parse(char c, char *argv[], + struct ip_conntrack_tuple *orig, + struct ip_conntrack_tuple *reply, + union ip_conntrack_proto *proto, + unsigned int *flags) +{ + switch(c) { + case '1': + if (optarg) { + orig->src.u.sctp.port = htons(atoi(optarg)); + *flags |= ORIG_SPORT; + } + break; + case '2': + if (optarg) { + orig->dst.u.sctp.port = htons(atoi(optarg)); + *flags |= ORIG_DPORT; + } + break; + case '3': + if (optarg) { + reply->src.u.sctp.port = htons(atoi(optarg)); + *flags |= REPL_SPORT; + } + break; + case '4': + if (optarg) { + reply->dst.u.sctp.port = htons(atoi(optarg)); + *flags |= REPL_DPORT; + } + break; + case '5': + if (optarg) { + int i; + for (i=0; i<10; i++) { + if (strcmp(optarg, states[i]) == 0) { + proto->sctp.state = i; + break; + } + } + if (i == 10) { + printf("doh?\n"); + return 0; + } + } + break; + } + return 1; +} + +static int final_check(unsigned int flags) +{ + if ((flags & ORIG_SPORT) && (flags & ORIG_DPORT)) + return 1; + else if ((flags & REPL_SPORT) && (flags & REPL_DPORT)) + return 1; + + return 0; +} + +static void print_tuple(struct ip_conntrack_tuple *t) +{ + fprintf(stdout, "sport=%d dport=%d ", ntohs(t->src.u.sctp.port), + ntohs(t->dst.u.sctp.port)); +} + +static void print_proto(union ip_conntrack_proto *proto) +{ + if (proto->sctp.state > sizeof(states)/sizeof(char *)) + fprintf(stdout, "[%u] ", proto->sctp.state); + else + fprintf(stdout, "[%s] ", states[proto->sctp.state]); +} + +static struct ctproto_handler sctp = { + .name = "sctp", + .protonum = 132, + .parse = parse, + .print_tuple = print_tuple, + .print_proto = print_proto, + .final_check = final_check, + .help = help, + .opts = opts, +}; + +void __attribute__ ((constructor)) init(void); +void __attribute__ ((destructor)) fini(void); + +void init(void) +{ + register_proto(&sctp); +} + +void fini(void) +{ + unregister_proto(&sctp); +} diff --git a/extensions/libct_proto_tcp.c b/extensions/libct_proto_tcp.c index 4cddf53..45ee29b 100644 --- a/extensions/libct_proto_tcp.c +++ b/extensions/libct_proto_tcp.c @@ -10,6 +10,7 @@ #include #include #include +#include #include /* For htons */ #include #include @@ -54,7 +55,7 @@ static const char *states[] = { "LISTEN" }; -void help() +static void help() { fprintf(stdout, "--orig-port-src original source port\n"); fprintf(stdout, "--orig-port-dst original destination port\n"); @@ -63,7 +64,7 @@ void help() fprintf(stdout, "--state TCP state, fe. ESTABLISHED\n"); } -int parse(char c, char *argv[], +static int parse(char c, char *argv[], struct ip_conntrack_tuple *orig, struct ip_conntrack_tuple *reply, union ip_conntrack_proto *proto, @@ -113,7 +114,7 @@ int parse(char c, char *argv[], return 1; } -int final_check(unsigned int flags) +static int final_check(unsigned int flags) { if ((flags & ORIG_SPORT) && (flags & ORIG_DPORT)) return 1; @@ -123,15 +124,18 @@ int final_check(unsigned int flags) return 0; } -void print_tuple(struct ip_conntrack_tuple *t) +static void print_tuple(struct ip_conntrack_tuple *t) { fprintf(stdout, "sport=%d dport=%d ", ntohs(t->src.u.tcp.port), ntohs(t->dst.u.tcp.port)); } -void print_proto(union ip_conntrack_proto *proto) +static void print_proto(union ip_conntrack_proto *proto) { - fprintf(stdout, "[%s] ", states[proto->tcp.state]); + if (proto->tcp.state > sizeof(states)/sizeof(char *)) + fprintf(stdout, "[%u] ", states[proto->tcp.state]); + else + fprintf(stdout, "[%s] ", states[proto->tcp.state]); } static struct ctproto_handler tcp = { @@ -142,7 +146,7 @@ static struct ctproto_handler tcp = { .print_proto = print_proto, .final_check = final_check, .help = help, - .opts = opts + .opts = opts, }; void __attribute__ ((constructor)) init(void); diff --git a/extensions/libct_proto_tcp.man b/extensions/libct_proto_tcp.man new file mode 100644 index 0000000..41783f8 --- /dev/null +++ b/extensions/libct_proto_tcp.man @@ -0,0 +1,16 @@ +This module matches on TCP-specific fields. +.TP +.BI "--orig-port-src " "PORT" +Source port in original direction +.TP +.BI "--orig-port-dst " "PORT" +Destination port in original direction +.TP +.BI "--reply-port-src " "PORT" +Source port in reply direction +.TP +.BI "--reply-port-dst " "PORT" +Destination port in reply direction +.TP +.BI "--state " "[NONE|SYN_SENT|SYN_RECV|ESTABLISHED|FIN_WAIT|CLOSE_WAIT|LAST_ACK|TIME_WAIT|CLOSE|LISTEN]" +TCP state diff --git a/extensions/libct_proto_udp.man b/extensions/libct_proto_udp.man new file mode 100644 index 0000000..c67fedf --- /dev/null +++ b/extensions/libct_proto_udp.man @@ -0,0 +1,13 @@ +This module matches on UDP-specific fields. +.TP +.BI "--orig-port-src " "PORT" +Source port in original direction +.TP +.BI "--orig-port-dst " "PORT" +Destination port in original direction +.TP +.BI "--reply-port-src " "PORT" +Source port in reply direction +.TP +.BI "--reply-port-dst " "PORT" +Destination port in reply direction diff --git a/src/conntrack.c b/src/conntrack.c index 11a6b54..dfedf68 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -25,6 +25,8 @@ * * 2005-04-16 Harald Welte : * Add support for conntrack accounting and conntrack mark + * 2005-06-23 Harald Welte : + * Add support for expect creation * */ #include @@ -47,7 +49,7 @@ #include "libct_proto.h" #define PROGNAME "conntrack" -#define VERSION "0.62" +#define VERSION "0.63" #if 0 #define DEBUGP printf @@ -127,11 +129,22 @@ enum options { CT_OPT_EVENT_MASK_BIT = 10, CT_OPT_EVENT_MASK = (1 << CT_OPT_EVENT_MASK_BIT), + CT_OPT_TUPLE_SRC_BIT = 11, + CT_OPT_TUPLE_SRC = (1 << CT_OPT_TUPLE_SRC_BIT), + + CT_OPT_TUPLE_DST_BIT = 12, + CT_OPT_TUPLE_DST = (1 << CT_OPT_TUPLE_DST_BIT), + + CT_OPT_MASK_SRC_BIT = 13, + CT_OPT_MASK_SRC = (1 << CT_OPT_MASK_SRC_BIT), + + CT_OPT_MASK_DST_BIT = 14, + CT_OPT_MASK_DST = (1 << CT_OPT_MASK_DST_BIT), }; -#define NUMBER_OF_OPT 11 +#define NUMBER_OF_OPT 15 static const char optflags[NUMBER_OF_OPT] -= { 's', 'd', 'r', 'q', 'p', 't', 'u', 'z','m','g','e'}; += { 's', 'd', 'r', 'q', 'p', 't', 'u', 'z','m','g','e', '[',']','{','}'}; static struct option original_opts[] = { {"dump", 2, 0, 'L'}, @@ -154,6 +167,10 @@ static struct option original_opts[] = { {"dump-mask", 1, 0, 'm'}, {"groups", 1, 0, 'g'}, {"event-mask", 1, 0, 'e'}, + {"tuple-src", 1, 0, '['}, + {"tuple-dst", 1, 0, ']'}, + {"mask-src", 1, 0, '{'}, + {"mask-dst", 1, 0, '}'}, {0, 0, 0, 0} }; @@ -174,16 +191,16 @@ static unsigned int global_option_offset = 0; static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = /* Well, it's better than "Re: Linux vs FreeBSD" */ { - /* -s -d -r -q -p -t -u -z -m -g -e */ -/*LIST*/ {'x','x','x','x','x','x','x',' ','x','x','x'}, -/*CREATE*/ {'+','+','+','+','+','+','+','x','x','x','x'}, -/*DELETE*/ {' ',' ',' ',' ',' ','x','x','x','x','x','x'}, -/*GET*/ {' ',' ',' ',' ','+','x','x','x','x','x','x'}, -/*FLUSH*/ {'x','x','x','x','x','x','x','x','x','x','x'}, -/*EVENT*/ {'x','x','x','x','x','x','x','x','x',' ','x'}, -/*ACTION*/ {'x','x','x','x','x','x','x','x',' ','x',' '}, -/*VERSION*/ {'x','x','x','x','x','x','x','x','x','x','x'}, -/*HELP*/ {'x','x','x','x',' ','x','x','x','x','x','x'}, + /* -s -d -r -q -p -t -u -z -m -g -e ts td ms md */ +/*LIST*/ {'x','x','x','x','x','x','x',' ','x','x','x','x','x','x','x'}, +/*CREATE*/ {'+','+','+','+','+','+','+','x','x','x','x','+','+','+','+'}, +/*DELETE*/ {' ',' ',' ',' ',' ','x','x','x','x','x','x',' ',' ',' ',' '}, +/*GET*/ {' ',' ',' ',' ','+','x','x','x','x','x','x',' ',' ',' ',' '}, +/*FLUSH*/ {'x','x','x','x','x','x','x','x','x','x','x','x','x','x','x'}, +/*EVENT*/ {'x','x','x','x','x','x','x','x','x',' ','x','x','x','x','x'}, +/*ACTION*/ {'x','x','x','x','x','x','x','x',' ','x',' ','x','x','x','x'}, +/*VERSION*/ {'x','x','x','x','x','x','x','x','x','x','x','x','x','x','x'}, +/*HELP*/ {'x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x'}, }; /* FIXME: hardcoded!, this must be defined during compilation time */ @@ -355,9 +372,11 @@ static struct parse_parameter { size_t size; unsigned int value[10]; } parse_array[PARSE_MAX] = { - { {"ASSURED", "SEEN_REPLY", "UNSET"}, - 3, - { IPS_ASSURED, IPS_SEEN_REPLY, 0} }, + { {"EXPECTED", "ASSURED", "SEEN_REPLY", "CONFIRMED", "SNAT", "DNAT", + "SEQ_ADJUST", "UNSET"}, + 8, + { IPS_EXPECTED, IPS_ASSURED, IPS_SEEN_REPLY, IPS_CONFIRMED, + IPS_SRC_NAT, IPS_DST_NAT, IPS_SEQ_ADJUST, 0} }, { {"ALL", "TCP", "UDP", "ICMP"}, 4, {~0U, NFGRP_IPV4_CT_TCP, NFGRP_IPV4_CT_UDP, NFGRP_IPV4_CT_ICMP} }, @@ -502,7 +521,7 @@ fprintf(stdout, "Usage: %s [commands] [options]\n", prog); fprintf(stdout, "\n"); fprintf(stdout, "Commands:\n"); fprintf(stdout, "-L [table] [-z] List conntrack or expectation table\n"); -fprintf(stdout, "-G [table] parameters Get conntrack or expectation\n"); +fprintf(stdout, "-G [table] parameters Get conntrack or expectation\n"); fprintf(stdout, "-D [table] parameters Delete conntrack or expectation\n"); fprintf(stdout, "-I [table] parameters Create a conntrack or expectation\n"); fprintf(stdout, "-E [table] [options] Show events\n"); @@ -514,6 +533,10 @@ fprintf(stdout, "--orig-src ip Source address from original direction\n"); fprintf(stdout, "--orig-dst ip Destination address from original direction\n"); fprintf(stdout, "--reply-src ip Source addres from reply direction\n"); fprintf(stdout, "--reply-dst ip Destination address from reply direction\n"); +fprintf(stdout, "--tuple-src ip Source address in expect tuple\n"); +fprintf(stdout, "--tuple-dst ip Destination address in expect tuple\n"); +fprintf(stdout, "--mask-src ip Source mask in expect\n"); +fprintf(stdout, "--mask-dst ip Destination mask in expect\n"); fprintf(stdout, "-p proto Layer 4 Protocol\n"); fprintf(stdout, "-t timeout Set timeout\n"); fprintf(stdout, "-u status Set status\n"); @@ -525,9 +548,9 @@ fprintf(stdout, "-z Zero Counters\n"); int main(int argc, char *argv[]) { - char c; + int c; unsigned int command = 0, options = 0; - struct ip_conntrack_tuple orig, reply, *o = NULL, *r = NULL; + struct ip_conntrack_tuple orig, reply, tuple, mask, *o = NULL, *r = NULL; struct ctproto_handler *h = NULL; union ip_conntrack_proto proto; unsigned long timeout = 0; @@ -543,7 +566,7 @@ int main(int argc, char *argv[]) reply.dst.dir = IP_CT_DIR_REPLY; while ((c = getopt_long(argc, argv, - "L::I::D::G::E::A::F::hVs:d:r:q:p:t:u:m:g:e:z", + "L::I::D::G::E::A::F::hVs:d:r:q:p:t:u:m:g:e:z[:]:{:}:", opts, NULL)) != -1) { switch(c) { case 'L': @@ -644,6 +667,26 @@ int main(int argc, char *argv[]) case 'z': options |= CT_OPT_ZERO; break; + case '[': + options |= CT_OPT_TUPLE_SRC; + if (optarg) + tuple.src.ip = inet_addr(optarg); + break; + case ']': + options |= CT_OPT_TUPLE_DST; + if (optarg) + tuple.dst.ip = inet_addr(optarg); + break; + case '{': + options |= CT_OPT_MASK_SRC; + if (optarg) + mask.src.ip = inet_addr(optarg); + break; + case '}': + options |= CT_OPT_MASK_DST; + if (optarg) + mask.dst.ip = inet_addr(optarg); + break; default: if (h && h->parse && !h->parse(c - h->option_offset, argv, &orig, &reply, @@ -687,7 +730,8 @@ int main(int argc, char *argv[]) res = create_conntrack(&orig, &reply, timeout, &proto, status); else - not_implemented_yet(); + res = create_expect(&tuple, &mask, &orig, + &reply, timeout); break; case CT_DELETE: diff --git a/src/libct.c b/src/libct.c index d40c7f1..0555ec8 100644 --- a/src/libct.c +++ b/src/libct.c @@ -1,5 +1,6 @@ /* - * (C) 2005 by Pablo Neira Ayuso + * (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 @@ -233,6 +234,28 @@ int create_conntrack(struct ip_conntrack_tuple *orig, return 0; } +int create_expect(struct ip_conntrack_tuple *tuple, + struct ip_conntrack_tuple *mask, + struct ip_conntrack_tuple *master_tuple_orig, + struct ip_conntrack_tuple *master_tuple_reply, + unsigned long timeout) +{ + struct ctnl_handle cth; + int ret; + + if ((ret = ctnl_open(&cth, 0)) < 0) + return ret; + + if ((ret = ctnl_new_expect(&cth, tuple, mask, master_tuple_orig, + master_tuple_reply, timeout)) < 0) + return ret; + + if ((ret = ctnl_close(&cth)) < 0) + return ret; + + return -1; +} + int delete_conntrack(struct ip_conntrack_tuple *tuple, enum ctattr_type_t t) { -- cgit v1.2.3 From 9ab85762233756f1e828f7c4c6007d25ac26f494 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: Tue, 12 Jul 2005 23:24:06 +0000 Subject: o Use conntrack netlink attributes: Major change o Kill action setting: Mask based dumping --- ChangeLog | 31 ++- extensions/libct_proto_icmp.c | 31 +-- extensions/libct_proto_sctp.c | 108 ++++++--- extensions/libct_proto_tcp.c | 118 +++++++--- extensions/libct_proto_udp.c | 94 ++++++-- include/libct_proto.h | 25 +- src/conntrack.c | 535 ++++++++++++++++++++++++++++-------------- src/libct.c | 526 ++++++++++++++++++++++++++--------------- test.sh | 77 ++++-- 9 files changed, 1027 insertions(+), 518 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 688b0cc..0ae9fc5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2005-07-12 + + o Use conntrack netlink attributes: Major change + o Kill action setting: Mask based dumping + o Fix ChangeLog + 2005-05-23 o Fixed syntax error (tab/space issue) in help message @@ -9,11 +15,16 @@ o Add SCTP extension o Add support for expect creation o Bump version number to 0.63 -2005-04-25 + +2005-05-17 - o Added support for mask based event dumping - o Added support for mask based event notification - o On-demand autoload of ip_conntrack_netlink + o Added descriptive error messages. + o Fix wrong flags check in [tcp|udp] proto helpers. + +2005-05-16 + + o Implemented ICMP proto helper + o Added help() and final_check() functions for proto helpers. 2005-05-01 @@ -33,12 +44,8 @@ o Autoconf stuff for conntrack + some pablo's modifications. o Fixed packet counters formatting (use %llu instead of %lu) -2005-05-16 - - o Implemented ICMP proto helper - o Added help() and final_check() functions for proto helpers. - -2005-05-17 +2005-04-25 - o Added descriptive error messages. - o Fix wrong flags check in [tcp|udp] proto helpers. + o Added support for mask based event dumping + o Added support for mask based event notification + o On-demand autoload of ip_conntrack_netlink diff --git a/extensions/libct_proto_icmp.c b/extensions/libct_proto_icmp.c index 6a2db92..24d3d3f 100644 --- a/extensions/libct_proto_icmp.c +++ b/extensions/libct_proto_icmp.c @@ -11,8 +11,6 @@ #include #include #include /* For htons */ -#include -#include #include "libct_proto.h" static struct option opts[] = { @@ -41,27 +39,28 @@ void help() } int parse(char c, char *argv[], - struct ip_conntrack_tuple *orig, - struct ip_conntrack_tuple *reply, - union ip_conntrack_proto *proto, + struct ctnl_tuple *orig, + struct ctnl_tuple *reply, + struct ctnl_tuple *mask, + union ctnl_protoinfo *proto, unsigned int *flags) { switch(c) { case '1': if (optarg) { - orig->dst.u.icmp.type = atoi(optarg); + orig->l4dst.icmp.type = atoi(optarg); *flags |= ICMP_TYPE; } break; case '2': if (optarg) { - orig->dst.u.icmp.code = atoi(optarg); + orig->l4dst.icmp.code = atoi(optarg); *flags |= ICMP_CODE; } break; case '3': if (optarg) { - reply->src.u.icmp.id = atoi(optarg); + orig->l4src.icmp.id = atoi(optarg); *flags |= ICMP_ID; } break; @@ -69,7 +68,9 @@ int parse(char c, char *argv[], return 1; } -int final_check(unsigned int flags) +int final_check(unsigned int flags, + struct ctnl_tuple *orig, + struct ctnl_tuple *reply) { if (!(flags & ICMP_TYPE)) return 0; @@ -79,18 +80,18 @@ int final_check(unsigned int flags) return 1; } -void print_tuple(struct ip_conntrack_tuple *t) +void print_proto(struct ctnl_tuple *t) { - fprintf(stdout, "type=%d code=%d id=%d ", t->dst.u.icmp.type, - t->dst.u.icmp.code, - t->src.u.icmp.id); + fprintf(stdout, "type=%d code=%d id=%d", t->l4dst.icmp.type, + t->l4dst.icmp.code, + t->l4src.icmp.id); } static struct ctproto_handler icmp = { .name = "icmp", .protonum = 1, - .parse = parse, - .print_tuple = print_tuple, + .parse_opts = parse, + .print_proto = print_proto, .final_check = final_check, .help = help, .opts = opts diff --git a/extensions/libct_proto_sctp.c b/extensions/libct_proto_sctp.c index b84c2ba..5b50fbc 100644 --- a/extensions/libct_proto_sctp.c +++ b/extensions/libct_proto_sctp.c @@ -1,26 +1,26 @@ /* - * (C) 2005 by Harald Welte + * (C) 2005 by Harald Welte * * 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 + * 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 /* For htons */ -#include -#include +#include #include "libct_proto.h" +#include "libctnetlink.h" static struct option opts[] = { {"orig-port-src", 1, 0, '1'}, {"orig-port-dst", 1, 0, '2'}, {"reply-port-src", 1, 0, '3'}, {"reply-port-dst", 1, 0, '4'}, - {"state", 1, 0, '5'}, + {"state", 1, 0, '7'}, {0, 0, 0, 0} }; @@ -52,43 +52,44 @@ static const char *states[] = { "SHUTDOWN_ACK_SENT", }; -static void help() +void help() { fprintf(stdout, "--orig-port-src original source port\n"); fprintf(stdout, "--orig-port-dst original destination port\n"); fprintf(stdout, "--reply-port-src reply source port\n"); fprintf(stdout, "--reply-port-dst reply destination port\n"); - fprintf(stdout, "--state SCTP state, eg. ESTABLISHED\n"); + fprintf(stdout, "--state SCTP state, fe. ESTABLISHED\n"); } -static int parse(char c, char *argv[], - struct ip_conntrack_tuple *orig, - struct ip_conntrack_tuple *reply, - union ip_conntrack_proto *proto, - unsigned int *flags) +int parse_options(char c, char *argv[], + struct ctnl_tuple *orig, + struct ctnl_tuple *reply, + struct ctnl_tuple *mask, + union ctnl_protoinfo *proto, + unsigned int *flags) { switch(c) { case '1': if (optarg) { - orig->src.u.sctp.port = htons(atoi(optarg)); + orig->l4src.sctp.port = htons(atoi(optarg)); *flags |= ORIG_SPORT; } break; case '2': if (optarg) { - orig->dst.u.sctp.port = htons(atoi(optarg)); + orig->l4dst.sctp.port = htons(atoi(optarg)); *flags |= ORIG_DPORT; } break; case '3': if (optarg) { - reply->src.u.sctp.port = htons(atoi(optarg)); + reply->l4src.sctp.port = htons(atoi(optarg)); *flags |= REPL_SPORT; } break; case '4': if (optarg) { - reply->dst.u.sctp.port = htons(atoi(optarg)); + reply->l4dst.sctp.port = htons(atoi(optarg)); *flags |= REPL_DPORT; } break; @@ -97,7 +98,9 @@ static int parse(char c, char *argv[], int i; for (i=0; i<10; i++) { if (strcmp(optarg, states[i]) == 0) { - proto->sctp.state = i; + /* FIXME: Add state to + * ctnl_protoinfo + proto->sctp.state = i; */ break; } } @@ -111,39 +114,68 @@ static int parse(char c, char *argv[], return 1; } -static int final_check(unsigned int flags) +int final_check(unsigned int flags, + struct ctnl_tuple *orig, + struct ctnl_tuple *reply) { - if ((flags & ORIG_SPORT) && (flags & ORIG_DPORT)) + if ((flags & (ORIG_SPORT|ORIG_DPORT)) + && !(flags & (REPL_SPORT|REPL_DPORT))) { + reply->l4src.sctp.port = orig->l4dst.sctp.port; + reply->l4dst.sctp.port = orig->l4src.sctp.port; return 1; - else if ((flags & REPL_SPORT) && (flags & REPL_DPORT)) + } else if (!(flags & (ORIG_SPORT|ORIG_DPORT)) + && (flags & (REPL_SPORT|REPL_DPORT))) { + orig->l4src.sctp.port = reply->l4dst.sctp.port; + orig->l4dst.sctp.port = reply->l4src.sctp.port; + return 1; + } + if ((flags & (ORIG_SPORT|ORIG_DPORT)) + && ((flags & (REPL_SPORT|REPL_DPORT)))) return 1; return 0; } -static void print_tuple(struct ip_conntrack_tuple *t) +void parse_proto(struct nfattr *cda[], struct ctnl_tuple *tuple) +{ + if (cda[CTA_PROTO_SCTP_SRC-1]) + tuple->l4src.sctp.port = + *(u_int16_t *)NFA_DATA(cda[CTA_PROTO_SCTP_SRC-1]); + if (cda[CTA_PROTO_SCTP_DST-1]) + tuple->l4dst.sctp.port = + *(u_int16_t *)NFA_DATA(cda[CTA_PROTO_SCTP_DST-1]); +} + +void parse_protoinfo(struct nfattr *cda[], struct ctnl_conntrack *ct) +{ +/* if (cda[CTA_PROTOINFO_SCTP_STATE-1]) + ct->protoinfo.sctp.state = + *(u_int8_t *)NFA_DATA(cda[CTA_PROTOINFO_SCTP_STATE-1]); +*/ +} + +void print_protoinfo(union ctnl_protoinfo *protoinfo) { - fprintf(stdout, "sport=%d dport=%d ", ntohs(t->src.u.sctp.port), - ntohs(t->dst.u.sctp.port)); +/* fprintf(stdout, "%s ", states[protoinfo->sctp.state]); */ } -static void print_proto(union ip_conntrack_proto *proto) +void print_proto(struct ctnl_tuple *tuple) { - if (proto->sctp.state > sizeof(states)/sizeof(char *)) - fprintf(stdout, "[%u] ", proto->sctp.state); - else - fprintf(stdout, "[%s] ", states[proto->sctp.state]); + fprintf(stdout, "sport=%u dport=%u ", htons(tuple->l4src.sctp.port), + htons(tuple->l4dst.sctp.port)); } static struct ctproto_handler sctp = { - .name = "sctp", - .protonum = 132, - .parse = parse, - .print_tuple = print_tuple, - .print_proto = print_proto, - .final_check = final_check, - .help = help, - .opts = opts, + .name = "sctp", + .protonum = 132, + .parse_opts = parse_options, + .parse_protoinfo = parse_protoinfo, + .parse_proto = parse_proto, + .print_proto = print_proto, + .print_protoinfo = print_protoinfo, + .final_check = final_check, + .help = help, + .opts = opts }; void __attribute__ ((constructor)) init(void); diff --git a/extensions/libct_proto_tcp.c b/extensions/libct_proto_tcp.c index 45ee29b..5fa3652 100644 --- a/extensions/libct_proto_tcp.c +++ b/extensions/libct_proto_tcp.c @@ -10,18 +10,19 @@ #include #include #include -#include #include /* For htons */ -#include -#include +#include #include "libct_proto.h" +#include "libctnetlink.h" static struct option opts[] = { {"orig-port-src", 1, 0, '1'}, {"orig-port-dst", 1, 0, '2'}, {"reply-port-src", 1, 0, '3'}, {"reply-port-dst", 1, 0, '4'}, - {"state", 1, 0, '5'}, + {"mask-port-src", 1, 0, '5'}, + {"mask-port-dst", 1, 0, '6'}, + {"state", 1, 0, '7'}, {0, 0, 0, 0} }; @@ -38,7 +39,13 @@ enum tcp_param_flags { REPL_DPORT_BIT = 3, REPL_DPORT = (1 << REPL_DPORT_BIT), - STATE_BIT = 4, + MASK_SPORT_BIT = 4, + MASK_SPORT = (1 << MASK_SPORT_BIT), + + MASK_DPORT_BIT = 5, + MASK_DPORT = (1 << MASK_DPORT_BIT), + + STATE_BIT = 6, STATE = (1 << STATE_BIT) }; @@ -55,47 +62,62 @@ static const char *states[] = { "LISTEN" }; -static void help() +void help() { fprintf(stdout, "--orig-port-src original source port\n"); fprintf(stdout, "--orig-port-dst original destination port\n"); fprintf(stdout, "--reply-port-src reply source port\n"); fprintf(stdout, "--reply-port-dst reply destination port\n"); + fprintf(stdout, "--mask-port-src mask source port\n"); + fprintf(stdout, "--mask-port-dst mask destination port\n"); fprintf(stdout, "--state TCP state, fe. ESTABLISHED\n"); } -static int parse(char c, char *argv[], - struct ip_conntrack_tuple *orig, - struct ip_conntrack_tuple *reply, - union ip_conntrack_proto *proto, - unsigned int *flags) +int parse_options(char c, char *argv[], + struct ctnl_tuple *orig, + struct ctnl_tuple *reply, + struct ctnl_tuple *mask, + union ctnl_protoinfo *proto, + unsigned int *flags) { switch(c) { case '1': if (optarg) { - orig->src.u.tcp.port = htons(atoi(optarg)); + orig->l4src.tcp.port = htons(atoi(optarg)); *flags |= ORIG_SPORT; } break; case '2': if (optarg) { - orig->dst.u.tcp.port = htons(atoi(optarg)); + orig->l4dst.tcp.port = htons(atoi(optarg)); *flags |= ORIG_DPORT; } break; case '3': if (optarg) { - reply->src.u.tcp.port = htons(atoi(optarg)); + reply->l4src.tcp.port = htons(atoi(optarg)); *flags |= REPL_SPORT; } break; case '4': if (optarg) { - reply->dst.u.tcp.port = htons(atoi(optarg)); + reply->l4dst.tcp.port = htons(atoi(optarg)); *flags |= REPL_DPORT; } break; case '5': + if (optarg) { + mask->l4src.tcp.port = htons(atoi(optarg)); + *flags |= MASK_SPORT; + } + break; + case '6': + if (optarg) { + mask->l4src.tcp.port = htons(atoi(optarg)); + *flags |= MASK_DPORT; + } + break; + case '7': if (optarg) { int i; for (i=0; i<10; i++) { @@ -114,39 +136,67 @@ static int parse(char c, char *argv[], return 1; } -static int final_check(unsigned int flags) +int final_check(unsigned int flags, + struct ctnl_tuple *orig, + struct ctnl_tuple *reply) { - if ((flags & ORIG_SPORT) && (flags & ORIG_DPORT)) + if ((flags & (ORIG_SPORT|ORIG_DPORT)) + && !(flags & (REPL_SPORT|REPL_DPORT))) { + reply->l4src.tcp.port = orig->l4dst.tcp.port; + reply->l4dst.tcp.port = orig->l4src.tcp.port; return 1; - else if ((flags & REPL_SPORT) && (flags & REPL_DPORT)) + } else if (!(flags & (ORIG_SPORT|ORIG_DPORT)) + && (flags & (REPL_SPORT|REPL_DPORT))) { + orig->l4src.tcp.port = reply->l4dst.tcp.port; + orig->l4dst.tcp.port = reply->l4src.tcp.port; + return 1; + } + if ((flags & (ORIG_SPORT|ORIG_DPORT)) + && ((flags & (REPL_SPORT|REPL_DPORT)))) return 1; return 0; } -static void print_tuple(struct ip_conntrack_tuple *t) +void parse_proto(struct nfattr *cda[], struct ctnl_tuple *tuple) +{ + if (cda[CTA_PROTO_TCP_SRC-1]) + tuple->l4src.tcp.port = + *(u_int16_t *)NFA_DATA(cda[CTA_PROTO_TCP_SRC-1]); + if (cda[CTA_PROTO_TCP_DST-1]) + tuple->l4dst.tcp.port = + *(u_int16_t *)NFA_DATA(cda[CTA_PROTO_TCP_DST-1]); +} + +void parse_protoinfo(struct nfattr *cda[], struct ctnl_conntrack *ct) +{ + if (cda[CTA_PROTOINFO_TCP_STATE-1]) + ct->protoinfo.tcp.state = + *(u_int8_t *)NFA_DATA(cda[CTA_PROTOINFO_TCP_STATE-1]); +} + +void print_protoinfo(union ctnl_protoinfo *protoinfo) { - fprintf(stdout, "sport=%d dport=%d ", ntohs(t->src.u.tcp.port), - ntohs(t->dst.u.tcp.port)); + fprintf(stdout, "%s ", states[protoinfo->tcp.state]); } -static void print_proto(union ip_conntrack_proto *proto) +void print_proto(struct ctnl_tuple *tuple) { - if (proto->tcp.state > sizeof(states)/sizeof(char *)) - fprintf(stdout, "[%u] ", states[proto->tcp.state]); - else - fprintf(stdout, "[%s] ", states[proto->tcp.state]); + fprintf(stdout, "sport=%u dport=%u ", htons(tuple->l4src.tcp.port), + htons(tuple->l4dst.tcp.port)); } static struct ctproto_handler tcp = { - .name = "tcp", - .protonum = 6, - .parse = parse, - .print_tuple = print_tuple, - .print_proto = print_proto, - .final_check = final_check, - .help = help, - .opts = opts, + .name = "tcp", + .protonum = 6, + .parse_opts = parse_options, + .parse_protoinfo = parse_protoinfo, + .parse_proto = parse_proto, + .print_proto = print_proto, + .print_protoinfo = print_protoinfo, + .final_check = final_check, + .help = help, + .opts = opts }; void __attribute__ ((constructor)) init(void); diff --git a/extensions/libct_proto_udp.c b/extensions/libct_proto_udp.c index 0088cc5..aa733f0 100644 --- a/extensions/libct_proto_udp.c +++ b/extensions/libct_proto_udp.c @@ -11,15 +11,17 @@ #include #include #include /* For htons */ -#include -#include +#include #include "libct_proto.h" +#include "libctnetlink.h" static struct option opts[] = { {"orig-port-src", 1, 0, '1'}, {"orig-port-dst", 1, 0, '2'}, {"reply-port-src", 1, 0, '3'}, {"reply-port-dst", 1, 0, '4'}, + {"mask-port-src", 1, 0, '5'}, + {"mask-port-dst", 1, 0, '6'}, {0, 0, 0, 0} }; @@ -35,6 +37,12 @@ enum udp_param_flags { REPL_DPORT_BIT = 3, REPL_DPORT = (1 << REPL_DPORT_BIT), + + MASK_SPORT_BIT = 4, + MASK_SPORT = (1 << MASK_SPORT_BIT), + + MASK_DPORT_BIT = 5, + MASK_DPORT = (1 << MASK_DPORT_BIT), }; void help() @@ -43,67 +51,105 @@ void help() fprintf(stdout, "--orig-port-dst original destination port\n"); fprintf(stdout, "--reply-port-src reply source port\n"); fprintf(stdout, "--reply-port-dst reply destination port\n"); + fprintf(stdout, "--mask-port-src mask source port\n"); + fprintf(stdout, "--mask-port-dst mask destination port\n"); } -int parse(char c, char *argv[], - struct ip_conntrack_tuple *orig, - struct ip_conntrack_tuple *reply, - union ip_conntrack_proto *proto, - unsigned int *flags) +int parse_options(char c, char *argv[], + struct ctnl_tuple *orig, + struct ctnl_tuple *reply, + struct ctnl_tuple *mask, + union ctnl_protoinfo *proto, + unsigned int *flags) { switch(c) { case '1': if (optarg) { - orig->src.u.udp.port = htons(atoi(optarg)); + orig->l4src.udp.port = htons(atoi(optarg)); *flags |= ORIG_SPORT; } break; case '2': if (optarg) { - orig->dst.u.udp.port = htons(atoi(optarg)); + orig->l4dst.udp.port = htons(atoi(optarg)); *flags |= ORIG_DPORT; } break; case '3': if (optarg) { - reply->src.u.udp.port = htons(atoi(optarg)); + reply->l4src.udp.port = htons(atoi(optarg)); *flags |= REPL_SPORT; } break; case '4': if (optarg) { - reply->dst.u.udp.port = htons(atoi(optarg)); + reply->l4dst.udp.port = htons(atoi(optarg)); *flags |= REPL_DPORT; } break; + case '5': + if (optarg) { + mask->l4src.udp.port = htons(atoi(optarg)); + *flags |= MASK_SPORT; + } + break; + case '6': + if (optarg) { + mask->l4src.udp.port = htons(atoi(optarg)); + *flags |= MASK_DPORT; + } + break; } return 1; } -int final_check(unsigned int flags) +int final_check(unsigned int flags, + struct ctnl_tuple *orig, + struct ctnl_tuple *reply) { - if ((flags & ORIG_SPORT) && (flags & ORIG_DPORT)) + if ((flags & (ORIG_SPORT|ORIG_DPORT)) + && !(flags & (REPL_SPORT|REPL_DPORT))) { + reply->l4src.udp.port = orig->l4dst.udp.port; + reply->l4dst.udp.port = orig->l4src.udp.port; + return 1; + } else if (!(flags & (ORIG_SPORT|ORIG_DPORT)) + && (flags & (REPL_SPORT|REPL_DPORT))) { + orig->l4src.udp.port = reply->l4dst.udp.port; + orig->l4dst.udp.port = reply->l4src.udp.port; return 1; - else if ((flags & REPL_SPORT) && (flags & REPL_DPORT)) + } + if ((flags & (ORIG_SPORT|ORIG_DPORT)) + && ((flags & (REPL_SPORT|REPL_DPORT)))) return 1; return 0; } -void print_tuple(struct ip_conntrack_tuple *t) +void parse_proto(struct nfattr *cda[], struct ctnl_tuple *tuple) +{ + if (cda[CTA_PROTO_UDP_SRC-1]) + tuple->l4src.udp.port = + *(u_int16_t *)NFA_DATA(cda[CTA_PROTO_UDP_SRC-1]); + if (cda[CTA_PROTO_UDP_DST-1]) + tuple->l4dst.udp.port = + *(u_int16_t *)NFA_DATA(cda[CTA_PROTO_UDP_DST-1]); +} + +void print_proto(struct ctnl_tuple *tuple) { - fprintf(stdout, "sport=%d dport=%d ", ntohs(t->src.u.udp.port), - ntohs(t->dst.u.udp.port)); + fprintf(stdout, "sport=%u dport=%u ", htons(tuple->l4src.udp.port), + htons(tuple->l4dst.udp.port)); } static struct ctproto_handler udp = { - .name = "udp", - .protonum = 17, - .parse = parse, - .print_tuple = print_tuple, - .final_check = final_check, - .help = help, - .opts = opts + .name = "udp", + .protonum = 17, + .parse_opts = parse_options, + .parse_proto = parse_proto, + .print_proto = print_proto, + .final_check = final_check, + .help = help, + .opts = opts }; void __attribute__ ((constructor)) init(void); diff --git a/include/libct_proto.h b/include/libct_proto.h index 6df03e7..51e23fc 100644 --- a/include/libct_proto.h +++ b/include/libct_proto.h @@ -5,6 +5,7 @@ #include "linux_list.h" #include +#include "libctnetlink.h" struct cta_proto; @@ -13,16 +14,24 @@ struct ctproto_handler { char *name; u_int16_t protonum; + + enum ctattr_protoinfo protoinfo_attr; - int (*parse)(char c, char *argv[], - struct ip_conntrack_tuple *orig, - struct ip_conntrack_tuple *reply, - union ip_conntrack_proto *proto, + int (*parse_opts)(char c, char *argv[], + struct ctnl_tuple *orig, + struct ctnl_tuple *reply, + struct ctnl_tuple *mask, + union ctnl_protoinfo *proto, unsigned int *flags); - void (*print_tuple)(struct ip_conntrack_tuple *t); - void (*print_proto)(union ip_conntrack_proto *proto); - - int (*final_check)(unsigned int flags); + void (*parse_proto)(struct nfattr *cda[], struct ctnl_tuple *tuple); + void (*parse_protoinfo)(struct nfattr *cda[], + struct ctnl_conntrack *ct); + void (*print_proto)(struct ctnl_tuple *t); + void (*print_protoinfo)(union ctnl_protoinfo *protoinfo); + + int (*final_check)(unsigned int flags, + struct ctnl_tuple *orig, + struct ctnl_tuple *reply); void (*help)(); diff --git a/src/conntrack.c b/src/conntrack.c index dfedf68..a6efd8b 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -41,7 +41,6 @@ #include #include #include -#include #include #include "libctnetlink.h" #include "libnfnetlink.h" @@ -62,34 +61,60 @@ #endif enum action { + CT_NONE = 0, + CT_LIST_BIT = 0, CT_LIST = (1 << CT_LIST_BIT), CT_CREATE_BIT = 1, CT_CREATE = (1 << CT_CREATE_BIT), + + CT_UPDATE_BIT = 2, + CT_UPDATE = (1 << CT_UPDATE_BIT), - CT_DELETE_BIT = 2, + CT_DELETE_BIT = 3, CT_DELETE = (1 << CT_DELETE_BIT), - CT_GET_BIT = 3, + CT_GET_BIT = 4, CT_GET = (1 << CT_GET_BIT), - CT_FLUSH_BIT = 4, + CT_FLUSH_BIT = 5, CT_FLUSH = (1 << CT_FLUSH_BIT), - CT_EVENT_BIT = 5, + CT_EVENT_BIT = 6, CT_EVENT = (1 << CT_EVENT_BIT), - CT_ACTION_BIT = 6, - CT_ACTION = (1 << CT_ACTION_BIT), - CT_VERSION_BIT = 7, CT_VERSION = (1 << CT_VERSION_BIT), CT_HELP_BIT = 8, CT_HELP = (1 << CT_HELP_BIT), + + EXP_LIST_BIT = 9, + EXP_LIST = (1 << EXP_LIST_BIT), + + EXP_CREATE_BIT = 10, + EXP_CREATE = (1 << EXP_CREATE_BIT), + + EXP_DELETE_BIT = 11, + EXP_DELETE = (1 << EXP_DELETE_BIT), + + EXP_GET_BIT = 12, + EXP_GET = (1 << EXP_GET_BIT), + + EXP_FLUSH_BIT = 13, + EXP_FLUSH = (1 << EXP_FLUSH_BIT), + + EXP_EVENT_BIT = 14, + EXP_EVENT = (1 << EXP_EVENT_BIT), }; -#define NUMBER_OF_CMD 9 +#define NUMBER_OF_CMD 15 + +static const char cmdflags[NUMBER_OF_CMD] += {'L','I','U','D','G','F','E','V','h','L','I','D','G','F','E'}; + +static const char cmd_need_param[NUMBER_OF_CMD] += {' ','x','x','x','x',' ',' ',' ',' ',' ','x','x','x',' ',' '}; enum options { CT_OPT_ORIG_SRC_BIT = 0, @@ -120,36 +145,34 @@ enum options { CT_OPT_ZERO_BIT = 7, CT_OPT_ZERO = (1 << CT_OPT_ZERO_BIT), - CT_OPT_DUMP_MASK_BIT = 8, - CT_OPT_DUMP_MASK = (1 << CT_OPT_DUMP_MASK_BIT), - - CT_OPT_GROUP_MASK_BIT = 9, - CT_OPT_GROUP_MASK = (1 << CT_OPT_GROUP_MASK_BIT), - - CT_OPT_EVENT_MASK_BIT = 10, + CT_OPT_EVENT_MASK_BIT = 8, CT_OPT_EVENT_MASK = (1 << CT_OPT_EVENT_MASK_BIT), - CT_OPT_TUPLE_SRC_BIT = 11, - CT_OPT_TUPLE_SRC = (1 << CT_OPT_TUPLE_SRC_BIT), + CT_OPT_EXP_SRC_BIT = 9, + CT_OPT_EXP_SRC = (1 << CT_OPT_EXP_SRC_BIT), - CT_OPT_TUPLE_DST_BIT = 12, - CT_OPT_TUPLE_DST = (1 << CT_OPT_TUPLE_DST_BIT), + CT_OPT_EXP_DST_BIT = 10, + CT_OPT_EXP_DST = (1 << CT_OPT_EXP_DST_BIT), - CT_OPT_MASK_SRC_BIT = 13, + CT_OPT_MASK_SRC_BIT = 11, CT_OPT_MASK_SRC = (1 << CT_OPT_MASK_SRC_BIT), - CT_OPT_MASK_DST_BIT = 14, + CT_OPT_MASK_DST_BIT = 12, CT_OPT_MASK_DST = (1 << CT_OPT_MASK_DST_BIT), + + CT_OPT_NATRANGE_BIT = 13, + CT_OPT_NATRANGE = (1 << CT_OPT_NATRANGE_BIT), }; -#define NUMBER_OF_OPT 15 +#define NUMBER_OF_OPT 14 static const char optflags[NUMBER_OF_OPT] -= { 's', 'd', 'r', 'q', 'p', 't', 'u', 'z','m','g','e', '[',']','{','}'}; += {'s','d','r','q','p','t','u','z','e','[',']','{','}','a'}; static struct option original_opts[] = { {"dump", 2, 0, 'L'}, {"create", 1, 0, 'I'}, {"delete", 1, 0, 'D'}, + {"update", 1, 0, 'U'}, {"get", 1, 0, 'G'}, {"flush", 1, 0, 'F'}, {"event", 1, 0, 'E'}, @@ -164,13 +187,12 @@ static struct option original_opts[] = { {"timeout", 1, 0, 't'}, {"status", 1, 0, 'u'}, {"zero", 0, 0, 'z'}, - {"dump-mask", 1, 0, 'm'}, - {"groups", 1, 0, 'g'}, {"event-mask", 1, 0, 'e'}, {"tuple-src", 1, 0, '['}, {"tuple-dst", 1, 0, ']'}, {"mask-src", 1, 0, '{'}, {"mask-dst", 1, 0, '}'}, + {"nat-range", 1, 0, 'a'}, {0, 0, 0, 0} }; @@ -188,22 +210,29 @@ static unsigned int global_option_offset = 0; * optional */ +/* FIXME: I'd need something different than this table to catch up some + * particular cases. Better later Pablo */ static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = /* Well, it's better than "Re: Linux vs FreeBSD" */ { - /* -s -d -r -q -p -t -u -z -m -g -e ts td ms md */ -/*LIST*/ {'x','x','x','x','x','x','x',' ','x','x','x','x','x','x','x'}, -/*CREATE*/ {'+','+','+','+','+','+','+','x','x','x','x','+','+','+','+'}, -/*DELETE*/ {' ',' ',' ',' ',' ','x','x','x','x','x','x',' ',' ',' ',' '}, -/*GET*/ {' ',' ',' ',' ','+','x','x','x','x','x','x',' ',' ',' ',' '}, -/*FLUSH*/ {'x','x','x','x','x','x','x','x','x','x','x','x','x','x','x'}, -/*EVENT*/ {'x','x','x','x','x','x','x','x','x',' ','x','x','x','x','x'}, -/*ACTION*/ {'x','x','x','x','x','x','x','x',' ','x',' ','x','x','x','x'}, -/*VERSION*/ {'x','x','x','x','x','x','x','x','x','x','x','x','x','x','x'}, -/*HELP*/ {'x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x'}, + /* -s -d -r -q -p -t -u -z -e -x -y -k -l -a */ +/*CT_LIST*/ {'x','x','x','x','x','x','x',' ','x','x','x','x','x','x'}, +/*CT_CREATE*/ {' ',' ',' ',' ','+','+','+','x','x','x','x','x','x',' '}, +/*CT_UPDATE*/ {' ',' ',' ',' ','+','+','+','x','x','x','x','x','x','x'}, +/*CT_DELETE*/ {' ',' ',' ',' ',' ','x','x','x','x','x','x','x','x','x'}, +/*CT_GET*/ {' ',' ',' ',' ','+','x','x','x','x','x','x','x','x','x'}, +/*CT_FLUSH*/ {'x','x','x','x','x','x','x','x','x','x','x','x','x','x'}, +/*CT_EVENT*/ {'x','x','x','x','x','x','x','x',' ','x','x','x','x','x'}, +/*VERSION*/ {'x','x','x','x','x','x','x','x','x','x','x','x','x','x'}, +/*HELP*/ {'x','x','x','x',' ','x','x','x','x','x','x','x','x','x'}, +/*EXP_LIST*/ {'x','x','x','x','x','x','x','x','x','x','x','x','x','x'}, +/*EXP_CREATE*/{'+','+',' ',' ','+','+',' ','x','x','+','+','+','+','x'}, +/*EXP_DELETE*/{'+','+',' ',' ','+','x','x','x','x','x','x','x','x','x'}, +/*EXP_GET*/ {'+','+',' ',' ','+','x','x','x','x','x','x','x','x','x'}, +/*EXP_FLUSH*/ {'x','x','x','x','x','x','x','x','x','x','x','x','x','x'}, +/*EXP_EVENT*/ {'x','x','x','x','x','x','x','x','x','x','x','x','x','x'}, }; -/* FIXME: hardcoded!, this must be defined during compilation time */ char *lib_dir = CONNTRACK_LIB_DIR; LIST_HEAD(proto_list); @@ -258,6 +287,22 @@ exit_error(enum exittype status, char *msg, ...) exit(status); } +static void +generic_cmd_check(int command, int options) +{ + int i; + + for (i = 0; i < NUMBER_OF_CMD; i++) { + if (!(command & (1< %u.%u.%u.%u:%hu\n", - tp, tp->dst.protonum, - NIPQUAD(tp->src.ip), ntohs(tp->src.u.all), - NIPQUAD(tp->dst.ip), ntohs(tp->dst.u.all)); + tp, tp->protonum, + NIPQUAD(tp->src.v4), ntohs(tp->l4src.all), + NIPQUAD(tp->dst.v4), ntohs(tp->l4dst.all)); } -void not_implemented_yet() -{ - exit_error(OTHER_PROBLEM, "Sorry, not implemented yet :(\n"); -} - - #define PARSE_STATUS 0 -#define PARSE_GROUP 1 -#define PARSE_EVENT 2 -#define PARSE_DUMP 3 -#define PARSE_MAX PARSE_DUMP+1 +#define PARSE_EVENT 1 +#define PARSE_MAX 2 static struct parse_parameter { - char *parameter[10]; + char *parameter[5]; size_t size; - unsigned int value[10]; + unsigned int value[5]; } parse_array[PARSE_MAX] = { - { {"EXPECTED", "ASSURED", "SEEN_REPLY", "CONFIRMED", "SNAT", "DNAT", - "SEQ_ADJUST", "UNSET"}, - 8, - { IPS_EXPECTED, IPS_ASSURED, IPS_SEEN_REPLY, IPS_CONFIRMED, - IPS_SRC_NAT, IPS_DST_NAT, IPS_SEQ_ADJUST, 0} }, - { {"ALL", "TCP", "UDP", "ICMP"}, - 4, - {~0U, NFGRP_IPV4_CT_TCP, NFGRP_IPV4_CT_UDP, NFGRP_IPV4_CT_ICMP} }, - { {"ALL", "NEW", "RELATED", "DESTROY", "REFRESH", "STATUS", - "PROTOINFO", "HELPER", "HELPINFO", "NATINFO"}, - 10, - {~0U, IPCT_NEW, IPCT_RELATED, IPCT_DESTROY, IPCT_REFRESH, IPCT_STATUS, - IPCT_PROTOINFO, IPCT_HELPER, IPCT_HELPINFO, IPCT_NATINFO} }, - { {"ALL", "TUPLE", "STATUS", "TIMEOUT", "PROTOINFO", "HELPINFO", - "COUNTERS", "MARK"}, 8, - {~0U, DUMP_TUPLE, DUMP_STATUS, DUMP_TIMEOUT, DUMP_PROTOINFO, - DUMP_HELPINFO, DUMP_COUNTERS, DUMP_MARK} } + { {"ASSURED", "SEEN_REPLY", "UNSET", "SRC_NAT", "DST_NAT"}, 5, + { IPS_ASSURED, IPS_SEEN_REPLY, 0, + IPS_SRC_NAT_DONE, IPS_DST_NAT_DONE} }, + { {"ALL", "NEW", "UPDATES", "DESTROY"}, 4, + {~0U, NF_NETLINK_CONNTRACK_NEW, NF_NETLINK_CONNTRACK_UPDATE, + NF_NETLINK_CONNTRACK_DESTROY} }, }; static int @@ -425,6 +454,14 @@ parse_parameter(const char *arg, unsigned int *status, int parse_type) exit_error(PARAMETER_PROBLEM, "Bad parameter `%s'", arg); } +static void +add_command(int *cmd, const int newcmd, const int othercmds) +{ + if (*cmd & (~othercmds)) + exit_error(PARAMETER_PROBLEM, "Invalid commands combination\n"); + *cmd |= newcmd; +} + unsigned int check_type(int argc, char *argv[]) { char *table = NULL; @@ -515,15 +552,90 @@ int iptables_insmod(const char *modname, const char *modprobe) return -1; } +/* Shamelessly stolen from libipt_DNAT ;). Ranges expected in network order. */ +static void +nat_parse(char *arg, int portok, struct ctnl_nat *range) +{ + char *colon, *dash, *error; + unsigned long ip; + + memset(range, 0, sizeof(range)); + colon = strchr(arg, ':'); + + if (colon) { + int port; + + if (!portok) + exit_error(PARAMETER_PROBLEM, + "Need TCP or UDP with port specification"); + + port = atoi(colon+1); + if (port == 0 || port > 65535) + exit_error(PARAMETER_PROBLEM, + "Port `%s' not valid\n", colon+1); + + error = strchr(colon+1, ':'); + if (error) + exit_error(PARAMETER_PROBLEM, + "Invalid port:port syntax - use dash\n"); + + dash = strchr(colon, '-'); + if (!dash) { + range->l4min.tcp.port + = range->l4max.tcp.port + = htons(port); + } else { + int maxport; + + maxport = atoi(dash + 1); + if (maxport == 0 || maxport > 65535) + exit_error(PARAMETER_PROBLEM, + "Port `%s' not valid\n", dash+1); + if (maxport < port) + // People are stupid. + exit_error(PARAMETER_PROBLEM, + "Port range `%s' funky\n", colon+1); + range->l4min.tcp.port = htons(port); + range->l4max.tcp.port = htons(maxport); + } + // Starts with a colon? No IP info... + if (colon == arg) + return; + *colon = '\0'; + } + + dash = strchr(arg, '-'); + if (colon && dash && dash > colon) + dash = NULL; + + if (dash) + *dash = '\0'; + + ip = inet_addr(arg); + if (!ip) + exit_error(PARAMETER_PROBLEM, "Bad IP address `%s'\n", + arg); + range->min_ip = ip; + if (dash) { + ip = inet_addr(dash+1); + if (!ip) + exit_error(PARAMETER_PROBLEM, "Bad IP address `%s'\n", + dash+1); + range->max_ip = ip; + } else + range->max_ip = range->min_ip; +} + void usage(char *prog) { fprintf(stdout, "Tool to manipulate conntrack and expectations. Version %s\n", VERSION); fprintf(stdout, "Usage: %s [commands] [options]\n", prog); fprintf(stdout, "\n"); fprintf(stdout, "Commands:\n"); fprintf(stdout, "-L [table] [-z] List conntrack or expectation table\n"); -fprintf(stdout, "-G [table] parameters Get conntrack or expectation\n"); +fprintf(stdout, "-G [table] parameters Get conntrack or expectation\n"); fprintf(stdout, "-D [table] parameters Delete conntrack or expectation\n"); fprintf(stdout, "-I [table] parameters Create a conntrack or expectation\n"); +fprintf(stdout, "-U [table] parameters Update a conntrack\n"); fprintf(stdout, "-E [table] [options] Show events\n"); fprintf(stdout, "-F [table] Flush table\n"); fprintf(stdout, "-A [table] [options] Set action\n"); @@ -535,108 +647,127 @@ fprintf(stdout, "--reply-src ip Source addres from reply direction\n"); fprintf(stdout, "--reply-dst ip Destination address from reply direction\n"); fprintf(stdout, "--tuple-src ip Source address in expect tuple\n"); fprintf(stdout, "--tuple-dst ip Destination address in expect tuple\n"); -fprintf(stdout, "--mask-src ip Source mask in expect\n"); -fprintf(stdout, "--mask-dst ip Destination mask in expect\n"); +fprintf(stdout, "--mask-src ip Source mask address for expectation\n"); +fprintf(stdout, "--mask-dst ip Destination mask address for expectations\n"); fprintf(stdout, "-p proto Layer 4 Protocol\n"); fprintf(stdout, "-t timeout Set timeout\n"); fprintf(stdout, "-u status Set status\n"); fprintf(stdout, "-m dumpmask Set dump mask\n"); fprintf(stdout, "-g groupmask Set group mask\n"); fprintf(stdout, "-e eventmask Set event mask\n"); +fprintf(stdout, "-a min_ip[-max_ip] NAT ip range\n"); fprintf(stdout, "-z Zero Counters\n"); } int main(int argc, char *argv[]) { - int c; + char c; unsigned int command = 0, options = 0; - struct ip_conntrack_tuple orig, reply, tuple, mask, *o = NULL, *r = NULL; + struct ctnl_tuple orig, reply, mask, *o = NULL, *r = NULL; + struct ctnl_tuple exptuple; struct ctproto_handler *h = NULL; - union ip_conntrack_proto proto; + union ctnl_protoinfo proto; + struct ctnl_nat range; unsigned long timeout = 0; - unsigned int status = 0, group_mask = 0; + unsigned int status = IPS_CONFIRMED; unsigned long id = 0; unsigned int type = 0, dump_mask = 0, extra_flags = 0, event_mask = 0; + int manip = -1; int res = 0, retry = 2; - memset(&proto, 0, sizeof(union ip_conntrack_proto)); - memset(&orig, 0, sizeof(struct ip_conntrack_tuple)); - memset(&reply, 0, sizeof(struct ip_conntrack_tuple)); - orig.dst.dir = IP_CT_DIR_ORIGINAL; - reply.dst.dir = IP_CT_DIR_REPLY; + memset(&proto, 0, sizeof(union ctnl_protoinfo)); + memset(&orig, 0, sizeof(struct ctnl_tuple)); + memset(&reply, 0, sizeof(struct ctnl_tuple)); + memset(&mask, 0, sizeof(struct ctnl_tuple)); + memset(&range, 0, sizeof(struct ctnl_nat)); while ((c = getopt_long(argc, argv, - "L::I::D::G::E::A::F::hVs:d:r:q:p:t:u:m:g:e:z[:]:{:}:", + "L::I::U::D::G::E::A::F::hVs:d:r:q:p:t:u:e:a:z[:]:{:}:", opts, NULL)) != -1) { switch(c) { case 'L': - command |= CT_LIST; type = check_type(argc, argv); + if (type == 0) + add_command(&command, CT_LIST, CT_NONE); + else if (type == 1) + add_command(&command, EXP_LIST, CT_NONE); break; case 'I': - command |= CT_CREATE; type = check_type(argc, argv); + if (type == 0) + add_command(&command, CT_CREATE, CT_NONE); + else if (type == 1) + add_command(&command, EXP_CREATE, CT_NONE); + break; + case 'U': + type = check_type(argc, argv); + if (type == 0) + add_command(&command, CT_UPDATE, CT_NONE); + else + exit_error(PARAMETER_PROBLEM, "Can't update " + "expectations"); break; case 'D': - command |= CT_DELETE; type = check_type(argc, argv); + if (type == 0) + add_command(&command, CT_DELETE, CT_NONE); + else if (type == 1) + add_command(&command, EXP_DELETE, CT_NONE); break; case 'G': - command |= CT_GET; type = check_type(argc, argv); + if (type == 0) + add_command(&command, CT_GET, CT_NONE); + else if (type == 1) + add_command(&command, EXP_GET, CT_NONE); break; case 'F': - command |= CT_FLUSH; type = check_type(argc, argv); + if (type == 0) + add_command(&command, CT_FLUSH, CT_NONE); + else if (type == 1) + add_command(&command, EXP_FLUSH, CT_NONE); break; case 'E': - command |= CT_EVENT; - type = check_type(argc, argv); - break; - case 'A': - command |= CT_ACTION; type = check_type(argc, argv); + if (type == 0) + add_command(&command, CT_EVENT, CT_NONE); + else if (type == 1) + add_command(&command, EXP_EVENT, CT_NONE); break; case 'V': - command |= CT_VERSION; + add_command(&command, CT_VERSION, CT_NONE); break; case 'h': - command |= CT_HELP; - break; - case 'm': - if (!optarg) - continue; - - options |= CT_OPT_DUMP_MASK; - parse_parameter(optarg, &dump_mask, PARSE_DUMP); + add_command(&command, CT_HELP, CT_NONE); break; case 's': options |= CT_OPT_ORIG_SRC; if (optarg) - orig.src.ip = inet_addr(optarg); + orig.src.v4 = inet_addr(optarg); break; case 'd': options |= CT_OPT_ORIG_DST; if (optarg) - orig.dst.ip = inet_addr(optarg); + orig.dst.v4 = inet_addr(optarg); break; case 'r': options |= CT_OPT_REPL_SRC; if (optarg) - reply.src.ip = inet_addr(optarg); + reply.src.v4 = inet_addr(optarg); break; case 'q': options |= CT_OPT_REPL_DST; if (optarg) - reply.dst.ip = inet_addr(optarg); + reply.dst.v4 = inet_addr(optarg); break; case 'p': options |= CT_OPT_PROTO; h = findproto(optarg); if (!h) exit_error(PARAMETER_PROBLEM, "proto needed\n"); - orig.dst.protonum = h->protonum; - reply.dst.protonum = h->protonum; + orig.protonum = h->protonum; + reply.protonum = h->protonum; opts = merge_options(opts, h->opts, &h->option_offset); break; @@ -646,20 +777,13 @@ int main(int argc, char *argv[]) timeout = atol(optarg); break; case 'u': { - /* FIXME: NAT stuff, later... */ if (!optarg) continue; options |= CT_OPT_STATUS; parse_parameter(optarg, &status, PARSE_STATUS); - /* Just insert confirmed conntracks */ - status |= IPS_CONFIRMED; break; } - case 'g': - options |= CT_OPT_GROUP_MASK; - parse_parameter(optarg, &group_mask, PARSE_GROUP); - break; case 'e': options |= CT_OPT_EVENT_MASK; parse_parameter(optarg, &event_mask, PARSE_EVENT); @@ -667,30 +791,35 @@ int main(int argc, char *argv[]) case 'z': options |= CT_OPT_ZERO; break; - case '[': - options |= CT_OPT_TUPLE_SRC; + case 'k': + options |= CT_OPT_MASK_SRC; if (optarg) - tuple.src.ip = inet_addr(optarg); + mask.src.v4 = inet_addr(optarg); break; - case ']': - options |= CT_OPT_TUPLE_DST; + case 'l': + options |= CT_OPT_MASK_DST; if (optarg) - tuple.dst.ip = inet_addr(optarg); + mask.dst.v4 = inet_addr(optarg); break; - case '{': - options |= CT_OPT_MASK_SRC; + case 'x': + options |= CT_OPT_EXP_SRC; if (optarg) - mask.src.ip = inet_addr(optarg); + exptuple.src.v4 = inet_addr(optarg); break; - case '}': - options |= CT_OPT_MASK_DST; + case 'y': + options |= CT_OPT_EXP_DST; if (optarg) - mask.dst.ip = inet_addr(optarg); + exptuple.dst.v4 = inet_addr(optarg); + break; + case 'a': + options |= CT_OPT_NATRANGE; + nat_parse(optarg, 1, &range); break; default: - if (h && h->parse && !h->parse(c - h->option_offset, - argv, &orig, &reply, - &proto, &extra_flags)) + if (h && h->parse_opts + &&!h->parse_opts(c - h->option_offset, argv, &orig, + &reply, &mask, &proto, + &extra_flags)) exit_error(PARAMETER_PROBLEM, "parse error\n"); /* Unknown argument... */ @@ -703,10 +832,12 @@ int main(int argc, char *argv[]) } } + generic_cmd_check(command, options); generic_opt_check(command, options); if (!(command & CT_HELP) - && h && h->final_check && !h->final_check(extra_flags)) { + && h && h->final_check + && !h->final_check(extra_flags, &orig, &reply)) { usage(argv[0]); extension_help(h); exit_error(PARAMETER_PROBLEM, "Missing protocol arguments!\n"); @@ -716,71 +847,115 @@ int main(int argc, char *argv[]) retry--; switch(command) { case CT_LIST: - if (type == 0) { - if (options & CT_OPT_ZERO) - res = dump_conntrack_table(1); - else - res = dump_conntrack_table(0); - } else - res = dump_expect_list(); + if (options & CT_OPT_ZERO) + res = dump_conntrack_table(1); + else + res = dump_conntrack_table(0); + break; + + case EXP_LIST: + res = dump_expect_list(); break; case CT_CREATE: - if (type == 0) + if ((options & CT_OPT_ORIG) + && !(options & CT_OPT_REPL)) { + reply.src.v4 = orig.dst.v4; + reply.dst.v4 = orig.src.v4; + } else if (!(options & CT_OPT_ORIG) + && (options & CT_OPT_REPL)) { + orig.src.v4 = reply.dst.v4; + orig.dst.v4 = reply.src.v4; + } + if (options & CT_OPT_NATRANGE) res = create_conntrack(&orig, &reply, timeout, - &proto, status); + &proto, status, &range); else - res = create_expect(&tuple, &mask, &orig, - &reply, timeout); + res = create_conntrack(&orig, &reply, timeout, + &proto, status, NULL); + break; + + case EXP_CREATE: + if (options & CT_OPT_ORIG) + res = create_expectation(&orig, + CTA_TUPLE_ORIG, + &exptuple, + &mask, + timeout); + else if (options & CT_OPT_REPL) + res = create_expectation(&reply, + CTA_TUPLE_RPLY, + &exptuple, + &mask, + timeout); + break; + + case CT_UPDATE: + if ((options & CT_OPT_ORIG) + && !(options & CT_OPT_REPL)) { + reply.src.v4 = orig.dst.v4; + reply.dst.v4 = orig.src.v4; + } else if (!(options & CT_OPT_ORIG) + && (options & CT_OPT_REPL)) { + orig.src.v4 = reply.dst.v4; + orig.dst.v4 = reply.src.v4; + } + res = update_conntrack(&orig, &reply, timeout, + &proto, status); break; case CT_DELETE: - if (type == 0) { - if (options & CT_OPT_ORIG) - res =delete_conntrack(&orig, CTA_ORIG, - id); - else if (options & CT_OPT_REPL) - res = delete_conntrack(&reply, CTA_RPLY, - id); - } else - not_implemented_yet(); + if (options & CT_OPT_ORIG) + res = delete_conntrack(&orig, CTA_TUPLE_ORIG, + CTNL_DIR_ORIGINAL); + else if (options & CT_OPT_REPL) + res = delete_conntrack(&reply, CTA_TUPLE_RPLY, + CTNL_DIR_REPLY); break; - + + case EXP_DELETE: + if (options & CT_OPT_ORIG) + res = delete_expectation(&orig, CTA_TUPLE_ORIG); + else if (options & CT_OPT_REPL) + res = delete_expectation(&reply, CTA_TUPLE_RPLY); + break; + case CT_GET: - if (type == 0) { - if (options & CT_OPT_ORIG) - res = get_conntrack(&orig, CTA_ORIG, - id); - else if (options & CT_OPT_REPL) - res = get_conntrack(&reply, CTA_RPLY, - id); - } else - not_implemented_yet(); + if (options & CT_OPT_ORIG) + res = get_conntrack(&orig, CTA_TUPLE_ORIG, id); + else if (options & CT_OPT_REPL) + res = get_conntrack(&reply, CTA_TUPLE_RPLY, id); break; - + + case EXP_GET: + if (options & CT_OPT_ORIG) + res = get_expect(&orig, CTA_TUPLE_ORIG); + else if (options & CT_OPT_REPL) + res = get_expect(&reply, CTA_TUPLE_RPLY); + break; + case CT_FLUSH: - if (type == 0) - res = flush_conntrack(); - else - not_implemented_yet(); + res = flush_conntrack(); + break; + + case EXP_FLUSH: + res = flush_expectation(); break; case CT_EVENT: - if (type == 0) { - if (options & CT_OPT_GROUP_MASK) - res = event_conntrack(group_mask); - else - res = event_conntrack(~0U); - } else - not_implemented_yet(); - - case CT_ACTION: - if (type == 0) - if (options & CT_OPT_DUMP_MASK) - res = set_mask(dump_mask, 0); - else if (options & CT_OPT_EVENT_MASK) - res = set_mask(event_mask, 1); + if (options & CT_OPT_EVENT_MASK) + res = event_conntrack(event_mask); + else + res = event_conntrack(~0U); break; + + case EXP_EVENT: + if (options & CT_OPT_EVENT_MASK) + res = event_expectation(event_mask); + else + res = event_expectation(~0U); + break; + case CT_VERSION: fprintf(stdout, "%s v%s\n", PROGNAME, VERSION); break; diff --git a/src/libct.c b/src/libct.c index 0555ec8..94e5b24 100644 --- a/src/libct.c +++ b/src/libct.c @@ -1,5 +1,5 @@ /* - * (C) 2005 by Pablo Neira Ayuso , + * (C) 2005 by Pablo Neira Ayuso * Harald Welte * * This program is free software; you can redistribute it and/or modify @@ -11,9 +11,13 @@ #include #include #include +#include #include -#include +/* From kernel.h */ +#define INT_MAX ((int)(~0U>>1)) +#define INT_MIN (-INT_MAX - 1) #include +#include #include "libctnetlink.h" #include "libnfnetlink.h" #include "linux_list.h" @@ -25,6 +29,7 @@ #define DEBUGP #endif +static struct ctnl_handle cth; extern char *lib_dir; extern struct list_head proto_list; extern char *proto2str[]; @@ -37,89 +42,192 @@ static void print_status(unsigned int status) fprintf(stdout, "[UNREPLIED] "); } +static void parse_ip(struct nfattr *attr, struct ctnl_tuple *tuple) +{ + struct nfattr *tb[CTA_IP_MAX]; + + memset(tb, 0, CTA_IP_MAX * sizeof(struct nfattr *)); + + nfnl_parse_attr(tb, CTA_IP_MAX, NFA_DATA(attr), NFA_PAYLOAD(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 ctnl_tuple *tuple) +{ + struct nfattr *tb[CTA_PROTO_MAX]; + struct ctproto_handler *h; + int dir = CTNL_DIR_REPLY; + + memset(tb, 0, CTA_PROTO_MAX * sizeof(struct nfattr *)); + + nfnl_parse_attr(tb, CTA_IP_MAX, NFA_DATA(attr), NFA_PAYLOAD(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 ctnl_tuple *tuple) +{ + struct nfattr *tb[CTA_TUPLE_MAX]; + + memset(tb, 0, CTA_TUPLE_MAX*sizeof(struct nfattr *)); + + nfnl_parse_attr(tb, CTA_TUPLE_MAX, NFA_DATA(attr), NFA_PAYLOAD(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 ctnl_conntrack *ct) +{ + struct nfattr *tb[CTA_PROTOINFO_MAX]; + struct ctproto_handler *h; + + memset(tb, 0, CTA_PROTOINFO_MAX*sizeof(struct nfattr *)); + + nfnl_parse_attr(tb,CTA_PROTOINFO_MAX,NFA_DATA(attr), NFA_PAYLOAD(attr)); + + h = findproto(proto2str[ct->tuple[CTNL_DIR_ORIGINAL].protonum]); + if (h && h->parse_protoinfo) + h->parse_protoinfo(tb, ct); +} + +static void parse_counters(struct nfattr *attr, struct ctnl_conntrack *ct, + enum ctattr_type parent) +{ + struct nfattr *tb[CTA_COUNTERS_MAX]; + + memset(tb, 0, CTA_COUNTERS_MAX*sizeof(struct nfattr *)); + + nfnl_parse_attr(tb, CTA_COUNTERS_MAX, NFA_DATA(attr),NFA_PAYLOAD(attr)); + if (tb[CTA_COUNTERS_PACKETS_ORIG-1]) + ct->counters[CTNL_DIR_ORIGINAL].packets + = *(u_int64_t *)NFA_DATA(tb[CTA_COUNTERS_PACKETS_ORIG-1]); + if (tb[CTA_COUNTERS_BYTES_ORIG-1]) + ct->counters[CTNL_DIR_ORIGINAL].bytes + = *(u_int64_t *)NFA_DATA(tb[CTA_COUNTERS_BYTES_ORIG-1]); + if (tb[CTA_COUNTERS_PACKETS_RPLY-1]) + ct->counters[CTNL_DIR_REPLY].packets + = *(u_int64_t *)NFA_DATA(tb[CTA_COUNTERS_PACKETS_RPLY-1]); + if (tb[CTA_COUNTERS_BYTES_RPLY-1]) + ct->counters[CTNL_DIR_REPLY].bytes + = *(u_int64_t *)NFA_DATA(tb[CTA_COUNTERS_BYTES_RPLY-1]); +} + +#define STATUS 1 +#define PROTOINFO 2 +#define TIMEOUT 4 +#define MARK 8 +#define COUNTERS 16 +#define USE 32 + static int handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void *arg) { struct nfgenmsg *nfmsg; struct nfattr *nfa; - int min_len = 0; + int min_len = sizeof(struct nfgenmsg);; struct ctproto_handler *h = NULL; struct nfattr *attr = NFM_NFA(NLMSG_DATA(nlh)); int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); + struct ctnl_conntrack ct; + unsigned int flags = 0; - struct ip_conntrack_tuple *orig, *reply; - struct cta_counters *ctr; - unsigned long *status, *timeout; - struct cta_proto *proto; - unsigned long *id, *mark; - - DEBUGP("netlink header\n"); - DEBUGP("len: %d type: %d flags: %d seq: %d pid: %d\n", - nlh->nlmsg_len, nlh->nlmsg_type, nlh->nlmsg_flags, - nlh->nlmsg_seq, nlh->nlmsg_pid); + memset(&ct, 0, sizeof(struct ctnl_conntrack)); nfmsg = NLMSG_DATA(nlh); - DEBUGP("nfmsg->nfgen_family: %d\n", nfmsg->nfgen_family); +// min_len = sizeof(struct nfgenmsg); - min_len = sizeof(struct nfgenmsg); if (nlh->nlmsg_len < min_len) return -EINVAL; - DEBUGP("size:%d\n", nlh->nlmsg_len); - while (NFA_OK(attr, attrlen)) { switch(attr->nfa_type) { - case CTA_ORIG: - orig = NFA_DATA(attr); - fprintf(stdout, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ", - NIPQUAD(orig->src.ip), - NIPQUAD(orig->dst.ip)); - h = findproto(proto2str[orig->dst.protonum]); - if (h && h->print_tuple) - h->print_tuple(orig); + case CTA_TUPLE_ORIG: + parse_tuple(attr, &ct.tuple[CTNL_DIR_ORIGINAL]); break; - case CTA_RPLY: - reply = NFA_DATA(attr); - fprintf(stdout, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ", - NIPQUAD(reply->src.ip), - NIPQUAD(reply->dst.ip)); - h = findproto(proto2str[reply->dst.protonum]); - if (h && h->print_tuple) - h->print_tuple(reply); + case CTA_TUPLE_RPLY: + parse_tuple(attr, &ct.tuple[CTNL_DIR_REPLY]); break; case CTA_STATUS: - status = NFA_DATA(attr); - print_status(*status); + ct.status = *(unsigned int *)NFA_DATA(attr); + flags |= STATUS; break; case CTA_PROTOINFO: - proto = NFA_DATA(attr); - if (proto2str[proto->num_proto]) { - fprintf(stdout, "%s %d ", proto2str[proto->num_proto], proto->num_proto); - h = findproto(proto2str[proto->num_proto]); - if (h && h->print_proto) - h->print_proto(&proto->proto); - } else - fprintf(stdout, "unknown %d ", proto->num_proto); + parse_protoinfo(attr, &ct); + flags |= PROTOINFO; break; case CTA_TIMEOUT: - timeout = NFA_DATA(attr); - fprintf(stdout, "timeout=%lu ", *timeout); + ct.timeout = *(unsigned long *)NFA_DATA(attr); + flags |= TIMEOUT; break; case CTA_MARK: - mark = NFA_DATA(attr); - fprintf(stdout, "mark=%lu ", *mark); + ct.mark = *(unsigned long *)NFA_DATA(attr); + flags |= MARK; break; case CTA_COUNTERS: - ctr = NFA_DATA(attr); - fprintf(stdout, "orig_packets=%llu orig_bytes=%llu, " - "reply_packets=%llu reply_bytes=%llu ", - ctr->orig.packets, ctr->orig.bytes, - ctr->reply.packets, ctr->reply.bytes); + parse_counters(attr, &ct, CTA_COUNTERS-1); + flags |= COUNTERS; + break; + case CTA_USE: + ct.use = *(unsigned int *)NFA_DATA(attr); + flags |= USE; break; } - DEBUGP("nfa->nfa_type: %d\n", attr->nfa_type); - DEBUGP("nfa->nfa_len: %d\n", attr->nfa_len); attr = NFA_NEXT(attr, attrlen); } + + fprintf(stdout, "%-8s %u ", + proto2str[ct.tuple[CTNL_DIR_ORIGINAL].protonum] == NULL ? + "unknown" : proto2str[ct.tuple[CTNL_DIR_ORIGINAL].protonum], + ct.tuple[CTNL_DIR_ORIGINAL].protonum); + + if (flags & TIMEOUT) + fprintf(stdout, "%lu ", ct.timeout); + + h = findproto(proto2str[ct.tuple[CTNL_DIR_ORIGINAL].protonum]); + if ((flags & PROTOINFO) && h && h->print_protoinfo) + h->print_protoinfo(&ct.protoinfo); + + fprintf(stdout, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ", + NIPQUAD(ct.tuple[CTNL_DIR_ORIGINAL].src.v4), + NIPQUAD(ct.tuple[CTNL_DIR_ORIGINAL].dst.v4)); + + if (h && h->print_proto) + h->print_proto(&ct.tuple[CTNL_DIR_ORIGINAL]); + + if (flags & COUNTERS) + fprintf(stdout, "packets=%llu bytes=%llu ", + ct.counters[CTNL_DIR_ORIGINAL].packets, + ct.counters[CTNL_DIR_ORIGINAL].bytes); + + fprintf(stdout, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ", + NIPQUAD(ct.tuple[CTNL_DIR_REPLY].src.v4), + NIPQUAD(ct.tuple[CTNL_DIR_REPLY].dst.v4)); + + h = findproto(proto2str[ct.tuple[CTNL_DIR_ORIGINAL].protonum]); + if (h && h->print_proto) + h->print_proto(&ct.tuple[CTNL_DIR_REPLY]); + + if (flags & COUNTERS) + fprintf(stdout, "packets=%llu bytes=%llu ", + ct.counters[CTNL_DIR_REPLY].packets, + ct.counters[CTNL_DIR_REPLY].bytes); + + print_status(ct.status); + + if (flags & MARK) + fprintf(stdout, "mark=%lu ", ct.mark); + if (flags & USE) + fprintf(stdout, "use=%u ", ct.use); + fprintf(stdout, "\n"); return 0; @@ -148,140 +256,133 @@ static int event_handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, return handler(sock, nlh, arg); } +void parse_expect(struct nfattr *attr, struct ctnl_tuple *tuple, + struct ctnl_tuple *mask, unsigned long *timeout) +{ + struct nfattr *tb[CTA_EXPECT_MAX]; + + memset(tb, 0, CTA_EXPECT_MAX*sizeof(struct nfattr *)); + + nfnl_parse_attr(tb, CTA_EXPECT_MAX, NFA_DATA(attr), NFA_PAYLOAD(attr)); + if (tb[CTA_EXPECT_TUPLE-1]) + parse_tuple(tb[CTA_EXPECT_TUPLE-1], tuple); + if (tb[CTA_EXPECT_MASK-1]) + parse_tuple(tb[CTA_EXPECT_MASK-1], mask); + if (tb[CTA_EXPECT_TIMEOUT-1]) + *timeout = *(unsigned long *)NFA_DATA(tb[CTA_EXPECT_TIMEOUT-1]); +} + static int expect_handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void *arg) { struct nfgenmsg *nfmsg; struct nfattr *nfa; - int min_len = 0; + int min_len = sizeof(struct nfgenmsg);; struct ctproto_handler *h = NULL; struct nfattr *attr = NFM_NFA(NLMSG_DATA(nlh)); int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); + struct ctnl_tuple tuple, mask; + unsigned long timeout = 0; - struct ip_conntrack_tuple *exp, *mask; - unsigned long *timeout; - - DEBUGP("netlink header\n"); - DEBUGP("len: %d type: %d flags: %d seq: %d pid: %d\n", - nlh->nlmsg_len, nlh->nlmsg_type, nlh->nlmsg_flags, - nlh->nlmsg_seq, nlh->nlmsg_pid); + memset(&tuple, 0, sizeof(struct ctnl_tuple)); + memset(&mask, 0, sizeof(struct ctnl_tuple)); nfmsg = NLMSG_DATA(nlh); - DEBUGP("nfmsg->nfgen_family: %d\n", nfmsg->nfgen_family); - min_len = sizeof(struct nfgenmsg); if (nlh->nlmsg_len < min_len) return -EINVAL; - DEBUGP("size:%d\n", nlh->nlmsg_len); - while (NFA_OK(attr, attrlen)) { switch(attr->nfa_type) { - case CTA_EXP_TUPLE: - exp = NFA_DATA(attr); - fprintf(stdout, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ", - NIPQUAD(exp->src.ip), - NIPQUAD(exp->dst.ip)); - h = findproto(proto2str[exp->dst.protonum]); - if (h && h->print_tuple) - h->print_tuple(exp); - break; - case CTA_EXP_MASK: - mask = NFA_DATA(attr); - fprintf(stdout, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ", - NIPQUAD(mask->src.ip), - NIPQUAD(mask->dst.ip)); - h = findproto(proto2str[mask->dst.protonum]); - if (h && h->print_tuple) - h->print_tuple(mask); - break; - case CTA_EXP_TIMEOUT: - timeout = NFA_DATA(attr); - fprintf(stdout, "timeout:%lu ", *timeout); - break; + case CTA_EXPECT: + parse_expect(attr, &tuple, &mask, &timeout); + break; } - DEBUGP("nfa->nfa_type: %d\n", attr->nfa_type); - DEBUGP("nfa->nfa_len: %d\n", attr->nfa_len); attr = NFA_NEXT(attr, attrlen); } - fprintf(stdout, "\n"); + fprintf(stdout, "%ld proto=%d ", timeout, tuple.protonum); + + fprintf(stdout, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ", + NIPQUAD(tuple.src.v4), + NIPQUAD(tuple.dst.v4)); + + fprintf(stdout, "src=%u.%u.%u.%u dst=%u.%u.%u.%u\n", + NIPQUAD(mask.src.v4), + NIPQUAD(mask.dst.v4)); return 0; } -int create_conntrack(struct ip_conntrack_tuple *orig, - struct ip_conntrack_tuple *reply, +int create_conntrack(struct ctnl_tuple *orig, + struct ctnl_tuple *reply, unsigned long timeout, - union ip_conntrack_proto *proto, - unsigned int status) + union ctnl_protoinfo *proto, + unsigned int status, + struct ctnl_nat *range) { - struct cta_proto cta; - struct nfattr *cda[CTA_MAX]; - struct ctnl_handle cth; + struct ctnl_conntrack ct; int ret; + + memset(&ct, 0, sizeof(struct ctnl_conntrack)); + ct.tuple[CTNL_DIR_ORIGINAL] = *orig; + ct.tuple[CTNL_DIR_REPLY] = *reply; + ct.timeout = timeout; + ct.status = status; + ct.protoinfo = *proto; + if (range) + ct.nat = *range; - cta.num_proto = orig->dst.protonum; - memcpy(&cta.proto, proto, sizeof(*proto)); if ((ret = ctnl_open(&cth, 0)) < 0) return ret; - if ((ret = ctnl_new_conntrack(&cth, orig, reply, timeout, &cta, - status)) < 0) - return ret; + ret = ctnl_new_conntrack(&cth, &ct); - if ((ret = ctnl_close(&cth)) < 0) - return ret; + ctnl_close(&cth); - return 0; + return ret; } -int create_expect(struct ip_conntrack_tuple *tuple, - struct ip_conntrack_tuple *mask, - struct ip_conntrack_tuple *master_tuple_orig, - struct ip_conntrack_tuple *master_tuple_reply, - unsigned long timeout) +int update_conntrack(struct ctnl_tuple *orig, + struct ctnl_tuple *reply, + unsigned long timeout, + union ctnl_protoinfo *proto, + unsigned int status) { - struct ctnl_handle cth; + struct ctnl_conntrack ct; int ret; + memset(&ct, 0, sizeof(struct ctnl_conntrack)); + ct.tuple[CTNL_DIR_ORIGINAL] = *orig; + ct.tuple[CTNL_DIR_REPLY] = *reply; + ct.timeout = timeout; + ct.status = status; + ct.protoinfo = *proto; + if ((ret = ctnl_open(&cth, 0)) < 0) return ret; - if ((ret = ctnl_new_expect(&cth, tuple, mask, master_tuple_orig, - master_tuple_reply, timeout)) < 0) - return ret; - - if ((ret = ctnl_close(&cth)) < 0) - return ret; + ret = ctnl_upd_conntrack(&cth, &ct); - return -1; + ctnl_close(&cth); + + return ret; } -int delete_conntrack(struct ip_conntrack_tuple *tuple, - enum ctattr_type_t t) +int delete_conntrack(struct ctnl_tuple *tuple, int dir) { - struct nfattr *cda[CTA_MAX]; - struct ctnl_handle cth; int ret; if ((ret = ctnl_open(&cth, 0)) < 0) return ret; - if ((ret = ctnl_del_conntrack(&cth, tuple, t)) < 0) - return ret; - - if ((ret = ctnl_close(&cth)) < 0) - return ret; + ret = ctnl_del_conntrack(&cth, tuple, dir); + ctnl_close(&cth); - return 0; + return ret; } /* get_conntrack_handler */ -int get_conntrack(struct ip_conntrack_tuple *tuple, - enum ctattr_type_t t, - unsigned long id) +int get_conntrack(struct ctnl_tuple *tuple, int dir) { - struct nfattr *cda[CTA_MAX]; - struct ctnl_handle cth; struct ctnl_msg_handler h = { .type = 0, .handler = handler @@ -293,22 +394,17 @@ int get_conntrack(struct ip_conntrack_tuple *tuple, ctnl_register_handler(&cth, &h); - /* FIXME!!!! get_conntrack_handler returns -100 */ - if ((ret = ctnl_get_conntrack(&cth, tuple, t)) != -100) - return ret; - - if ((ret = ctnl_close(&cth)) < 0) - return ret; + ret = ctnl_get_conntrack(&cth, tuple, dir); + ctnl_close(&cth); - return 0; + return ret; } int dump_conntrack_table(int zero) { int ret; - struct ctnl_handle cth; struct ctnl_msg_handler h = { - .type = 0, /* Hm... really? */ + .type = IPCTNL_MSG_CT_NEW, /* Hm... really? */ .handler = handler }; @@ -322,38 +418,37 @@ int dump_conntrack_table(int zero) } else ret = ctnl_list_conntrack(&cth, AF_INET); - if (ret != -100) - return ret; + ctnl_close(&cth); - if ((ret = ctnl_close(&cth)) < 0) - return ret; + return ret; +} - return 0; +static void event_sighandler(int s) +{ + fprintf(stdout, "Now closing conntrack event dumping...\n"); + ctnl_close(&cth); } int event_conntrack(unsigned int event_mask) { - struct ctnl_handle cth; struct ctnl_msg_handler hnew = { - .type = 0, /* new */ + .type = IPCTNL_MSG_CT_NEW, .handler = event_handler }; struct ctnl_msg_handler hdestroy = { - .type = 2, /* destroy */ + .type = IPCTNL_MSG_CT_DELETE, .handler = event_handler }; int ret; - + if ((ret = ctnl_open(&cth, event_mask)) < 0) return ret; + signal(SIGINT, event_sighandler); ctnl_register_handler(&cth, &hnew); ctnl_register_handler(&cth, &hdestroy); - if ((ret = ctnl_event_conntrack(&cth, AF_INET)) < 0) - return ret; - - if ((ret = ctnl_close(&cth)) < 0) - return ret; + ret = ctnl_event_conntrack(&cth, AF_INET); + ctnl_close(&cth); return 0; } @@ -404,9 +499,8 @@ void unregister_proto(struct ctproto_handler *h) int dump_expect_list() { - struct ctnl_handle cth; struct ctnl_msg_handler h = { - .type = 5, /* Hm... really? */ + .type = IPCTNL_MSG_EXP_NEW, .handler = expect_handler }; int ret; @@ -416,58 +510,114 @@ int dump_expect_list() ctnl_register_handler(&cth, &h); - if ((ret = ctnl_list_expect(&cth, AF_INET)) != -100) - return ret; + ret = ctnl_list_expect(&cth, AF_INET); + ctnl_close(&cth); + + return ret; +} - if ((ret = ctnl_close(&cth)) < 0) +int flush_conntrack() +{ + int ret; + + if ((ret = ctnl_open(&cth, 0)) < 0) return ret; - return 0; + ret = ctnl_flush_conntrack(&cth); + ctnl_close(&cth); + + return ret; } -int set_mask(unsigned int mask, int type) +int get_expect(struct ctnl_tuple *tuple, + enum ctattr_type t) { - struct ctnl_handle cth; - enum ctattr_type_t cta_type; + /* + struct ctnl_msg_handler h = { + .type = IPCTNL_MSG_EXP_NEW, + .handler = expect_handler + }; int ret; - switch(type) { - case 0: - cta_type = CTA_DUMPMASK; - break; - case 1: - cta_type = CTA_EVENTMASK; - break; - default: - /* Shouldn't happen */ - return -1; - } + if ((ret = ctnl_open(&cth, 0)) < 0) + return 0; + + ctnl_register_handler(&cth, &h); + + ret = ctnl_get_expect(&cth, tuple, t); + ctnl_close(&cth); + + return ret; + */ +} +int create_expectation(struct ctnl_tuple *tuple, + enum ctattr_type t, + struct ctnl_tuple *exptuple, + struct ctnl_tuple *mask, + unsigned long timeout) +{ + /* + int ret; + if ((ret = ctnl_open(&cth, 0)) < 0) return ret; + + ret = ctnl_new_expect(&cth, tuple, t, exptuple, mask, timeout); + ctnl_close(&cth); + + return ret; + */ +} + +int delete_expectation(struct ctnl_tuple *tuple, enum ctattr_type t) +{ + /* + int ret; - if ((ret = ctnl_set_mask(&cth, mask, cta_type)) < 0) + if ((ret = ctnl_open(&cth, 0)) < 0) return ret; + + ret = ctnl_del_expect(&cth, tuple, t); + ctnl_close(&cth); + + return ret; + */ +} + +int event_expectation(unsigned int event_mask) +{ + struct ctnl_msg_handler hnew = { + .type = IPCTNL_MSG_EXP_NEW, + .handler = expect_handler + }; + struct ctnl_msg_handler hdestroy = { + .type = IPCTNL_MSG_EXP_DELETE, + .handler = expect_handler + }; + int ret; - if ((ret = ctnl_close(&cth)) < 0) + if ((ret = ctnl_open(&cth, event_mask)) < 0) return ret; - return 0; + ctnl_register_handler(&cth, &hnew); + ctnl_register_handler(&cth, &hdestroy); + ret = ctnl_event_expect(&cth, AF_INET); + ctnl_close(&cth); + + return ret; } -int flush_conntrack() +int flush_expectation() { - struct ctnl_handle cth; int ret; if ((ret = ctnl_open(&cth, 0)) < 0) return ret; - if ((ret = ctnl_flush_conntrack(&cth)) < 0) - return ret; + ret = ctnl_flush_expect(&cth); + ctnl_close(&cth); - if ((ret = ctnl_close(&cth)) < 0) - return ret; - - return 0; + return ret; } + diff --git a/test.sh b/test.sh index 5999a8f..08c840f 100644 --- a/test.sh +++ b/test.sh @@ -2,27 +2,17 @@ CONNTRACK=conntrack SRC=1.1.1.1 DST=2.2.2.2 -SPORT=1980 -DPORT=2005 +SPORT=2005 +DPORT=21 case $1 in dump) - # Setting dump mask - echo "dump mask set to TUPLE" - $CONNTRACK -A -m TUPLE + echo "Dumping conntrack table" $CONNTRACK -L - echo "Press any key to continue..." - read - echo "dump mask set to TUPLE,COUNTERS" - $CONNTRACK -A -m TUPLE,COUNTERS - $CONNTRACK -L - echo "Press any key to continue..." - read - echo "dump mask set to ALL" - $CONNTRACK -A -m ALL - $CONNTRACK -L - echo "Press any key to continue..." - read + ;; + flush) + echo "Flushing conntrack table" + $CONNTRACK -F ;; new) echo "creating a new conntrack" @@ -32,6 +22,18 @@ case $1 in --reply-port-src $DPORT --reply-port-dst $SPORT \ --state LISTEN -u SEEN_REPLY -t 50 ;; + new-simple) + echo "creating a new conntrack (simplified)" + $CONNTRACK -I --orig-src $SRC --orig-dst $DST \ + -p tcp --orig-port-src $SPORT --orig-port-dst $DPORT \ + --state LISTEN -u SEEN_REPLY -t 50 + ;; + new-nat) + echo "creating a new conntrack (NAT)" + $CONNTRACK -I --orig-src $SRC --orig-dst $DST \ + -p tcp --orig-port-src $SPORT --orig-port-dst $DPORT \ + --state LISTEN -u SEEN_REPLY,SRC_NAT -t 50 -a 8.8.8.8 + ;; get) echo "getting a conntrack" $CONNTRACK -G --orig-src $SRC --orig-dst $DST \ @@ -40,7 +42,7 @@ case $1 in ;; change) echo "change a conntrack" - $CONNTRACK -I --orig-src $SRC --orig-dst $DST \ + $CONNTRACK -U --orig-src $SRC --orig-dst $DST \ --reply-src $DST --reply-dst $SRC -p tcp \ --orig-port-src $SPORT --orig-port-dst $DPORT \ --reply-port-src $DPORT --reply-port-dst $SPORT \ @@ -64,7 +66,44 @@ case $1 in fi fi ;; + dump-expect) + $CONNTRACK -L expect + ;; + flush-expect) + $CONNTRACK -F expect + ;; + create-expect) + # requires modprobe ip_conntrack_ftp + $CONNTRACK -I expect --orig-src $SRC --orig-dst $DST \ + --exp-src 4.4.4.4 --exp-dst 5.5.5.5 \ + --mask-src 255.255.255.0 --mask-dst 255.255.255.255 \ + -p tcp --orig-port-src $SPORT --orig-port-dst $DPORT \ + -t 200 --mask-port-src 10 --mask-port-dst 300 + ;; + get-expect) + $CONNTRACK -G expect --orig-src 4.4.4.4 --orig-dst 5.5.5.5 \ + --p tcp --orig-port-src 0 --orig-port-dst 0 \ + --mask-port-src 10 --mask-port-dst 11 + ;; + delete-expect) + $CONNTRACK -D expect --orig-src 4.4.4.4 \ + --orig-dst 5.5.5.5 -p tcp --orig-port-src 0 \ + --orig-port-dst 0 --mask-port-src 10 --mask-port-dst 11 + ;; *) - echo "Usage: $0 [dump|new|change|delete|output]" + echo "Usage: $0 [dump" + echo " |new" + echo " |new-simple" + echo " |new-nat" + echo " |get" + echo " |change" + echo " |delete" + echo " |output" + echo " |flush" + echo " |dump-expect" + echo " |flush-expect" + echo " |create-expect" + echo " |get-expect" + echo " |delete-expect]" ;; esac -- cgit v1.2.3 From 7ec2f918a384e62ca5b0a62e204d1fbe882718d7 Mon Sep 17 00:00:00 2001 From: "/C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=laforge/emailAddress=laforge@netfilter.org" Date: Fri, 22 Jul 2005 07:40:26 +0000 Subject: major re-sync with current names/definitions in libctnetlink and kernel --- extensions/libct_proto_icmp.c | 19 +++++++++++++- extensions/libct_proto_sctp.c | 9 ++++--- extensions/libct_proto_tcp.c | 9 ++++--- extensions/libct_proto_udp.c | 8 +++--- src/conntrack.c | 12 ++++----- src/libct.c | 60 ++++++++++++++++++++++++++----------------- 6 files changed, 75 insertions(+), 42 deletions(-) (limited to 'src') diff --git a/extensions/libct_proto_icmp.c b/extensions/libct_proto_icmp.c index 24d3d3f..e0de27e 100644 --- a/extensions/libct_proto_icmp.c +++ b/extensions/libct_proto_icmp.c @@ -1,5 +1,6 @@ /* * (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 @@ -68,6 +69,21 @@ int parse(char c, char *argv[], return 1; } +void parse_proto(struct nfattr *cda[], struct ctnl_tuple *tuple) +{ + if (cda[CTA_PROTO_ICMP_TYPE-1]) + tuple->l4dst.icmp.type = + *(u_int8_t *)NFA_DATA(cda[CTA_PROTO_ICMP_TYPE-1]); + + if (cda[CTA_PROTO_ICMP_CODE-1]) + tuple->l4dst.icmp.code = + *(u_int8_t *)NFA_DATA(cda[CTA_PROTO_ICMP_CODE-1]); + + if (cda[CTA_PROTO_ICMP_ID-1]) + tuple->l4src.icmp.id = + *(u_int8_t *)NFA_DATA(cda[CTA_PROTO_ICMP_ID-1]); +} + int final_check(unsigned int flags, struct ctnl_tuple *orig, struct ctnl_tuple *reply) @@ -82,7 +98,7 @@ int final_check(unsigned int flags, void print_proto(struct ctnl_tuple *t) { - fprintf(stdout, "type=%d code=%d id=%d", t->l4dst.icmp.type, + fprintf(stdout, "type=%d code=%d id=%d ", t->l4dst.icmp.type, t->l4dst.icmp.code, t->l4src.icmp.id); } @@ -91,6 +107,7 @@ static struct ctproto_handler icmp = { .name = "icmp", .protonum = 1, .parse_opts = parse, + .parse_proto = parse_proto, .print_proto = print_proto, .final_check = final_check, .help = help, diff --git a/extensions/libct_proto_sctp.c b/extensions/libct_proto_sctp.c index 5b50fbc..d5ff298 100644 --- a/extensions/libct_proto_sctp.c +++ b/extensions/libct_proto_sctp.c @@ -10,6 +10,7 @@ #include #include #include +#include #include /* For htons */ #include #include "libct_proto.h" @@ -138,12 +139,12 @@ int final_check(unsigned int flags, void parse_proto(struct nfattr *cda[], struct ctnl_tuple *tuple) { - if (cda[CTA_PROTO_SCTP_SRC-1]) + if (cda[CTA_PROTO_SRC_PORT-1]) tuple->l4src.sctp.port = - *(u_int16_t *)NFA_DATA(cda[CTA_PROTO_SCTP_SRC-1]); - if (cda[CTA_PROTO_SCTP_DST-1]) + *(u_int16_t *)NFA_DATA(cda[CTA_PROTO_SRC_PORT-1]); + if (cda[CTA_PROTO_DST_PORT-1]) tuple->l4dst.sctp.port = - *(u_int16_t *)NFA_DATA(cda[CTA_PROTO_SCTP_DST-1]); + *(u_int16_t *)NFA_DATA(cda[CTA_PROTO_DST_PORT-1]); } void parse_protoinfo(struct nfattr *cda[], struct ctnl_conntrack *ct) diff --git a/extensions/libct_proto_tcp.c b/extensions/libct_proto_tcp.c index 5fa3652..973c5ab 100644 --- a/extensions/libct_proto_tcp.c +++ b/extensions/libct_proto_tcp.c @@ -10,6 +10,7 @@ #include #include #include +#include #include /* For htons */ #include #include "libct_proto.h" @@ -160,12 +161,12 @@ int final_check(unsigned int flags, void parse_proto(struct nfattr *cda[], struct ctnl_tuple *tuple) { - if (cda[CTA_PROTO_TCP_SRC-1]) + if (cda[CTA_PROTO_SRC_PORT-1]) tuple->l4src.tcp.port = - *(u_int16_t *)NFA_DATA(cda[CTA_PROTO_TCP_SRC-1]); - if (cda[CTA_PROTO_TCP_DST-1]) + *(u_int16_t *)NFA_DATA(cda[CTA_PROTO_SRC_PORT-1]); + if (cda[CTA_PROTO_DST_PORT-1]) tuple->l4dst.tcp.port = - *(u_int16_t *)NFA_DATA(cda[CTA_PROTO_TCP_DST-1]); + *(u_int16_t *)NFA_DATA(cda[CTA_PROTO_DST_PORT-1]); } void parse_protoinfo(struct nfattr *cda[], struct ctnl_conntrack *ct) diff --git a/extensions/libct_proto_udp.c b/extensions/libct_proto_udp.c index aa733f0..7821d5b 100644 --- a/extensions/libct_proto_udp.c +++ b/extensions/libct_proto_udp.c @@ -127,12 +127,12 @@ int final_check(unsigned int flags, void parse_proto(struct nfattr *cda[], struct ctnl_tuple *tuple) { - if (cda[CTA_PROTO_UDP_SRC-1]) + if (cda[CTA_PROTO_SRC_PORT-1]) tuple->l4src.udp.port = - *(u_int16_t *)NFA_DATA(cda[CTA_PROTO_UDP_SRC-1]); - if (cda[CTA_PROTO_UDP_DST-1]) + *(u_int16_t *)NFA_DATA(cda[CTA_PROTO_SRC_PORT-1]); + if (cda[CTA_PROTO_DST_PORT-1]) tuple->l4dst.udp.port = - *(u_int16_t *)NFA_DATA(cda[CTA_PROTO_UDP_DST-1]); + *(u_int16_t *)NFA_DATA(cda[CTA_PROTO_DST_PORT-1]); } void print_proto(struct ctnl_tuple *tuple) diff --git a/src/conntrack.c b/src/conntrack.c index a6efd8b..2a8fa87 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -455,7 +455,7 @@ parse_parameter(const char *arg, unsigned int *status, int parse_type) } static void -add_command(int *cmd, const int newcmd, const int othercmds) +add_command(unsigned int *cmd, const int newcmd, const int othercmds) { if (*cmd & (~othercmds)) exit_error(PARAMETER_PROBLEM, "Invalid commands combination\n"); @@ -884,7 +884,7 @@ int main(int argc, char *argv[]) timeout); else if (options & CT_OPT_REPL) res = create_expectation(&reply, - CTA_TUPLE_RPLY, + CTA_TUPLE_REPLY, &exptuple, &mask, timeout); @@ -909,7 +909,7 @@ int main(int argc, char *argv[]) res = delete_conntrack(&orig, CTA_TUPLE_ORIG, CTNL_DIR_ORIGINAL); else if (options & CT_OPT_REPL) - res = delete_conntrack(&reply, CTA_TUPLE_RPLY, + res = delete_conntrack(&reply, CTA_TUPLE_REPLY, CTNL_DIR_REPLY); break; @@ -917,21 +917,21 @@ int main(int argc, char *argv[]) if (options & CT_OPT_ORIG) res = delete_expectation(&orig, CTA_TUPLE_ORIG); else if (options & CT_OPT_REPL) - res = delete_expectation(&reply, CTA_TUPLE_RPLY); + res = delete_expectation(&reply, CTA_TUPLE_REPLY); break; case CT_GET: if (options & CT_OPT_ORIG) res = get_conntrack(&orig, CTA_TUPLE_ORIG, id); else if (options & CT_OPT_REPL) - res = get_conntrack(&reply, CTA_TUPLE_RPLY, id); + res = get_conntrack(&reply, CTA_TUPLE_REPLY, id); break; case EXP_GET: if (options & CT_OPT_ORIG) res = get_expect(&orig, CTA_TUPLE_ORIG); else if (options & CT_OPT_REPL) - res = get_expect(&reply, CTA_TUPLE_RPLY); + res = get_expect(&reply, CTA_TUPLE_REPLY); break; case CT_FLUSH: diff --git a/src/libct.c b/src/libct.c index 94e5b24..245c584 100644 --- a/src/libct.c +++ b/src/libct.c @@ -13,11 +13,12 @@ #include #include #include +#include /* From kernel.h */ #define INT_MAX ((int)(~0U>>1)) #define INT_MIN (-INT_MAX - 1) #include -#include +#include #include "libctnetlink.h" #include "libnfnetlink.h" #include "linux_list.h" @@ -48,7 +49,7 @@ static void parse_ip(struct nfattr *attr, struct ctnl_tuple *tuple) memset(tb, 0, CTA_IP_MAX * sizeof(struct nfattr *)); - nfnl_parse_attr(tb, CTA_IP_MAX, NFA_DATA(attr), NFA_PAYLOAD(attr)); + 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]); @@ -64,7 +65,7 @@ static void parse_proto(struct nfattr *attr, struct ctnl_tuple *tuple) memset(tb, 0, CTA_PROTO_MAX * sizeof(struct nfattr *)); - nfnl_parse_attr(tb, CTA_IP_MAX, NFA_DATA(attr), NFA_PAYLOAD(attr)); + nfnl_parse_nested(tb, CTA_IP_MAX, attr); if (tb[CTA_PROTO_NUM-1]) tuple->protonum = *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_NUM-1]); @@ -79,7 +80,7 @@ static void parse_tuple(struct nfattr *attr, struct ctnl_tuple *tuple) memset(tb, 0, CTA_TUPLE_MAX*sizeof(struct nfattr *)); - nfnl_parse_attr(tb, CTA_TUPLE_MAX, NFA_DATA(attr), NFA_PAYLOAD(attr)); + 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]) @@ -93,7 +94,7 @@ static void parse_protoinfo(struct nfattr *attr, struct ctnl_conntrack *ct) memset(tb, 0, CTA_PROTOINFO_MAX*sizeof(struct nfattr *)); - nfnl_parse_attr(tb,CTA_PROTOINFO_MAX,NFA_DATA(attr), NFA_PAYLOAD(attr)); + nfnl_parse_nested(tb,CTA_PROTOINFO_MAX, attr); h = findproto(proto2str[ct->tuple[CTNL_DIR_ORIGINAL].protonum]); if (h && h->parse_protoinfo) @@ -107,27 +108,23 @@ static void parse_counters(struct nfattr *attr, struct ctnl_conntrack *ct, memset(tb, 0, CTA_COUNTERS_MAX*sizeof(struct nfattr *)); - nfnl_parse_attr(tb, CTA_COUNTERS_MAX, NFA_DATA(attr),NFA_PAYLOAD(attr)); - if (tb[CTA_COUNTERS_PACKETS_ORIG-1]) + nfnl_parse_nested(tb, CTA_COUNTERS_MAX, attr); + if (tb[CTA_COUNTERS_PACKETS-1]) ct->counters[CTNL_DIR_ORIGINAL].packets - = *(u_int64_t *)NFA_DATA(tb[CTA_COUNTERS_PACKETS_ORIG-1]); - if (tb[CTA_COUNTERS_BYTES_ORIG-1]) + = *(u_int64_t *)NFA_DATA(tb[CTA_COUNTERS_PACKETS-1]); + if (tb[CTA_COUNTERS_BYTES-1]) ct->counters[CTNL_DIR_ORIGINAL].bytes - = *(u_int64_t *)NFA_DATA(tb[CTA_COUNTERS_BYTES_ORIG-1]); - if (tb[CTA_COUNTERS_PACKETS_RPLY-1]) - ct->counters[CTNL_DIR_REPLY].packets - = *(u_int64_t *)NFA_DATA(tb[CTA_COUNTERS_PACKETS_RPLY-1]); - if (tb[CTA_COUNTERS_BYTES_RPLY-1]) - ct->counters[CTNL_DIR_REPLY].bytes - = *(u_int64_t *)NFA_DATA(tb[CTA_COUNTERS_BYTES_RPLY-1]); + = *(u_int64_t *)NFA_DATA(tb[CTA_COUNTERS_BYTES-1]); } +/* Some people seem to like counting in decimal... */ #define STATUS 1 #define PROTOINFO 2 #define TIMEOUT 4 #define MARK 8 #define COUNTERS 16 #define USE 32 +#define ID 64 static int handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void *arg) { @@ -153,7 +150,7 @@ static int handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void *arg) case CTA_TUPLE_ORIG: parse_tuple(attr, &ct.tuple[CTNL_DIR_ORIGINAL]); break; - case CTA_TUPLE_RPLY: + case CTA_TUPLE_REPLY: parse_tuple(attr, &ct.tuple[CTNL_DIR_REPLY]); break; case CTA_STATUS: @@ -172,14 +169,19 @@ static int handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void *arg) ct.mark = *(unsigned long *)NFA_DATA(attr); flags |= MARK; break; - case CTA_COUNTERS: - parse_counters(attr, &ct, CTA_COUNTERS-1); + case CTA_COUNTERS_ORIG: + case CTA_COUNTERS_REPLY: + parse_counters(attr, &ct, attr->nfa_type-1); flags |= COUNTERS; break; case CTA_USE: ct.use = *(unsigned int *)NFA_DATA(attr); flags |= USE; break; + case CTA_ID: + ct.id = *(u_int32_t *)NFA_DATA(attr); + flags |= ID; + break; } attr = NFA_NEXT(attr, attrlen); } @@ -227,6 +229,8 @@ static int handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void *arg) fprintf(stdout, "mark=%lu ", ct.mark); if (flags & USE) fprintf(stdout, "use=%u ", ct.use); + if (flags & ID) + fprintf(stdout, "id=%u ", ct.id); fprintf(stdout, "\n"); @@ -257,19 +261,22 @@ static int event_handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, } void parse_expect(struct nfattr *attr, struct ctnl_tuple *tuple, - struct ctnl_tuple *mask, unsigned long *timeout) + struct ctnl_tuple *mask, unsigned long *timeout, + u_int32_t *id) { struct nfattr *tb[CTA_EXPECT_MAX]; memset(tb, 0, CTA_EXPECT_MAX*sizeof(struct nfattr *)); - nfnl_parse_attr(tb, CTA_EXPECT_MAX, NFA_DATA(attr), NFA_PAYLOAD(attr)); + nfnl_parse_nested(tb, CTA_EXPECT_MAX, attr); if (tb[CTA_EXPECT_TUPLE-1]) parse_tuple(tb[CTA_EXPECT_TUPLE-1], tuple); if (tb[CTA_EXPECT_MASK-1]) parse_tuple(tb[CTA_EXPECT_MASK-1], mask); if (tb[CTA_EXPECT_TIMEOUT-1]) *timeout = *(unsigned long *)NFA_DATA(tb[CTA_EXPECT_TIMEOUT-1]); + if (tb[CTA_EXPECT_ID-1]) + *id = *(u_int32_t *)NFA_DATA(tb[CTA_EXPECT_ID-1]); } static int expect_handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void *arg) @@ -282,6 +289,8 @@ static int expect_handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void * int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); struct ctnl_tuple tuple, mask; unsigned long timeout = 0; + u_int32_t id = 0; + unsigned int flags; memset(&tuple, 0, sizeof(struct ctnl_tuple)); memset(&mask, 0, sizeof(struct ctnl_tuple)); @@ -294,7 +303,8 @@ static int expect_handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void * while (NFA_OK(attr, attrlen)) { switch(attr->nfa_type) { case CTA_EXPECT: - parse_expect(attr, &tuple, &mask, &timeout); + parse_expect(attr, &tuple, &mask, &timeout, + &id); break; } attr = NFA_NEXT(attr, attrlen); @@ -305,10 +315,14 @@ static int expect_handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void * NIPQUAD(tuple.src.v4), NIPQUAD(tuple.dst.v4)); - fprintf(stdout, "src=%u.%u.%u.%u dst=%u.%u.%u.%u\n", + fprintf(stdout, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ", NIPQUAD(mask.src.v4), NIPQUAD(mask.dst.v4)); + fprintf(stdout, "id=0x%x ", id); + + fputc('\n', stdout); + return 0; } -- cgit v1.2.3 From 74fa2604aded64cd87c59b9bf787fa4ebdc179d2 Mon Sep 17 00:00:00 2001 From: "/C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=laforge/emailAddress=laforge@netfilter.org" Date: Sat, 30 Jul 2005 21:17:30 +0000 Subject: libctnetlink now called libnfnetlink_conntrack --- include/libct_proto.h | 2 +- src/libct.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/include/libct_proto.h b/include/libct_proto.h index 51e23fc..dcf7009 100644 --- a/include/libct_proto.h +++ b/include/libct_proto.h @@ -5,7 +5,7 @@ #include "linux_list.h" #include -#include "libctnetlink.h" +#include struct cta_proto; diff --git a/src/libct.c b/src/libct.c index 245c584..966758d 100644 --- a/src/libct.c +++ b/src/libct.c @@ -19,8 +19,8 @@ #define INT_MIN (-INT_MAX - 1) #include #include -#include "libctnetlink.h" -#include "libnfnetlink.h" +#include +#include #include "linux_list.h" #include "libct_proto.h" -- cgit v1.2.3 From cf96e5c1a423cce66d21cbf43e6a1f5e496bab30 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: Tue, 2 Aug 2005 13:21:25 +0000 Subject: More re-sync to work fine with current ip_conntrack_netlink implementation available in Harald's 2.6.14 tree. --- extensions/libct_proto_sctp.c | 2 +- extensions/libct_proto_tcp.c | 4 ++-- extensions/libct_proto_udp.c | 4 ++-- src/conntrack.c | 11 ++++++---- src/libct.c | 47 +++++++++++++++++++++++-------------------- test.sh | 2 +- 6 files changed, 38 insertions(+), 32 deletions(-) (limited to 'src') diff --git a/extensions/libct_proto_sctp.c b/extensions/libct_proto_sctp.c index d5ff298..b519ff1 100644 --- a/extensions/libct_proto_sctp.c +++ b/extensions/libct_proto_sctp.c @@ -12,7 +12,7 @@ #include #include #include /* For htons */ -#include +#include #include "libct_proto.h" #include "libctnetlink.h" diff --git a/extensions/libct_proto_tcp.c b/extensions/libct_proto_tcp.c index 973c5ab..65f0fb6 100644 --- a/extensions/libct_proto_tcp.c +++ b/extensions/libct_proto_tcp.c @@ -12,7 +12,7 @@ #include #include #include /* For htons */ -#include +#include #include "libct_proto.h" #include "libctnetlink.h" @@ -114,7 +114,7 @@ int parse_options(char c, char *argv[], break; case '6': if (optarg) { - mask->l4src.tcp.port = htons(atoi(optarg)); + mask->l4dst.tcp.port = htons(atoi(optarg)); *flags |= MASK_DPORT; } break; diff --git a/extensions/libct_proto_udp.c b/extensions/libct_proto_udp.c index 7821d5b..706f113 100644 --- a/extensions/libct_proto_udp.c +++ b/extensions/libct_proto_udp.c @@ -11,7 +11,7 @@ #include #include #include /* For htons */ -#include +#include #include "libct_proto.h" #include "libctnetlink.h" @@ -95,7 +95,7 @@ int parse_options(char c, char *argv[], break; case '6': if (optarg) { - mask->l4src.udp.port = htons(atoi(optarg)); + mask->l4dst.udp.port = htons(atoi(optarg)); *flags |= MASK_DPORT; } break; diff --git a/src/conntrack.c b/src/conntrack.c index 2a8fa87..611f0d5 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -679,6 +679,7 @@ int main(int argc, char *argv[]) memset(&orig, 0, sizeof(struct ctnl_tuple)); memset(&reply, 0, sizeof(struct ctnl_tuple)); memset(&mask, 0, sizeof(struct ctnl_tuple)); + memset(&exptuple, 0, sizeof(struct ctnl_tuple)); memset(&range, 0, sizeof(struct ctnl_nat)); while ((c = getopt_long(argc, argv, @@ -768,6 +769,8 @@ int main(int argc, char *argv[]) exit_error(PARAMETER_PROBLEM, "proto needed\n"); orig.protonum = h->protonum; reply.protonum = h->protonum; + exptuple.protonum = h->protonum; + mask.protonum = h->protonum; opts = merge_options(opts, h->opts, &h->option_offset); break; @@ -791,22 +794,22 @@ int main(int argc, char *argv[]) case 'z': options |= CT_OPT_ZERO; break; - case 'k': + case '{': options |= CT_OPT_MASK_SRC; if (optarg) mask.src.v4 = inet_addr(optarg); break; - case 'l': + case '}': options |= CT_OPT_MASK_DST; if (optarg) mask.dst.v4 = inet_addr(optarg); break; - case 'x': + case '[': options |= CT_OPT_EXP_SRC; if (optarg) exptuple.src.v4 = inet_addr(optarg); break; - case 'y': + case ']': options |= CT_OPT_EXP_DST; if (optarg) exptuple.dst.v4 = inet_addr(optarg); diff --git a/src/libct.c b/src/libct.c index 966758d..cf46b99 100644 --- a/src/libct.c +++ b/src/libct.c @@ -35,6 +35,14 @@ extern char *lib_dir; extern struct list_head proto_list; extern char *proto2str[]; +static void dump_tuple(struct ctnl_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 void print_status(unsigned int status) { if (status & IPS_ASSURED) @@ -100,7 +108,7 @@ static void parse_protoinfo(struct nfattr *attr, struct ctnl_conntrack *ct) if (h && h->parse_protoinfo) h->parse_protoinfo(tb, ct); } - + static void parse_counters(struct nfattr *attr, struct ctnl_conntrack *ct, enum ctattr_type parent) { @@ -111,10 +119,10 @@ static void parse_counters(struct nfattr *attr, struct ctnl_conntrack *ct, nfnl_parse_nested(tb, CTA_COUNTERS_MAX, attr); if (tb[CTA_COUNTERS_PACKETS-1]) ct->counters[CTNL_DIR_ORIGINAL].packets - = *(u_int64_t *)NFA_DATA(tb[CTA_COUNTERS_PACKETS-1]); + = *(u_int64_t *)NFA_DATA(tb[CTA_COUNTERS_PACKETS-1]); if (tb[CTA_COUNTERS_BYTES-1]) ct->counters[CTNL_DIR_ORIGINAL].bytes - = *(u_int64_t *)NFA_DATA(tb[CTA_COUNTERS_BYTES-1]); + = *(u_int64_t *)NFA_DATA(tb[CTA_COUNTERS_BYTES-1]); } /* Some people seem to like counting in decimal... */ @@ -154,7 +162,7 @@ static int handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void *arg) parse_tuple(attr, &ct.tuple[CTNL_DIR_REPLY]); break; case CTA_STATUS: - ct.status = *(unsigned int *)NFA_DATA(attr); + ct.status = ntohl(*(unsigned int *)NFA_DATA(attr)); flags |= STATUS; break; case CTA_PROTOINFO: @@ -162,11 +170,11 @@ static int handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void *arg) flags |= PROTOINFO; break; case CTA_TIMEOUT: - ct.timeout = *(unsigned long *)NFA_DATA(attr); + ct.timeout = ntohl(*(unsigned long *)NFA_DATA(attr)); flags |= TIMEOUT; break; case CTA_MARK: - ct.mark = *(unsigned long *)NFA_DATA(attr); + ct.mark = ntohl(*(unsigned long *)NFA_DATA(attr)); flags |= MARK; break; case CTA_COUNTERS_ORIG: @@ -175,11 +183,11 @@ static int handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void *arg) flags |= COUNTERS; break; case CTA_USE: - ct.use = *(unsigned int *)NFA_DATA(attr); + ct.use = ntohl(*(unsigned int *)NFA_DATA(attr)); flags |= USE; break; case CTA_ID: - ct.id = *(u_int32_t *)NFA_DATA(attr); + ct.id = ntohl(*(u_int32_t *)NFA_DATA(attr)); flags |= ID; break; } @@ -274,9 +282,9 @@ void parse_expect(struct nfattr *attr, struct ctnl_tuple *tuple, if (tb[CTA_EXPECT_MASK-1]) parse_tuple(tb[CTA_EXPECT_MASK-1], mask); if (tb[CTA_EXPECT_TIMEOUT-1]) - *timeout = *(unsigned long *)NFA_DATA(tb[CTA_EXPECT_TIMEOUT-1]); + *timeout = htonl(*(unsigned long *)NFA_DATA(tb[CTA_EXPECT_TIMEOUT-1])); if (tb[CTA_EXPECT_ID-1]) - *id = *(u_int32_t *)NFA_DATA(tb[CTA_EXPECT_ID-1]); + *id = htonl(*(u_int32_t *)NFA_DATA(tb[CTA_EXPECT_ID-1])); } static int expect_handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void *arg) @@ -319,7 +327,7 @@ static int expect_handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void * NIPQUAD(mask.src.v4), NIPQUAD(mask.dst.v4)); - fprintf(stdout, "id=0x%x ", id); + fprintf(stdout, "id=%u ", id); fputc('\n', stdout); @@ -339,8 +347,8 @@ int create_conntrack(struct ctnl_tuple *orig, memset(&ct, 0, sizeof(struct ctnl_conntrack)); ct.tuple[CTNL_DIR_ORIGINAL] = *orig; ct.tuple[CTNL_DIR_REPLY] = *reply; - ct.timeout = timeout; - ct.status = status; + ct.timeout = htonl(timeout); + ct.status = htonl(status); ct.protoinfo = *proto; if (range) ct.nat = *range; @@ -367,8 +375,8 @@ int update_conntrack(struct ctnl_tuple *orig, memset(&ct, 0, sizeof(struct ctnl_conntrack)); ct.tuple[CTNL_DIR_ORIGINAL] = *orig; ct.tuple[CTNL_DIR_REPLY] = *reply; - ct.timeout = timeout; - ct.status = status; + ct.timeout = htonl(timeout); + ct.status = htonl(status); ct.protoinfo = *proto; if ((ret = ctnl_open(&cth, 0)) < 0) @@ -518,7 +526,7 @@ int dump_expect_list() .handler = expect_handler }; int ret; - + if ((ret = ctnl_open(&cth, 0)) < 0) return ret; @@ -546,7 +554,6 @@ int flush_conntrack() int get_expect(struct ctnl_tuple *tuple, enum ctattr_type t) { - /* struct ctnl_msg_handler h = { .type = IPCTNL_MSG_EXP_NEW, .handler = expect_handler @@ -562,7 +569,6 @@ int get_expect(struct ctnl_tuple *tuple, ctnl_close(&cth); return ret; - */ } int create_expectation(struct ctnl_tuple *tuple, @@ -571,22 +577,20 @@ int create_expectation(struct ctnl_tuple *tuple, struct ctnl_tuple *mask, unsigned long timeout) { - /* int ret; if ((ret = ctnl_open(&cth, 0)) < 0) return ret; + ret = ctnl_new_expect(&cth, tuple, t, exptuple, mask, timeout); ctnl_close(&cth); return ret; - */ } int delete_expectation(struct ctnl_tuple *tuple, enum ctattr_type t) { - /* int ret; if ((ret = ctnl_open(&cth, 0)) < 0) @@ -596,7 +600,6 @@ int delete_expectation(struct ctnl_tuple *tuple, enum ctattr_type t) ctnl_close(&cth); return ret; - */ } int event_expectation(unsigned int event_mask) diff --git a/test.sh b/test.sh index 08c840f..b84fb13 100644 --- a/test.sh +++ b/test.sh @@ -75,7 +75,7 @@ case $1 in create-expect) # requires modprobe ip_conntrack_ftp $CONNTRACK -I expect --orig-src $SRC --orig-dst $DST \ - --exp-src 4.4.4.4 --exp-dst 5.5.5.5 \ + --tuple-src 4.4.4.4 --tuple-dst 5.5.5.5 \ --mask-src 255.255.255.0 --mask-dst 255.255.255.255 \ -p tcp --orig-port-src $SPORT --orig-port-dst $DPORT \ -t 200 --mask-port-src 10 --mask-port-dst 300 -- cgit v1.2.3 From 3d4031de7d4e394afefe50819357d007c74ae39c Mon Sep 17 00:00:00 2001 From: "/C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=laforge/emailAddress=laforge@netfilter.org" Date: Fri, 5 Aug 2005 18:11:43 +0000 Subject: use new header file --- src/conntrack.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index 611f0d5..ccfb71a 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -42,8 +42,7 @@ #include #include #include -#include "libctnetlink.h" -#include "libnfnetlink.h" +#include #include "linux_list.h" #include "libct_proto.h" -- cgit v1.2.3 From 7a60a4748220105e592c583ef0860d51e540a2c6 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: Mon, 8 Aug 2005 11:38:55 +0000 Subject: Resync to current libnfnetlink_conntrack and 2.6.14 tree --- Makefile.am | 2 +- config.h.in | 7 ++-- configure.in | 2 +- extensions/libct_proto_sctp.c | 2 +- extensions/libct_proto_tcp.c | 2 +- extensions/libct_proto_udp.c | 2 +- src/conntrack.c | 10 +++--- src/libct.c | 79 +++++++++++++++++++------------------------ 8 files changed, 47 insertions(+), 59 deletions(-) (limited to 'src') diff --git a/Makefile.am b/Makefile.am index 888d53e..b114b00 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5,7 +5,7 @@ AUTOMAKE_OPTIONS = foreign 1.4 INCLUDES = $(all_includes) -I$(top_srcdir)/include -I${KERNELDIR} SUBDIRS = src extensions DIST_SUBDIRS = include src extensions -LINKOPTS = -ldl -lnfnetlink -lctnetlink +LINKOPTS = -ldl -lnfnetlink -lnfnetlink_conntrack AM_CFLAGS = -g $(OBJECTS): libtool diff --git a/config.h.in b/config.h.in index 3921abd..9045dbb 100644 --- a/config.h.in +++ b/config.h.in @@ -6,15 +6,16 @@ /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H -/* Define to 1 if you have the `ctnetlink' library (-lctnetlink). */ -#undef HAVE_LIBCTNETLINK - /* Define to 1 if you have the `dl' library (-ldl). */ #undef HAVE_LIBDL /* Define to 1 if you have the `nfnetlink' library (-lnfnetlink). */ #undef HAVE_LIBNFNETLINK +/* Define to 1 if you have the `nfnetlink_conntrack' library + (-lnfnetlink_conntrack). */ +#undef HAVE_LIBNFNETLINK_CONNTRACK + /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H diff --git a/configure.in b/configure.in index efdacf1..8956e34 100644 --- a/configure.in +++ b/configure.in @@ -22,7 +22,7 @@ dnl AC_CHECK_LIB([c], [main]) AC_CHECK_LIB([dl], [dlopen]) AC_CHECK_LIB([nfnetlink], [nfnl_listen]) -AC_CHECK_LIB([ctnetlink], [ctnl_register_handler] ,,,[-lnfnetlink]) +AC_CHECK_LIB([nfnetlink_conntrack], [ctnl_register_handler] ,,,[-lnfnetlink]) # Checks for header files. dnl AC_HEADER_STDC diff --git a/extensions/libct_proto_sctp.c b/extensions/libct_proto_sctp.c index b519ff1..4dbdf27 100644 --- a/extensions/libct_proto_sctp.c +++ b/extensions/libct_proto_sctp.c @@ -14,7 +14,7 @@ #include /* For htons */ #include #include "libct_proto.h" -#include "libctnetlink.h" +#include static struct option opts[] = { {"orig-port-src", 1, 0, '1'}, diff --git a/extensions/libct_proto_tcp.c b/extensions/libct_proto_tcp.c index 65f0fb6..323e4ec 100644 --- a/extensions/libct_proto_tcp.c +++ b/extensions/libct_proto_tcp.c @@ -14,7 +14,7 @@ #include /* For htons */ #include #include "libct_proto.h" -#include "libctnetlink.h" +#include static struct option opts[] = { {"orig-port-src", 1, 0, '1'}, diff --git a/extensions/libct_proto_udp.c b/extensions/libct_proto_udp.c index 706f113..8a9f0cf 100644 --- a/extensions/libct_proto_udp.c +++ b/extensions/libct_proto_udp.c @@ -13,7 +13,7 @@ #include /* For htons */ #include #include "libct_proto.h" -#include "libctnetlink.h" +#include static struct option opts[] = { {"orig-port-src", 1, 0, '1'}, diff --git a/src/conntrack.c b/src/conntrack.c index ccfb71a..22c6115 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -880,13 +880,11 @@ int main(int argc, char *argv[]) case EXP_CREATE: if (options & CT_OPT_ORIG) res = create_expectation(&orig, - CTA_TUPLE_ORIG, &exptuple, &mask, timeout); else if (options & CT_OPT_REPL) res = create_expectation(&reply, - CTA_TUPLE_REPLY, &exptuple, &mask, timeout); @@ -917,16 +915,16 @@ int main(int argc, char *argv[]) case EXP_DELETE: if (options & CT_OPT_ORIG) - res = delete_expectation(&orig, CTA_TUPLE_ORIG); + res = delete_expectation(&orig); else if (options & CT_OPT_REPL) - res = delete_expectation(&reply, CTA_TUPLE_REPLY); + res = delete_expectation(&reply); break; case CT_GET: if (options & CT_OPT_ORIG) - res = get_conntrack(&orig, CTA_TUPLE_ORIG, id); + res = get_conntrack(&orig, id); else if (options & CT_OPT_REPL) - res = get_conntrack(&reply, CTA_TUPLE_REPLY, id); + res = get_conntrack(&reply, id); break; case EXP_GET: diff --git a/src/libct.c b/src/libct.c index cf46b99..e03c02a 100644 --- a/src/libct.c +++ b/src/libct.c @@ -162,7 +162,7 @@ static int handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void *arg) parse_tuple(attr, &ct.tuple[CTNL_DIR_REPLY]); break; case CTA_STATUS: - ct.status = ntohl(*(unsigned int *)NFA_DATA(attr)); + ct.status = *(unsigned int *)NFA_DATA(attr); flags |= STATUS; break; case CTA_PROTOINFO: @@ -268,25 +268,6 @@ static int event_handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, return handler(sock, nlh, arg); } -void parse_expect(struct nfattr *attr, struct ctnl_tuple *tuple, - struct ctnl_tuple *mask, unsigned long *timeout, - u_int32_t *id) -{ - struct nfattr *tb[CTA_EXPECT_MAX]; - - memset(tb, 0, CTA_EXPECT_MAX*sizeof(struct nfattr *)); - - nfnl_parse_nested(tb, CTA_EXPECT_MAX, attr); - if (tb[CTA_EXPECT_TUPLE-1]) - parse_tuple(tb[CTA_EXPECT_TUPLE-1], tuple); - if (tb[CTA_EXPECT_MASK-1]) - parse_tuple(tb[CTA_EXPECT_MASK-1], mask); - if (tb[CTA_EXPECT_TIMEOUT-1]) - *timeout = htonl(*(unsigned long *)NFA_DATA(tb[CTA_EXPECT_TIMEOUT-1])); - if (tb[CTA_EXPECT_ID-1]) - *id = htonl(*(u_int32_t *)NFA_DATA(tb[CTA_EXPECT_ID-1])); -} - static int expect_handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void *arg) { struct nfgenmsg *nfmsg; @@ -310,9 +291,19 @@ static int expect_handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void * while (NFA_OK(attr, attrlen)) { switch(attr->nfa_type) { - case CTA_EXPECT: - parse_expect(attr, &tuple, &mask, &timeout, - &id); + + case CTA_EXPECT_TUPLE: + parse_tuple(attr, &tuple); + break; + case CTA_EXPECT_MASK: + parse_tuple(attr, &mask); + break; + case CTA_EXPECT_TIMEOUT: + timeout = htonl(*(unsigned long *) + NFA_DATA(attr)); + break; + case CTA_EXPECT_ID: + id = htonl(*(u_int32_t *)NFA_DATA(attr)); break; } attr = NFA_NEXT(attr, attrlen); @@ -348,12 +339,12 @@ int create_conntrack(struct ctnl_tuple *orig, ct.tuple[CTNL_DIR_ORIGINAL] = *orig; ct.tuple[CTNL_DIR_REPLY] = *reply; ct.timeout = htonl(timeout); - ct.status = htonl(status); + ct.status = status; ct.protoinfo = *proto; if (range) ct.nat = *range; - if ((ret = ctnl_open(&cth, 0)) < 0) + if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK, 0)) < 0) return ret; ret = ctnl_new_conntrack(&cth, &ct); @@ -376,10 +367,10 @@ int update_conntrack(struct ctnl_tuple *orig, ct.tuple[CTNL_DIR_ORIGINAL] = *orig; ct.tuple[CTNL_DIR_REPLY] = *reply; ct.timeout = htonl(timeout); - ct.status = htonl(status); + ct.status = status; ct.protoinfo = *proto; - if ((ret = ctnl_open(&cth, 0)) < 0) + if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK, 0)) < 0) return ret; ret = ctnl_upd_conntrack(&cth, &ct); @@ -393,7 +384,7 @@ int delete_conntrack(struct ctnl_tuple *tuple, int dir) { int ret; - if ((ret = ctnl_open(&cth, 0)) < 0) + if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK, 0)) < 0) return ret; ret = ctnl_del_conntrack(&cth, tuple, dir); @@ -411,7 +402,7 @@ int get_conntrack(struct ctnl_tuple *tuple, int dir) }; int ret; - if ((ret = ctnl_open(&cth, 0)) < 0) + if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK, 0)) < 0) return ret; ctnl_register_handler(&cth, &h); @@ -430,7 +421,7 @@ int dump_conntrack_table(int zero) .handler = handler }; - if ((ret = ctnl_open(&cth, 0)) < 0) + if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK, 0)) < 0) return ret; ctnl_register_handler(&cth, &h); @@ -463,7 +454,7 @@ int event_conntrack(unsigned int event_mask) }; int ret; - if ((ret = ctnl_open(&cth, event_mask)) < 0) + if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK, event_mask)) < 0) return ret; signal(SIGINT, event_sighandler); @@ -527,7 +518,7 @@ int dump_expect_list() }; int ret; - if ((ret = ctnl_open(&cth, 0)) < 0) + if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK_EXP, 0)) < 0) return ret; ctnl_register_handler(&cth, &h); @@ -542,7 +533,7 @@ int flush_conntrack() { int ret; - if ((ret = ctnl_open(&cth, 0)) < 0) + if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK, 0)) < 0) return ret; ret = ctnl_flush_conntrack(&cth); @@ -551,8 +542,7 @@ int flush_conntrack() return ret; } -int get_expect(struct ctnl_tuple *tuple, - enum ctattr_type t) +int get_expect(struct ctnl_tuple *tuple) { struct ctnl_msg_handler h = { .type = IPCTNL_MSG_EXP_NEW, @@ -560,43 +550,42 @@ int get_expect(struct ctnl_tuple *tuple, }; int ret; - if ((ret = ctnl_open(&cth, 0)) < 0) + if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK_EXP, 0)) < 0) return 0; ctnl_register_handler(&cth, &h); - ret = ctnl_get_expect(&cth, tuple, t); + ret = ctnl_get_expect(&cth, tuple); ctnl_close(&cth); return ret; } int create_expectation(struct ctnl_tuple *tuple, - enum ctattr_type t, struct ctnl_tuple *exptuple, struct ctnl_tuple *mask, unsigned long timeout) { int ret; - if ((ret = ctnl_open(&cth, 0)) < 0) + if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK_EXP, 0)) < 0) return ret; - ret = ctnl_new_expect(&cth, tuple, t, exptuple, mask, timeout); + ret = ctnl_new_expect(&cth, tuple, exptuple, mask, timeout); ctnl_close(&cth); return ret; } -int delete_expectation(struct ctnl_tuple *tuple, enum ctattr_type t) +int delete_expectation(struct ctnl_tuple *tuple) { int ret; - if ((ret = ctnl_open(&cth, 0)) < 0) + if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK_EXP, 0)) < 0) return ret; - ret = ctnl_del_expect(&cth, tuple, t); + ret = ctnl_del_expect(&cth, tuple); ctnl_close(&cth); return ret; @@ -614,7 +603,7 @@ int event_expectation(unsigned int event_mask) }; int ret; - if ((ret = ctnl_open(&cth, event_mask)) < 0) + if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK_EXP, event_mask)) < 0) return ret; ctnl_register_handler(&cth, &hnew); @@ -629,7 +618,7 @@ int flush_expectation() { int ret; - if ((ret = ctnl_open(&cth, 0)) < 0) + if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK_EXP, 0)) < 0) return ret; ret = ctnl_flush_expect(&cth); -- cgit v1.2.3 From 8354fefa19bdaadb19a8fd0a818a7097e24bceaf 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: Mon, 8 Aug 2005 11:40:51 +0000 Subject: Resync to 2.6.14 and libnfnetlink_conntrack --- Makefile.am | 2 +- config.h.in | 7 ++-- configure.in | 2 +- extensions/libct_proto_sctp.c | 2 +- extensions/libct_proto_tcp.c | 2 +- extensions/libct_proto_udp.c | 2 +- src/conntrack.c | 10 +++--- src/libct.c | 79 ++++++++++++++++++++++++------------------- 8 files changed, 59 insertions(+), 47 deletions(-) (limited to 'src') diff --git a/Makefile.am b/Makefile.am index b114b00..888d53e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5,7 +5,7 @@ AUTOMAKE_OPTIONS = foreign 1.4 INCLUDES = $(all_includes) -I$(top_srcdir)/include -I${KERNELDIR} SUBDIRS = src extensions DIST_SUBDIRS = include src extensions -LINKOPTS = -ldl -lnfnetlink -lnfnetlink_conntrack +LINKOPTS = -ldl -lnfnetlink -lctnetlink AM_CFLAGS = -g $(OBJECTS): libtool diff --git a/config.h.in b/config.h.in index 9045dbb..3921abd 100644 --- a/config.h.in +++ b/config.h.in @@ -6,16 +6,15 @@ /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H +/* Define to 1 if you have the `ctnetlink' library (-lctnetlink). */ +#undef HAVE_LIBCTNETLINK + /* Define to 1 if you have the `dl' library (-ldl). */ #undef HAVE_LIBDL /* Define to 1 if you have the `nfnetlink' library (-lnfnetlink). */ #undef HAVE_LIBNFNETLINK -/* Define to 1 if you have the `nfnetlink_conntrack' library - (-lnfnetlink_conntrack). */ -#undef HAVE_LIBNFNETLINK_CONNTRACK - /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H diff --git a/configure.in b/configure.in index 8956e34..efdacf1 100644 --- a/configure.in +++ b/configure.in @@ -22,7 +22,7 @@ dnl AC_CHECK_LIB([c], [main]) AC_CHECK_LIB([dl], [dlopen]) AC_CHECK_LIB([nfnetlink], [nfnl_listen]) -AC_CHECK_LIB([nfnetlink_conntrack], [ctnl_register_handler] ,,,[-lnfnetlink]) +AC_CHECK_LIB([ctnetlink], [ctnl_register_handler] ,,,[-lnfnetlink]) # Checks for header files. dnl AC_HEADER_STDC diff --git a/extensions/libct_proto_sctp.c b/extensions/libct_proto_sctp.c index 4dbdf27..b519ff1 100644 --- a/extensions/libct_proto_sctp.c +++ b/extensions/libct_proto_sctp.c @@ -14,7 +14,7 @@ #include /* For htons */ #include #include "libct_proto.h" -#include +#include "libctnetlink.h" static struct option opts[] = { {"orig-port-src", 1, 0, '1'}, diff --git a/extensions/libct_proto_tcp.c b/extensions/libct_proto_tcp.c index 323e4ec..65f0fb6 100644 --- a/extensions/libct_proto_tcp.c +++ b/extensions/libct_proto_tcp.c @@ -14,7 +14,7 @@ #include /* For htons */ #include #include "libct_proto.h" -#include +#include "libctnetlink.h" static struct option opts[] = { {"orig-port-src", 1, 0, '1'}, diff --git a/extensions/libct_proto_udp.c b/extensions/libct_proto_udp.c index 8a9f0cf..706f113 100644 --- a/extensions/libct_proto_udp.c +++ b/extensions/libct_proto_udp.c @@ -13,7 +13,7 @@ #include /* For htons */ #include #include "libct_proto.h" -#include +#include "libctnetlink.h" static struct option opts[] = { {"orig-port-src", 1, 0, '1'}, diff --git a/src/conntrack.c b/src/conntrack.c index 22c6115..ccfb71a 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -880,11 +880,13 @@ int main(int argc, char *argv[]) case EXP_CREATE: if (options & CT_OPT_ORIG) res = create_expectation(&orig, + CTA_TUPLE_ORIG, &exptuple, &mask, timeout); else if (options & CT_OPT_REPL) res = create_expectation(&reply, + CTA_TUPLE_REPLY, &exptuple, &mask, timeout); @@ -915,16 +917,16 @@ int main(int argc, char *argv[]) case EXP_DELETE: if (options & CT_OPT_ORIG) - res = delete_expectation(&orig); + res = delete_expectation(&orig, CTA_TUPLE_ORIG); else if (options & CT_OPT_REPL) - res = delete_expectation(&reply); + res = delete_expectation(&reply, CTA_TUPLE_REPLY); break; case CT_GET: if (options & CT_OPT_ORIG) - res = get_conntrack(&orig, id); + res = get_conntrack(&orig, CTA_TUPLE_ORIG, id); else if (options & CT_OPT_REPL) - res = get_conntrack(&reply, id); + res = get_conntrack(&reply, CTA_TUPLE_REPLY, id); break; case EXP_GET: diff --git a/src/libct.c b/src/libct.c index e03c02a..cf46b99 100644 --- a/src/libct.c +++ b/src/libct.c @@ -162,7 +162,7 @@ static int handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void *arg) parse_tuple(attr, &ct.tuple[CTNL_DIR_REPLY]); break; case CTA_STATUS: - ct.status = *(unsigned int *)NFA_DATA(attr); + ct.status = ntohl(*(unsigned int *)NFA_DATA(attr)); flags |= STATUS; break; case CTA_PROTOINFO: @@ -268,6 +268,25 @@ static int event_handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, return handler(sock, nlh, arg); } +void parse_expect(struct nfattr *attr, struct ctnl_tuple *tuple, + struct ctnl_tuple *mask, unsigned long *timeout, + u_int32_t *id) +{ + struct nfattr *tb[CTA_EXPECT_MAX]; + + memset(tb, 0, CTA_EXPECT_MAX*sizeof(struct nfattr *)); + + nfnl_parse_nested(tb, CTA_EXPECT_MAX, attr); + if (tb[CTA_EXPECT_TUPLE-1]) + parse_tuple(tb[CTA_EXPECT_TUPLE-1], tuple); + if (tb[CTA_EXPECT_MASK-1]) + parse_tuple(tb[CTA_EXPECT_MASK-1], mask); + if (tb[CTA_EXPECT_TIMEOUT-1]) + *timeout = htonl(*(unsigned long *)NFA_DATA(tb[CTA_EXPECT_TIMEOUT-1])); + if (tb[CTA_EXPECT_ID-1]) + *id = htonl(*(u_int32_t *)NFA_DATA(tb[CTA_EXPECT_ID-1])); +} + static int expect_handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void *arg) { struct nfgenmsg *nfmsg; @@ -291,19 +310,9 @@ static int expect_handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void * while (NFA_OK(attr, attrlen)) { switch(attr->nfa_type) { - - case CTA_EXPECT_TUPLE: - parse_tuple(attr, &tuple); - break; - case CTA_EXPECT_MASK: - parse_tuple(attr, &mask); - break; - case CTA_EXPECT_TIMEOUT: - timeout = htonl(*(unsigned long *) - NFA_DATA(attr)); - break; - case CTA_EXPECT_ID: - id = htonl(*(u_int32_t *)NFA_DATA(attr)); + case CTA_EXPECT: + parse_expect(attr, &tuple, &mask, &timeout, + &id); break; } attr = NFA_NEXT(attr, attrlen); @@ -339,12 +348,12 @@ int create_conntrack(struct ctnl_tuple *orig, ct.tuple[CTNL_DIR_ORIGINAL] = *orig; ct.tuple[CTNL_DIR_REPLY] = *reply; ct.timeout = htonl(timeout); - ct.status = status; + ct.status = htonl(status); ct.protoinfo = *proto; if (range) ct.nat = *range; - if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK, 0)) < 0) + if ((ret = ctnl_open(&cth, 0)) < 0) return ret; ret = ctnl_new_conntrack(&cth, &ct); @@ -367,10 +376,10 @@ int update_conntrack(struct ctnl_tuple *orig, ct.tuple[CTNL_DIR_ORIGINAL] = *orig; ct.tuple[CTNL_DIR_REPLY] = *reply; ct.timeout = htonl(timeout); - ct.status = status; + ct.status = htonl(status); ct.protoinfo = *proto; - if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK, 0)) < 0) + if ((ret = ctnl_open(&cth, 0)) < 0) return ret; ret = ctnl_upd_conntrack(&cth, &ct); @@ -384,7 +393,7 @@ int delete_conntrack(struct ctnl_tuple *tuple, int dir) { int ret; - if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK, 0)) < 0) + if ((ret = ctnl_open(&cth, 0)) < 0) return ret; ret = ctnl_del_conntrack(&cth, tuple, dir); @@ -402,7 +411,7 @@ int get_conntrack(struct ctnl_tuple *tuple, int dir) }; int ret; - if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK, 0)) < 0) + if ((ret = ctnl_open(&cth, 0)) < 0) return ret; ctnl_register_handler(&cth, &h); @@ -421,7 +430,7 @@ int dump_conntrack_table(int zero) .handler = handler }; - if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK, 0)) < 0) + if ((ret = ctnl_open(&cth, 0)) < 0) return ret; ctnl_register_handler(&cth, &h); @@ -454,7 +463,7 @@ int event_conntrack(unsigned int event_mask) }; int ret; - if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK, event_mask)) < 0) + if ((ret = ctnl_open(&cth, event_mask)) < 0) return ret; signal(SIGINT, event_sighandler); @@ -518,7 +527,7 @@ int dump_expect_list() }; int ret; - if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK_EXP, 0)) < 0) + if ((ret = ctnl_open(&cth, 0)) < 0) return ret; ctnl_register_handler(&cth, &h); @@ -533,7 +542,7 @@ int flush_conntrack() { int ret; - if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK, 0)) < 0) + if ((ret = ctnl_open(&cth, 0)) < 0) return ret; ret = ctnl_flush_conntrack(&cth); @@ -542,7 +551,8 @@ int flush_conntrack() return ret; } -int get_expect(struct ctnl_tuple *tuple) +int get_expect(struct ctnl_tuple *tuple, + enum ctattr_type t) { struct ctnl_msg_handler h = { .type = IPCTNL_MSG_EXP_NEW, @@ -550,42 +560,43 @@ int get_expect(struct ctnl_tuple *tuple) }; int ret; - if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK_EXP, 0)) < 0) + if ((ret = ctnl_open(&cth, 0)) < 0) return 0; ctnl_register_handler(&cth, &h); - ret = ctnl_get_expect(&cth, tuple); + ret = ctnl_get_expect(&cth, tuple, t); ctnl_close(&cth); return ret; } int create_expectation(struct ctnl_tuple *tuple, + enum ctattr_type t, struct ctnl_tuple *exptuple, struct ctnl_tuple *mask, unsigned long timeout) { int ret; - if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK_EXP, 0)) < 0) + if ((ret = ctnl_open(&cth, 0)) < 0) return ret; - ret = ctnl_new_expect(&cth, tuple, exptuple, mask, timeout); + ret = ctnl_new_expect(&cth, tuple, t, exptuple, mask, timeout); ctnl_close(&cth); return ret; } -int delete_expectation(struct ctnl_tuple *tuple) +int delete_expectation(struct ctnl_tuple *tuple, enum ctattr_type t) { int ret; - if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK_EXP, 0)) < 0) + if ((ret = ctnl_open(&cth, 0)) < 0) return ret; - ret = ctnl_del_expect(&cth, tuple); + ret = ctnl_del_expect(&cth, tuple, t); ctnl_close(&cth); return ret; @@ -603,7 +614,7 @@ int event_expectation(unsigned int event_mask) }; int ret; - if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK_EXP, event_mask)) < 0) + if ((ret = ctnl_open(&cth, event_mask)) < 0) return ret; ctnl_register_handler(&cth, &hnew); @@ -618,7 +629,7 @@ int flush_expectation() { int ret; - if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK_EXP, 0)) < 0) + if ((ret = ctnl_open(&cth, 0)) < 0) return ret; ret = ctnl_flush_expect(&cth); -- cgit v1.2.3 From 496dbfa8a0d9ae7bc432873dfb2ef3b41087acd5 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: Mon, 8 Aug 2005 11:43:51 +0000 Subject: Bumped version to 0.80 --- Makefile.am | 2 +- config.h.in | 7 ++-- configure.in | 2 +- extensions/libct_proto_sctp.c | 2 +- extensions/libct_proto_tcp.c | 2 +- extensions/libct_proto_udp.c | 2 +- src/conntrack.c | 12 +++---- src/libct.c | 79 +++++++++++++++++++------------------------ 8 files changed, 48 insertions(+), 60 deletions(-) (limited to 'src') diff --git a/Makefile.am b/Makefile.am index 888d53e..b114b00 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5,7 +5,7 @@ AUTOMAKE_OPTIONS = foreign 1.4 INCLUDES = $(all_includes) -I$(top_srcdir)/include -I${KERNELDIR} SUBDIRS = src extensions DIST_SUBDIRS = include src extensions -LINKOPTS = -ldl -lnfnetlink -lctnetlink +LINKOPTS = -ldl -lnfnetlink -lnfnetlink_conntrack AM_CFLAGS = -g $(OBJECTS): libtool diff --git a/config.h.in b/config.h.in index 3921abd..9045dbb 100644 --- a/config.h.in +++ b/config.h.in @@ -6,15 +6,16 @@ /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H -/* Define to 1 if you have the `ctnetlink' library (-lctnetlink). */ -#undef HAVE_LIBCTNETLINK - /* Define to 1 if you have the `dl' library (-ldl). */ #undef HAVE_LIBDL /* Define to 1 if you have the `nfnetlink' library (-lnfnetlink). */ #undef HAVE_LIBNFNETLINK +/* Define to 1 if you have the `nfnetlink_conntrack' library + (-lnfnetlink_conntrack). */ +#undef HAVE_LIBNFNETLINK_CONNTRACK + /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H diff --git a/configure.in b/configure.in index efdacf1..8956e34 100644 --- a/configure.in +++ b/configure.in @@ -22,7 +22,7 @@ dnl AC_CHECK_LIB([c], [main]) AC_CHECK_LIB([dl], [dlopen]) AC_CHECK_LIB([nfnetlink], [nfnl_listen]) -AC_CHECK_LIB([ctnetlink], [ctnl_register_handler] ,,,[-lnfnetlink]) +AC_CHECK_LIB([nfnetlink_conntrack], [ctnl_register_handler] ,,,[-lnfnetlink]) # Checks for header files. dnl AC_HEADER_STDC diff --git a/extensions/libct_proto_sctp.c b/extensions/libct_proto_sctp.c index b519ff1..4dbdf27 100644 --- a/extensions/libct_proto_sctp.c +++ b/extensions/libct_proto_sctp.c @@ -14,7 +14,7 @@ #include /* For htons */ #include #include "libct_proto.h" -#include "libctnetlink.h" +#include static struct option opts[] = { {"orig-port-src", 1, 0, '1'}, diff --git a/extensions/libct_proto_tcp.c b/extensions/libct_proto_tcp.c index 65f0fb6..323e4ec 100644 --- a/extensions/libct_proto_tcp.c +++ b/extensions/libct_proto_tcp.c @@ -14,7 +14,7 @@ #include /* For htons */ #include #include "libct_proto.h" -#include "libctnetlink.h" +#include static struct option opts[] = { {"orig-port-src", 1, 0, '1'}, diff --git a/extensions/libct_proto_udp.c b/extensions/libct_proto_udp.c index 706f113..8a9f0cf 100644 --- a/extensions/libct_proto_udp.c +++ b/extensions/libct_proto_udp.c @@ -13,7 +13,7 @@ #include /* For htons */ #include #include "libct_proto.h" -#include "libctnetlink.h" +#include static struct option opts[] = { {"orig-port-src", 1, 0, '1'}, diff --git a/src/conntrack.c b/src/conntrack.c index ccfb71a..12825b4 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -47,7 +47,7 @@ #include "libct_proto.h" #define PROGNAME "conntrack" -#define VERSION "0.63" +#define VERSION "0.80" #if 0 #define DEBUGP printf @@ -880,13 +880,11 @@ int main(int argc, char *argv[]) case EXP_CREATE: if (options & CT_OPT_ORIG) res = create_expectation(&orig, - CTA_TUPLE_ORIG, &exptuple, &mask, timeout); else if (options & CT_OPT_REPL) res = create_expectation(&reply, - CTA_TUPLE_REPLY, &exptuple, &mask, timeout); @@ -917,16 +915,16 @@ int main(int argc, char *argv[]) case EXP_DELETE: if (options & CT_OPT_ORIG) - res = delete_expectation(&orig, CTA_TUPLE_ORIG); + res = delete_expectation(&orig); else if (options & CT_OPT_REPL) - res = delete_expectation(&reply, CTA_TUPLE_REPLY); + res = delete_expectation(&reply); break; case CT_GET: if (options & CT_OPT_ORIG) - res = get_conntrack(&orig, CTA_TUPLE_ORIG, id); + res = get_conntrack(&orig, id); else if (options & CT_OPT_REPL) - res = get_conntrack(&reply, CTA_TUPLE_REPLY, id); + res = get_conntrack(&reply, id); break; case EXP_GET: diff --git a/src/libct.c b/src/libct.c index cf46b99..e03c02a 100644 --- a/src/libct.c +++ b/src/libct.c @@ -162,7 +162,7 @@ static int handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void *arg) parse_tuple(attr, &ct.tuple[CTNL_DIR_REPLY]); break; case CTA_STATUS: - ct.status = ntohl(*(unsigned int *)NFA_DATA(attr)); + ct.status = *(unsigned int *)NFA_DATA(attr); flags |= STATUS; break; case CTA_PROTOINFO: @@ -268,25 +268,6 @@ static int event_handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, return handler(sock, nlh, arg); } -void parse_expect(struct nfattr *attr, struct ctnl_tuple *tuple, - struct ctnl_tuple *mask, unsigned long *timeout, - u_int32_t *id) -{ - struct nfattr *tb[CTA_EXPECT_MAX]; - - memset(tb, 0, CTA_EXPECT_MAX*sizeof(struct nfattr *)); - - nfnl_parse_nested(tb, CTA_EXPECT_MAX, attr); - if (tb[CTA_EXPECT_TUPLE-1]) - parse_tuple(tb[CTA_EXPECT_TUPLE-1], tuple); - if (tb[CTA_EXPECT_MASK-1]) - parse_tuple(tb[CTA_EXPECT_MASK-1], mask); - if (tb[CTA_EXPECT_TIMEOUT-1]) - *timeout = htonl(*(unsigned long *)NFA_DATA(tb[CTA_EXPECT_TIMEOUT-1])); - if (tb[CTA_EXPECT_ID-1]) - *id = htonl(*(u_int32_t *)NFA_DATA(tb[CTA_EXPECT_ID-1])); -} - static int expect_handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void *arg) { struct nfgenmsg *nfmsg; @@ -310,9 +291,19 @@ static int expect_handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void * while (NFA_OK(attr, attrlen)) { switch(attr->nfa_type) { - case CTA_EXPECT: - parse_expect(attr, &tuple, &mask, &timeout, - &id); + + case CTA_EXPECT_TUPLE: + parse_tuple(attr, &tuple); + break; + case CTA_EXPECT_MASK: + parse_tuple(attr, &mask); + break; + case CTA_EXPECT_TIMEOUT: + timeout = htonl(*(unsigned long *) + NFA_DATA(attr)); + break; + case CTA_EXPECT_ID: + id = htonl(*(u_int32_t *)NFA_DATA(attr)); break; } attr = NFA_NEXT(attr, attrlen); @@ -348,12 +339,12 @@ int create_conntrack(struct ctnl_tuple *orig, ct.tuple[CTNL_DIR_ORIGINAL] = *orig; ct.tuple[CTNL_DIR_REPLY] = *reply; ct.timeout = htonl(timeout); - ct.status = htonl(status); + ct.status = status; ct.protoinfo = *proto; if (range) ct.nat = *range; - if ((ret = ctnl_open(&cth, 0)) < 0) + if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK, 0)) < 0) return ret; ret = ctnl_new_conntrack(&cth, &ct); @@ -376,10 +367,10 @@ int update_conntrack(struct ctnl_tuple *orig, ct.tuple[CTNL_DIR_ORIGINAL] = *orig; ct.tuple[CTNL_DIR_REPLY] = *reply; ct.timeout = htonl(timeout); - ct.status = htonl(status); + ct.status = status; ct.protoinfo = *proto; - if ((ret = ctnl_open(&cth, 0)) < 0) + if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK, 0)) < 0) return ret; ret = ctnl_upd_conntrack(&cth, &ct); @@ -393,7 +384,7 @@ int delete_conntrack(struct ctnl_tuple *tuple, int dir) { int ret; - if ((ret = ctnl_open(&cth, 0)) < 0) + if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK, 0)) < 0) return ret; ret = ctnl_del_conntrack(&cth, tuple, dir); @@ -411,7 +402,7 @@ int get_conntrack(struct ctnl_tuple *tuple, int dir) }; int ret; - if ((ret = ctnl_open(&cth, 0)) < 0) + if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK, 0)) < 0) return ret; ctnl_register_handler(&cth, &h); @@ -430,7 +421,7 @@ int dump_conntrack_table(int zero) .handler = handler }; - if ((ret = ctnl_open(&cth, 0)) < 0) + if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK, 0)) < 0) return ret; ctnl_register_handler(&cth, &h); @@ -463,7 +454,7 @@ int event_conntrack(unsigned int event_mask) }; int ret; - if ((ret = ctnl_open(&cth, event_mask)) < 0) + if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK, event_mask)) < 0) return ret; signal(SIGINT, event_sighandler); @@ -527,7 +518,7 @@ int dump_expect_list() }; int ret; - if ((ret = ctnl_open(&cth, 0)) < 0) + if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK_EXP, 0)) < 0) return ret; ctnl_register_handler(&cth, &h); @@ -542,7 +533,7 @@ int flush_conntrack() { int ret; - if ((ret = ctnl_open(&cth, 0)) < 0) + if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK, 0)) < 0) return ret; ret = ctnl_flush_conntrack(&cth); @@ -551,8 +542,7 @@ int flush_conntrack() return ret; } -int get_expect(struct ctnl_tuple *tuple, - enum ctattr_type t) +int get_expect(struct ctnl_tuple *tuple) { struct ctnl_msg_handler h = { .type = IPCTNL_MSG_EXP_NEW, @@ -560,43 +550,42 @@ int get_expect(struct ctnl_tuple *tuple, }; int ret; - if ((ret = ctnl_open(&cth, 0)) < 0) + if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK_EXP, 0)) < 0) return 0; ctnl_register_handler(&cth, &h); - ret = ctnl_get_expect(&cth, tuple, t); + ret = ctnl_get_expect(&cth, tuple); ctnl_close(&cth); return ret; } int create_expectation(struct ctnl_tuple *tuple, - enum ctattr_type t, struct ctnl_tuple *exptuple, struct ctnl_tuple *mask, unsigned long timeout) { int ret; - if ((ret = ctnl_open(&cth, 0)) < 0) + if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK_EXP, 0)) < 0) return ret; - ret = ctnl_new_expect(&cth, tuple, t, exptuple, mask, timeout); + ret = ctnl_new_expect(&cth, tuple, exptuple, mask, timeout); ctnl_close(&cth); return ret; } -int delete_expectation(struct ctnl_tuple *tuple, enum ctattr_type t) +int delete_expectation(struct ctnl_tuple *tuple) { int ret; - if ((ret = ctnl_open(&cth, 0)) < 0) + if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK_EXP, 0)) < 0) return ret; - ret = ctnl_del_expect(&cth, tuple, t); + ret = ctnl_del_expect(&cth, tuple); ctnl_close(&cth); return ret; @@ -614,7 +603,7 @@ int event_expectation(unsigned int event_mask) }; int ret; - if ((ret = ctnl_open(&cth, event_mask)) < 0) + if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK_EXP, event_mask)) < 0) return ret; ctnl_register_handler(&cth, &hnew); @@ -629,7 +618,7 @@ int flush_expectation() { int ret; - if ((ret = ctnl_open(&cth, 0)) < 0) + if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK_EXP, 0)) < 0) return ret; ret = ctnl_flush_expect(&cth); -- cgit v1.2.3 From f4d2d25300de7169a02bf48d0bcbf6d3d592cf8f 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: Tue, 30 Aug 2005 23:59:05 +0000 Subject: o Fix packet and bytes counters (use __be64_to_cpu) --- ChangeLog | 4 ++++ src/libct.c | 30 ++++++++++++++++++++++++++++-- 2 files changed, 32 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 0ae9fc5..97d599a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2005-08-31 + + o Fix packet and bytes counters (use __be64_to_cpu) + 2005-07-12 o Use conntrack netlink attributes: Major change diff --git a/src/libct.c b/src/libct.c index e03c02a..a3560d2 100644 --- a/src/libct.c +++ b/src/libct.c @@ -109,6 +109,30 @@ static void parse_protoinfo(struct nfattr *attr, struct ctnl_conntrack *ct) h->parse_protoinfo(tb, ct); } +/* Pablo: What is the equivalence of be64_to_cpu in userspace? + * + * Harald: Good question. I don't think there's a standard way [yet?], + * so I'd suggest manually implementing it by "#if little endian" bitshift + * operations in C (at least for now). + * + * All the payload of any nfattr will always be in network byte order. + * This would allow easy transport over a real network in the future + * (e.g. jamal's netlink2). + * + * Pablo: I've called it __be64_to_cpu instead of be64_to_cpu, since maybe + * there will one in the userspace headers someday. We don't want to + * pollute POSIX space naming, + */ + +#include +#if __BYTE_ORDER == __BIG_ENDIAN +# define __be64_to_cpu(x) (x) +# else +# if __BYTE_ORDER == __LITTLE_ENDIAN +# define __be64_to_cpu(x) __bswap_64(x) +# endif +#endif + static void parse_counters(struct nfattr *attr, struct ctnl_conntrack *ct, enum ctattr_type parent) { @@ -119,10 +143,12 @@ static void parse_counters(struct nfattr *attr, struct ctnl_conntrack *ct, nfnl_parse_nested(tb, CTA_COUNTERS_MAX, attr); if (tb[CTA_COUNTERS_PACKETS-1]) ct->counters[CTNL_DIR_ORIGINAL].packets - = *(u_int64_t *)NFA_DATA(tb[CTA_COUNTERS_PACKETS-1]); + = __be64_to_cpu(*(u_int64_t *) + NFA_DATA(tb[CTA_COUNTERS_PACKETS-1])); if (tb[CTA_COUNTERS_BYTES-1]) ct->counters[CTNL_DIR_ORIGINAL].bytes - = *(u_int64_t *)NFA_DATA(tb[CTA_COUNTERS_BYTES-1]); + = __be64_to_cpu(*(u_int64_t *) + NFA_DATA(tb[CTA_COUNTERS_BYTES-1])); } /* Some people seem to like counting in decimal... */ -- cgit v1.2.3 From 6441e0d758fe88e2b20bb433cebf29757ed6a449 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: Wed, 31 Aug 2005 00:01:36 +0000 Subject: Fix ip_conntrack_netlink load-on-demand --- ChangeLog | 1 + src/conntrack.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 97d599a..e4573e9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,7 @@ 2005-08-31 o Fix packet and bytes counters (use __be64_to_cpu) + o Fix ip_conntrack_netlink load-on-demand 2005-07-12 diff --git a/src/conntrack.c b/src/conntrack.c index 12825b4..115cc62 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -969,7 +969,7 @@ int main(int argc, char *argv[]) break; } /* Maybe ip_conntrack_netlink isn't insmod'ed */ - if (res == -1 && retry) + if (res < 0 && retry) /* Give it a try just once */ iptables_insmod("ip_conntrack_netlink", NULL); else -- cgit v1.2.3 From 1291bc274e547a6ba81fdc38baf563ccb7054064 Mon Sep 17 00:00:00 2001 From: "/C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=laforge/emailAddress=laforge@netfilter.org" Date: Sat, 24 Sep 2005 17:53:24 +0000 Subject: get rid of old "-A" stuff --- src/conntrack.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index 115cc62..f9df119 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -27,6 +27,8 @@ * Add support for conntrack accounting and conntrack mark * 2005-06-23 Harald Welte : * Add support for expect creation + * 2005-09-24 Harald Welte : + * Remove remaints of "-A" * */ #include @@ -175,7 +177,6 @@ static struct option original_opts[] = { {"get", 1, 0, 'G'}, {"flush", 1, 0, 'F'}, {"event", 1, 0, 'E'}, - {"action", 1, 0, 'A'}, {"version", 0, 0, 'V'}, {"help", 0, 0, 'h'}, {"orig-src", 1, 0, 's'}, @@ -637,7 +638,6 @@ fprintf(stdout, "-I [table] parameters Create a conntrack or expectation\n"); fprintf(stdout, "-U [table] parameters Update a conntrack\n"); fprintf(stdout, "-E [table] [options] Show events\n"); fprintf(stdout, "-F [table] Flush table\n"); -fprintf(stdout, "-A [table] [options] Set action\n"); fprintf(stdout, "\n"); fprintf(stdout, "Options:\n"); fprintf(stdout, "--orig-src ip Source address from original direction\n"); @@ -682,7 +682,7 @@ int main(int argc, char *argv[]) memset(&range, 0, sizeof(struct ctnl_nat)); while ((c = getopt_long(argc, argv, - "L::I::U::D::G::E::A::F::hVs:d:r:q:p:t:u:e:a:z[:]:{:}:", + "L::I::U::D::G::E::F::hVs:d:r:q:p:t:u:e:a:z[:]:{:}:", opts, NULL)) != -1) { switch(c) { case 'L': -- cgit v1.2.3 From 53aff5a51af588ed1bdd94c9915fc610487c26c0 Mon Sep 17 00:00:00 2001 From: "/C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=laforge/emailAddress=laforge@netfilter.org" Date: Sat, 24 Sep 2005 17:57:44 +0000 Subject: get rid of c++ style comments --- src/conntrack.c | 4 ++-- src/libct.c | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index f9df119..07d15f6 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -592,13 +592,13 @@ nat_parse(char *arg, int portok, struct ctnl_nat *range) exit_error(PARAMETER_PROBLEM, "Port `%s' not valid\n", dash+1); if (maxport < port) - // People are stupid. + /* People are stupid. */ exit_error(PARAMETER_PROBLEM, "Port range `%s' funky\n", colon+1); range->l4min.tcp.port = htons(port); range->l4max.tcp.port = htons(maxport); } - // Starts with a colon? No IP info... + /* Starts with a colon? No IP info... */ if (colon == arg) return; *colon = '\0'; diff --git a/src/libct.c b/src/libct.c index a3560d2..7c1160a 100644 --- a/src/libct.c +++ b/src/libct.c @@ -174,7 +174,6 @@ static int handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void *arg) memset(&ct, 0, sizeof(struct ctnl_conntrack)); nfmsg = NLMSG_DATA(nlh); -// min_len = sizeof(struct nfgenmsg); if (nlh->nlmsg_len < min_len) return -EINVAL; -- cgit v1.2.3 From 41796b0c80876094f3db8af0efae16d162788793 Mon Sep 17 00:00:00 2001 From: "/C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=laforge/emailAddress=laforge@netfilter.org" Date: Sat, 24 Sep 2005 18:42:39 +0000 Subject: major update (See ChangeLog) --- ChangeLog | 9 +++++++++ configure.in | 8 ++++---- conntrack.8 | 15 +-------------- extensions/libct_proto_icmp.c | 3 ++- extensions/libct_proto_sctp.c | 3 ++- extensions/libct_proto_tcp.c | 6 ++++-- extensions/libct_proto_udp.c | 3 ++- include/libct_proto.h | 3 +++ src/conntrack.c | 7 ++----- src/libct.c | 30 +++++++++++++++++------------- 10 files changed, 46 insertions(+), 41 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index e4573e9..87daa18 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2005-09-24 + + o Get rid of C++ style comments + o Remove remaining bits of "-A --action", group-mask and dump-mask + o Clean up #include's + o Fix double-free when exiting via signal handler (Ctrl+C) + o Add "version" member to plugins + o Fix some Endianness issues when printing CTA_STATUS + 2005-08-31 o Fix packet and bytes counters (use __be64_to_cpu) diff --git a/configure.in b/configure.in index cd8f37f..8956e34 100644 --- a/configure.in +++ b/configure.in @@ -74,10 +74,10 @@ AC_ARG_WITH(kernel, [ Show location of kernel source. Default is to use uname -r and look in /lib/modules/KERNEL/build/include. ]), NF_KERNEL_SOURCE($with_kernel),NF_KERNEL_SOURCE()) -#if test ! -z "$libdir"; then -# MODULE_DIR="\\\"$libdir/\\\"" -# CFLAGS="$CFLAGS -DCONNTRACK_LIB_DIR=$MODULE_DIR" -#fi +if test ! -z "$libdir"; then + MODULE_DIR="\\\"$libdir/\\\"" + CFLAGS="$CFLAGS -DCONNTRACK_LIB_DIR=$MODULE_DIR" +fi dnl-------------------------------- diff --git a/conntrack.8 b/conntrack.8 index 5ba8494..c8d07d1 100644 --- a/conntrack.8 +++ b/conntrack.8 @@ -16,8 +16,6 @@ conntrack \- administration tool for netfilter connection tracking .BR "conntrack -E [table] parameters" .br .BR "conntrack -F [table]" -.br -.BR "conntrack -A [table] [options]" .SH DESCRIPTION .B conntrack is used to search, list, inspect and maintain the netfilter connection tracking @@ -70,9 +68,6 @@ Display a real-time event log. .TP .BI "-F, --flush " Flush the whole given table -.TP -.BI "-A, --action " -Set an action. .SS PARAMETERS .TP .BI "-z, --zero " @@ -85,15 +80,7 @@ event code. Using this parameter, you can reduce the event messages generated by the kernel to those types to those that you are actually interested in. . Please note that this is a system-wide setting, so make sure to not disable some events that other ctnetlink-using processes might need! -This option can only be used in conjunction with "-A, --action". -.TP -.BI "-m, --dump-mask " "[ALL|TUPLE|STATUS|TIMEOUT|PROTOINFO|HELPINFO|COUNTERS|MARK][,...]" -Set the bitmask of data fields that are to be sent with each message generated -by the in-kernel ctnetlink code. Using this parameter, you can reduce the -amount of information sent by the kernel to those bits and pieces that you are -actually interested in. -Please note that this is a system-wide setting, so make sure to not disable some data fields that other ctnetlink-using processes might need! -This option can only be used in conjunction with "-A, --action". +This option can only be used in conjunction with "-E, --event". .TP .BI "-g, --group-mask " "[ALL|TCP|UDP|ICMP][,...]" Set the group bitmask to those netlink groups (resembling layer 4 protocols) diff --git a/extensions/libct_proto_icmp.c b/extensions/libct_proto_icmp.c index e0de27e..817fc77 100644 --- a/extensions/libct_proto_icmp.c +++ b/extensions/libct_proto_icmp.c @@ -111,7 +111,8 @@ static struct ctproto_handler icmp = { .print_proto = print_proto, .final_check = final_check, .help = help, - .opts = opts + .opts = opts, + .version = LIBCT_VERSION, }; void __attribute__ ((constructor)) init(void); diff --git a/extensions/libct_proto_sctp.c b/extensions/libct_proto_sctp.c index 4dbdf27..9afb661 100644 --- a/extensions/libct_proto_sctp.c +++ b/extensions/libct_proto_sctp.c @@ -176,7 +176,8 @@ static struct ctproto_handler sctp = { .print_protoinfo = print_protoinfo, .final_check = final_check, .help = help, - .opts = opts + .opts = opts, + .version = LIBCT_VERSION, }; void __attribute__ ((constructor)) init(void); diff --git a/extensions/libct_proto_tcp.c b/extensions/libct_proto_tcp.c index 323e4ec..4f3094f 100644 --- a/extensions/libct_proto_tcp.c +++ b/extensions/libct_proto_tcp.c @@ -13,9 +13,10 @@ #include #include /* For htons */ #include -#include "libct_proto.h" #include +#include "libct_proto.h" + static struct option opts[] = { {"orig-port-src", 1, 0, '1'}, {"orig-port-dst", 1, 0, '2'}, @@ -197,7 +198,8 @@ static struct ctproto_handler tcp = { .print_protoinfo = print_protoinfo, .final_check = final_check, .help = help, - .opts = opts + .opts = opts, + .version = LIBCT_VERSION, }; void __attribute__ ((constructor)) init(void); diff --git a/extensions/libct_proto_udp.c b/extensions/libct_proto_udp.c index 8a9f0cf..ecde5f2 100644 --- a/extensions/libct_proto_udp.c +++ b/extensions/libct_proto_udp.c @@ -149,7 +149,8 @@ static struct ctproto_handler udp = { .print_proto = print_proto, .final_check = final_check, .help = help, - .opts = opts + .opts = opts, + .version = LIBCT_VERSION, }; void __attribute__ ((constructor)) init(void); diff --git a/include/libct_proto.h b/include/libct_proto.h index dcf7009..8849a3e 100644 --- a/include/libct_proto.h +++ b/include/libct_proto.h @@ -7,6 +7,8 @@ #include #include +#define LIBCT_VERSION "0.1.0" + struct cta_proto; struct ctproto_handler { @@ -14,6 +16,7 @@ struct ctproto_handler { char *name; u_int16_t protonum; + char *version; enum ctattr_protoinfo protoinfo_attr; diff --git a/src/conntrack.c b/src/conntrack.c index 07d15f6..3731d0e 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -43,13 +43,12 @@ #include #include #include -#include #include #include "linux_list.h" #include "libct_proto.h" #define PROGNAME "conntrack" -#define VERSION "0.80" +#define VERSION "0.81" #if 0 #define DEBUGP printf @@ -651,8 +650,6 @@ fprintf(stdout, "--mask-dst ip Destination mask address for expectations\n"); fprintf(stdout, "-p proto Layer 4 Protocol\n"); fprintf(stdout, "-t timeout Set timeout\n"); fprintf(stdout, "-u status Set status\n"); -fprintf(stdout, "-m dumpmask Set dump mask\n"); -fprintf(stdout, "-g groupmask Set group mask\n"); fprintf(stdout, "-e eventmask Set event mask\n"); fprintf(stdout, "-a min_ip[-max_ip] NAT ip range\n"); fprintf(stdout, "-z Zero Counters\n"); @@ -670,7 +667,7 @@ int main(int argc, char *argv[]) unsigned long timeout = 0; unsigned int status = IPS_CONFIRMED; unsigned long id = 0; - unsigned int type = 0, dump_mask = 0, extra_flags = 0, event_mask = 0; + unsigned int type = 0, extra_flags = 0, event_mask = 0; int manip = -1; int res = 0, retry = 2; diff --git a/src/libct.c b/src/libct.c index 7c1160a..01307f2 100644 --- a/src/libct.c +++ b/src/libct.c @@ -17,9 +17,6 @@ /* From kernel.h */ #define INT_MAX ((int)(~0U>>1)) #define INT_MIN (-INT_MAX - 1) -#include -#include -#include #include #include "linux_list.h" #include "libct_proto.h" @@ -187,7 +184,7 @@ static int handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void *arg) parse_tuple(attr, &ct.tuple[CTNL_DIR_REPLY]); break; case CTA_STATUS: - ct.status = *(unsigned int *)NFA_DATA(attr); + ct.status = ntohl(*(u_int32_t *)NFA_DATA(attr)); flags |= STATUS; break; case CTA_PROTOINFO: @@ -195,11 +192,11 @@ static int handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void *arg) flags |= PROTOINFO; break; case CTA_TIMEOUT: - ct.timeout = ntohl(*(unsigned long *)NFA_DATA(attr)); + ct.timeout = ntohl(*(u_int32_t *)NFA_DATA(attr)); flags |= TIMEOUT; break; case CTA_MARK: - ct.mark = ntohl(*(unsigned long *)NFA_DATA(attr)); + ct.mark = ntohl(*(u_int32_t *)NFA_DATA(attr)); flags |= MARK; break; case CTA_COUNTERS_ORIG: @@ -208,7 +205,7 @@ static int handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void *arg) flags |= COUNTERS; break; case CTA_USE: - ct.use = ntohl(*(unsigned int *)NFA_DATA(attr)); + ct.use = ntohl(*(u_int32_t *)NFA_DATA(attr)); flags |= USE; break; case CTA_ID: @@ -256,7 +253,8 @@ static int handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void *arg) ct.counters[CTNL_DIR_REPLY].packets, ct.counters[CTNL_DIR_REPLY].bytes); - print_status(ct.status); + if (flags & STATUS) + print_status(ct.status); if (flags & MARK) fprintf(stdout, "mark=%lu ", ct.mark); @@ -272,15 +270,15 @@ static int handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void *arg) static char *typemsg2str(type, flags) { - char *ret = "UNKNOWN"; + char *ret = "[UNKNOWN]"; if (type == IPCTNL_MSG_CT_NEW) { if (flags & NLM_F_CREATE) - ret = "NEW"; + ret = "[NEW]"; else - ret = "UPDATE"; + ret = "[UPDATE]"; } else if (type == IPCTNL_MSG_CT_DELETE) - ret = "DESTROY"; + ret = "[DESTROY]"; return ret; } @@ -289,7 +287,7 @@ static int event_handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void *arg) { int type = NFNL_MSG_TYPE(nlh->nlmsg_type); - fprintf(stdout, "[%s] ", typemsg2str(type, nlh->nlmsg_flags)); + fprintf(stdout, "%9s ", typemsg2str(type, nlh->nlmsg_flags)); return handler(sock, nlh, arg); } @@ -465,6 +463,7 @@ static void event_sighandler(int s) { fprintf(stdout, "Now closing conntrack event dumping...\n"); ctnl_close(&cth); + exit(0); } int event_conntrack(unsigned int event_mask) @@ -527,6 +526,11 @@ struct ctproto_handler *findproto(char *name) void register_proto(struct ctproto_handler *h) { + if (strcmp(h->version, LIBCT_VERSION) != 0) { + fprintf(stderr, "plugin `%s': version %s (I'm %s)\n", + h->name, h->version, LIBCT_VERSION); + exit(1); + } list_add(&h->head, &proto_list); } -- cgit v1.2.3 From f179e8af468c573d4a643fcd38980e0beeeecdbc 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: Wed, 5 Oct 2005 16:33:52 +0000 Subject: o Fix up counters o Fix up compilation (IPS_* stuff missing), still need a proper fix --- ChangeLog | 6 ++++++ include/libct_proto.h | 7 +++++++ src/conntrack.c | 2 +- src/libct.c | 6 ++++-- 4 files changed, 18 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 87daa18..f9b93a2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2005-10-05 + + o Fix up counters + o Fix up compilation (IPS_* stuff missing), still need a proper fix + o Bumped version number to 0.82 + 2005-09-24 o Get rid of C++ style comments diff --git a/include/libct_proto.h b/include/libct_proto.h index 8849a3e..b358e1a 100644 --- a/include/libct_proto.h +++ b/include/libct_proto.h @@ -9,6 +9,13 @@ #define LIBCT_VERSION "0.1.0" +/* FIXME: These should be independent from kernel space */ +#define IPS_ASSURED (1 << 2) +#define IPS_SEEN_REPLY (1 << 1) +#define IPS_SRC_NAT_DONE (1 << 7) +#define IPS_DST_NAT_DONE (1 << 8) +#define IPS_CONFIRMED (1 << 3) + struct cta_proto; struct ctproto_handler { diff --git a/src/conntrack.c b/src/conntrack.c index 3731d0e..1d5227e 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -48,7 +48,7 @@ #include "libct_proto.h" #define PROGNAME "conntrack" -#define VERSION "0.81" +#define VERSION "0.82" #if 0 #define DEBUGP printf diff --git a/src/libct.c b/src/libct.c index 01307f2..16ec4db 100644 --- a/src/libct.c +++ b/src/libct.c @@ -134,16 +134,18 @@ static void parse_counters(struct nfattr *attr, struct ctnl_conntrack *ct, enum ctattr_type parent) { struct nfattr *tb[CTA_COUNTERS_MAX]; + int dir = (parent == CTA_COUNTERS_ORIG ? CTNL_DIR_REPLY + : CTNL_DIR_ORIGINAL); memset(tb, 0, CTA_COUNTERS_MAX*sizeof(struct nfattr *)); nfnl_parse_nested(tb, CTA_COUNTERS_MAX, attr); if (tb[CTA_COUNTERS_PACKETS-1]) - ct->counters[CTNL_DIR_ORIGINAL].packets + 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[CTNL_DIR_ORIGINAL].bytes + ct->counters[dir].bytes = __be64_to_cpu(*(u_int64_t *) NFA_DATA(tb[CTA_COUNTERS_BYTES-1])); } -- cgit v1.2.3 From cce8dd1bd45465dd9b18e4f02b5d007cb39079b0 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: Fri, 7 Oct 2005 13:09:22 +0000 Subject: See Changelog --- ChangeLog | 7 +++++++ extensions/libct_proto_icmp.c | 32 +++++++++++++++++++++++++------- src/libct.c | 2 +- 3 files changed, 33 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index f9b93a2..1a44a43 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2005-10-07 + + o Fixed ICMP options + + o Multiple fixes for the ICMP protocol handler + o Fix ICMP output: wrong output. type and code were set to zero. + 2005-10-05 o Fix up counters diff --git a/extensions/libct_proto_icmp.c b/extensions/libct_proto_icmp.c index 817fc77..be81507 100644 --- a/extensions/libct_proto_icmp.c +++ b/extensions/libct_proto_icmp.c @@ -12,12 +12,13 @@ #include #include #include /* For htons */ +#include #include "libct_proto.h" static struct option opts[] = { - {"--icmp-type", 1, 0, '1'}, - {"--icmp-code", 1, 0, '2'}, - {"--icmp-id", 1, 0, '3'}, + {"icmp-type", 1, 0, '1'}, + {"icmp-code", 1, 0, '2'}, + {"icmp-id", 1, 0, '3'}, {0, 0, 0, 0} }; @@ -39,6 +40,17 @@ void help() fprintf(stdout, "--icmp-id icmp id\n"); } +/* Add 1; spaces filled with 0. */ +static u_int8_t invmap[] + = { [ICMP_ECHO] = ICMP_ECHOREPLY + 1, + [ICMP_ECHOREPLY] = ICMP_ECHO + 1, + [ICMP_TIMESTAMP] = ICMP_TIMESTAMPREPLY + 1, + [ICMP_TIMESTAMPREPLY] = ICMP_TIMESTAMP + 1, + [ICMP_INFO_REQUEST] = ICMP_INFO_REPLY + 1, + [ICMP_INFO_REPLY] = ICMP_INFO_REQUEST + 1, + [ICMP_ADDRESS] = ICMP_ADDRESSREPLY + 1, + [ICMP_ADDRESSREPLY] = ICMP_ADDRESS + 1}; + int parse(char c, char *argv[], struct ctnl_tuple *orig, struct ctnl_tuple *reply, @@ -50,18 +62,22 @@ int parse(char c, char *argv[], case '1': if (optarg) { orig->l4dst.icmp.type = atoi(optarg); + reply->l4dst.icmp.type = + invmap[orig->l4dst.icmp.type] - 1; *flags |= ICMP_TYPE; } break; case '2': if (optarg) { orig->l4dst.icmp.code = atoi(optarg); + reply->l4dst.icmp.code = 0; *flags |= ICMP_CODE; } break; case '3': if (optarg) { orig->l4src.icmp.id = atoi(optarg); + reply->l4dst.icmp.id = 0; *flags |= ICMP_ID; } break; @@ -81,7 +97,7 @@ void parse_proto(struct nfattr *cda[], struct ctnl_tuple *tuple) if (cda[CTA_PROTO_ICMP_ID-1]) tuple->l4src.icmp.id = - *(u_int8_t *)NFA_DATA(cda[CTA_PROTO_ICMP_ID-1]); + *(u_int16_t *)NFA_DATA(cda[CTA_PROTO_ICMP_ID-1]); } int final_check(unsigned int flags, @@ -98,9 +114,11 @@ int final_check(unsigned int flags, void print_proto(struct ctnl_tuple *t) { - fprintf(stdout, "type=%d code=%d id=%d ", t->l4dst.icmp.type, - t->l4dst.icmp.code, - t->l4src.icmp.id); + fprintf(stdout, "type=%d code=%d ", t->l4dst.icmp.type, + t->l4dst.icmp.code); + /* ID only makes sense with ECHO */ + if (t->l4dst.icmp.type == 8) + fprintf(stdout, "id=%d ", t->l4src.icmp.id); } static struct ctproto_handler icmp = { diff --git a/src/libct.c b/src/libct.c index 16ec4db..36aacbd 100644 --- a/src/libct.c +++ b/src/libct.c @@ -70,7 +70,7 @@ static void parse_proto(struct nfattr *attr, struct ctnl_tuple *tuple) memset(tb, 0, CTA_PROTO_MAX * sizeof(struct nfattr *)); - nfnl_parse_nested(tb, CTA_IP_MAX, attr); + 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]); -- cgit v1.2.3 From da9b980f8d34c436b31d5a0a09b4ea27849c9c82 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 21:13:29 +0000 Subject: See ChangeLog --- ChangeLog | 8 + Makefile.am | 2 +- configure.in | 4 +- extensions/libct_proto_icmp.c | 41 +-- extensions/libct_proto_sctp.c | 31 +- extensions/libct_proto_tcp.c | 49 +--- extensions/libct_proto_udp.c | 35 +-- include/libct_proto.h | 25 +- src/Makefile.am | 2 +- src/conntrack.c | 263 ++++++++++++----- src/libct.c | 660 ------------------------------------------ 11 files changed, 253 insertions(+), 867 deletions(-) delete mode 100644 src/libct.c (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 1a44a43..2942f78 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2005-10-14 + + o Kill config.h.in, it's generated by the autocrap + o The conntrack tool now uses libnetfilter_conntrack :) + o libct.c has been killed, now it's in libnetfilter_conntrack + o Check if you're root or CAP_NET_ADMIN + o Bumped version number to 0.86 + 2005-10-07 o Fixed ICMP options diff --git a/Makefile.am b/Makefile.am index 18a67c6..8d9faf6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -9,7 +9,7 @@ EXTRA_DIST = $(man_MANS) INCLUDES = $(all_includes) -I$(top_srcdir)/include -I${KERNELDIR} SUBDIRS = src extensions DIST_SUBDIRS = include src extensions -LINKOPTS = -ldl -lnfnetlink -lnfnetlink_conntrack +LINKOPTS = -ldl -lnfnetlink -lnetfilter_conntrack AM_CFLAGS = -g $(OBJECTS): libtool diff --git a/configure.in b/configure.in index cd6d7b5..0f0fc5f 100644 --- a/configure.in +++ b/configure.in @@ -2,7 +2,7 @@ AC_INIT AC_CANONICAL_SYSTEM -AM_INIT_AUTOMAKE(conntrack, 0.81) +AM_INIT_AUTOMAKE(conntrack, 0.63) AM_CONFIG_HEADER(config.h) AC_PROG_CC @@ -22,7 +22,7 @@ dnl AC_CHECK_LIB([c], [main]) AC_CHECK_LIB([dl], [dlopen]) AC_CHECK_LIB([nfnetlink], [nfnl_listen]) -AC_CHECK_LIB([nfnetlink_conntrack], [ctnl_register_handler] ,,,[-lnfnetlink]) +AC_CHECK_LIB([netfilter_conntrack], [nfct_dump_conntrack_table] ,,,[-lnetfilter_conntrack]) # Checks for header files. dnl AC_HEADER_STDC diff --git a/extensions/libct_proto_icmp.c b/extensions/libct_proto_icmp.c index be81507..7142fa7 100644 --- a/extensions/libct_proto_icmp.c +++ b/extensions/libct_proto_icmp.c @@ -13,6 +13,7 @@ #include #include /* For htons */ #include +#include #include "libct_proto.h" static struct option opts[] = { @@ -52,10 +53,10 @@ static u_int8_t invmap[] [ICMP_ADDRESSREPLY] = ICMP_ADDRESS + 1}; int parse(char c, char *argv[], - struct ctnl_tuple *orig, - struct ctnl_tuple *reply, - struct ctnl_tuple *mask, - union ctnl_protoinfo *proto, + struct nfct_tuple *orig, + struct nfct_tuple *reply, + struct nfct_tuple *mask, + union nfct_protoinfo *proto, unsigned int *flags) { switch(c) { @@ -85,24 +86,9 @@ int parse(char c, char *argv[], return 1; } -void parse_proto(struct nfattr *cda[], struct ctnl_tuple *tuple) -{ - if (cda[CTA_PROTO_ICMP_TYPE-1]) - tuple->l4dst.icmp.type = - *(u_int8_t *)NFA_DATA(cda[CTA_PROTO_ICMP_TYPE-1]); - - if (cda[CTA_PROTO_ICMP_CODE-1]) - tuple->l4dst.icmp.code = - *(u_int8_t *)NFA_DATA(cda[CTA_PROTO_ICMP_CODE-1]); - - if (cda[CTA_PROTO_ICMP_ID-1]) - tuple->l4src.icmp.id = - *(u_int16_t *)NFA_DATA(cda[CTA_PROTO_ICMP_ID-1]); -} - int final_check(unsigned int flags, - struct ctnl_tuple *orig, - struct ctnl_tuple *reply) + struct nfct_tuple *orig, + struct nfct_tuple *reply) { if (!(flags & ICMP_TYPE)) return 0; @@ -112,21 +98,10 @@ int final_check(unsigned int flags, return 1; } -void print_proto(struct ctnl_tuple *t) -{ - fprintf(stdout, "type=%d code=%d ", t->l4dst.icmp.type, - t->l4dst.icmp.code); - /* ID only makes sense with ECHO */ - if (t->l4dst.icmp.type == 8) - fprintf(stdout, "id=%d ", t->l4src.icmp.id); -} - static struct ctproto_handler icmp = { .name = "icmp", - .protonum = 1, + .protonum = IPPROTO_ICMP, .parse_opts = parse, - .parse_proto = parse_proto, - .print_proto = print_proto, .final_check = final_check, .help = help, .opts = opts, diff --git a/extensions/libct_proto_sctp.c b/extensions/libct_proto_sctp.c index 9afb661..bc91966 100644 --- a/extensions/libct_proto_sctp.c +++ b/extensions/libct_proto_sctp.c @@ -12,9 +12,8 @@ #include #include #include /* For htons */ -#include #include "libct_proto.h" -#include +#include static struct option opts[] = { {"orig-port-src", 1, 0, '1'}, @@ -63,10 +62,10 @@ void help() } int parse_options(char c, char *argv[], - struct ctnl_tuple *orig, - struct ctnl_tuple *reply, - struct ctnl_tuple *mask, - union ctnl_protoinfo *proto, + struct nfct_tuple *orig, + struct nfct_tuple *reply, + struct nfct_tuple *mask, + union nfct_protoinfo *proto, unsigned int *flags) { switch(c) { @@ -100,7 +99,7 @@ int parse_options(char c, char *argv[], for (i=0; i<10; i++) { if (strcmp(optarg, states[i]) == 0) { /* FIXME: Add state to - * ctnl_protoinfo + * nfct_protoinfo proto->sctp.state = i; */ break; } @@ -116,8 +115,8 @@ int parse_options(char c, char *argv[], } int final_check(unsigned int flags, - struct ctnl_tuple *orig, - struct ctnl_tuple *reply) + struct nfct_tuple *orig, + struct nfct_tuple *reply) { if ((flags & (ORIG_SPORT|ORIG_DPORT)) && !(flags & (REPL_SPORT|REPL_DPORT))) { @@ -137,7 +136,7 @@ int final_check(unsigned int flags, return 0; } -void parse_proto(struct nfattr *cda[], struct ctnl_tuple *tuple) +void parse_proto(struct nfattr *cda[], struct nfct_tuple *tuple) { if (cda[CTA_PROTO_SRC_PORT-1]) tuple->l4src.sctp.port = @@ -147,7 +146,7 @@ void parse_proto(struct nfattr *cda[], struct ctnl_tuple *tuple) *(u_int16_t *)NFA_DATA(cda[CTA_PROTO_DST_PORT-1]); } -void parse_protoinfo(struct nfattr *cda[], struct ctnl_conntrack *ct) +void parse_protoinfo(struct nfattr *cda[], struct nfct_conntrack *ct) { /* if (cda[CTA_PROTOINFO_SCTP_STATE-1]) ct->protoinfo.sctp.state = @@ -155,12 +154,12 @@ void parse_protoinfo(struct nfattr *cda[], struct ctnl_conntrack *ct) */ } -void print_protoinfo(union ctnl_protoinfo *protoinfo) +void print_protoinfo(union nfct_protoinfo *protoinfo) { /* fprintf(stdout, "%s ", states[protoinfo->sctp.state]); */ } -void print_proto(struct ctnl_tuple *tuple) +void print_proto(struct nfct_tuple *tuple) { fprintf(stdout, "sport=%u dport=%u ", htons(tuple->l4src.sctp.port), htons(tuple->l4dst.sctp.port)); @@ -168,12 +167,8 @@ void print_proto(struct ctnl_tuple *tuple) static struct ctproto_handler sctp = { .name = "sctp", - .protonum = 132, + .protonum = IPPROTO_SCTP, .parse_opts = parse_options, - .parse_protoinfo = parse_protoinfo, - .parse_proto = parse_proto, - .print_proto = print_proto, - .print_protoinfo = print_protoinfo, .final_check = final_check, .help = help, .opts = opts, diff --git a/extensions/libct_proto_tcp.c b/extensions/libct_proto_tcp.c index 4f3094f..3b06aa2 100644 --- a/extensions/libct_proto_tcp.c +++ b/extensions/libct_proto_tcp.c @@ -12,8 +12,7 @@ #include #include #include /* For htons */ -#include -#include +#include #include "libct_proto.h" @@ -76,10 +75,10 @@ void help() } int parse_options(char c, char *argv[], - struct ctnl_tuple *orig, - struct ctnl_tuple *reply, - struct ctnl_tuple *mask, - union ctnl_protoinfo *proto, + struct nfct_tuple *orig, + struct nfct_tuple *reply, + struct nfct_tuple *mask, + union nfct_protoinfo *proto, unsigned int *flags) { switch(c) { @@ -139,8 +138,8 @@ int parse_options(char c, char *argv[], } int final_check(unsigned int flags, - struct ctnl_tuple *orig, - struct ctnl_tuple *reply) + struct nfct_tuple *orig, + struct nfct_tuple *reply) { if ((flags & (ORIG_SPORT|ORIG_DPORT)) && !(flags & (REPL_SPORT|REPL_DPORT))) { @@ -160,42 +159,10 @@ int final_check(unsigned int flags, return 0; } -void parse_proto(struct nfattr *cda[], struct ctnl_tuple *tuple) -{ - if (cda[CTA_PROTO_SRC_PORT-1]) - tuple->l4src.tcp.port = - *(u_int16_t *)NFA_DATA(cda[CTA_PROTO_SRC_PORT-1]); - if (cda[CTA_PROTO_DST_PORT-1]) - tuple->l4dst.tcp.port = - *(u_int16_t *)NFA_DATA(cda[CTA_PROTO_DST_PORT-1]); -} - -void parse_protoinfo(struct nfattr *cda[], struct ctnl_conntrack *ct) -{ - if (cda[CTA_PROTOINFO_TCP_STATE-1]) - ct->protoinfo.tcp.state = - *(u_int8_t *)NFA_DATA(cda[CTA_PROTOINFO_TCP_STATE-1]); -} - -void print_protoinfo(union ctnl_protoinfo *protoinfo) -{ - fprintf(stdout, "%s ", states[protoinfo->tcp.state]); -} - -void print_proto(struct ctnl_tuple *tuple) -{ - fprintf(stdout, "sport=%u dport=%u ", htons(tuple->l4src.tcp.port), - htons(tuple->l4dst.tcp.port)); -} - static struct ctproto_handler tcp = { .name = "tcp", - .protonum = 6, + .protonum = IPPROTO_TCP, .parse_opts = parse_options, - .parse_protoinfo = parse_protoinfo, - .parse_proto = parse_proto, - .print_proto = print_proto, - .print_protoinfo = print_protoinfo, .final_check = final_check, .help = help, .opts = opts, diff --git a/extensions/libct_proto_udp.c b/extensions/libct_proto_udp.c index ecde5f2..8e77f0c 100644 --- a/extensions/libct_proto_udp.c +++ b/extensions/libct_proto_udp.c @@ -11,9 +11,8 @@ #include #include #include /* For htons */ -#include #include "libct_proto.h" -#include +#include static struct option opts[] = { {"orig-port-src", 1, 0, '1'}, @@ -56,10 +55,10 @@ void help() } int parse_options(char c, char *argv[], - struct ctnl_tuple *orig, - struct ctnl_tuple *reply, - struct ctnl_tuple *mask, - union ctnl_protoinfo *proto, + struct nfct_tuple *orig, + struct nfct_tuple *reply, + struct nfct_tuple *mask, + union nfct_protoinfo *proto, unsigned int *flags) { switch(c) { @@ -104,8 +103,8 @@ int parse_options(char c, char *argv[], } int final_check(unsigned int flags, - struct ctnl_tuple *orig, - struct ctnl_tuple *reply) + struct nfct_tuple *orig, + struct nfct_tuple *reply) { if ((flags & (ORIG_SPORT|ORIG_DPORT)) && !(flags & (REPL_SPORT|REPL_DPORT))) { @@ -125,28 +124,10 @@ int final_check(unsigned int flags, return 0; } -void parse_proto(struct nfattr *cda[], struct ctnl_tuple *tuple) -{ - if (cda[CTA_PROTO_SRC_PORT-1]) - tuple->l4src.udp.port = - *(u_int16_t *)NFA_DATA(cda[CTA_PROTO_SRC_PORT-1]); - if (cda[CTA_PROTO_DST_PORT-1]) - tuple->l4dst.udp.port = - *(u_int16_t *)NFA_DATA(cda[CTA_PROTO_DST_PORT-1]); -} - -void print_proto(struct ctnl_tuple *tuple) -{ - fprintf(stdout, "sport=%u dport=%u ", htons(tuple->l4src.udp.port), - htons(tuple->l4dst.udp.port)); -} - static struct ctproto_handler udp = { .name = "udp", - .protonum = 17, + .protonum = IPPROTO_UDP, .parse_opts = parse_options, - .parse_proto = parse_proto, - .print_proto = print_proto, .final_check = final_check, .help = help, .opts = opts, diff --git a/include/libct_proto.h b/include/libct_proto.h index b358e1a..db434d6 100644 --- a/include/libct_proto.h +++ b/include/libct_proto.h @@ -1,11 +1,9 @@ #ifndef _LIBCT_PROTO_H #define _LIBCT_PROTO_H -/* FIXME: Rename this file pablo... */ - #include "linux_list.h" #include -#include +#include #define LIBCT_VERSION "0.1.0" @@ -16,8 +14,6 @@ #define IPS_DST_NAT_DONE (1 << 8) #define IPS_CONFIRMED (1 << 3) -struct cta_proto; - struct ctproto_handler { struct list_head head; @@ -28,20 +24,15 @@ struct ctproto_handler { enum ctattr_protoinfo protoinfo_attr; int (*parse_opts)(char c, char *argv[], - struct ctnl_tuple *orig, - struct ctnl_tuple *reply, - struct ctnl_tuple *mask, - union ctnl_protoinfo *proto, + struct nfct_tuple *orig, + struct nfct_tuple *reply, + struct nfct_tuple *mask, + union nfct_protoinfo *proto, unsigned int *flags); - void (*parse_proto)(struct nfattr *cda[], struct ctnl_tuple *tuple); - void (*parse_protoinfo)(struct nfattr *cda[], - struct ctnl_conntrack *ct); - void (*print_proto)(struct ctnl_tuple *t); - void (*print_protoinfo)(union ctnl_protoinfo *protoinfo); int (*final_check)(unsigned int flags, - struct ctnl_tuple *orig, - struct ctnl_tuple *reply); + struct nfct_tuple *orig, + struct nfct_tuple *reply); void (*help)(); @@ -53,8 +44,6 @@ struct ctproto_handler { extern void register_proto(struct ctproto_handler *h); extern void unregister_proto(struct ctproto_handler *h); -extern struct ctproto_handler *findproto(char *name); - #define NIPQUAD(addr) \ ((unsigned char *)&addr)[0], \ ((unsigned char *)&addr)[1], \ diff --git a/src/Makefile.am b/src/Makefile.am index ae3f429..71ad3d5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,5 +1,5 @@ bin_PROGRAMS = conntrack -conntrack_SOURCES = conntrack.c libct.c +conntrack_SOURCES = conntrack.c INCLUDES= $(all_includes) -I$(top_srcdir)/include -I${KERNELDIR} conntrack_LDFLAGS = $(all_libraries) -rdynamic diff --git a/src/conntrack.c b/src/conntrack.c index 1d5227e..8132dcb 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -1,5 +1,5 @@ /* - * (C) 2005 by Pablo Neira Ayuso + * (C) 2005 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 @@ -42,19 +42,14 @@ #include #include #include +#include #include -#include #include "linux_list.h" #include "libct_proto.h" +#include #define PROGNAME "conntrack" -#define VERSION "0.82" - -#if 0 -#define DEBUGP printf -#else -#define DEBUGP -#endif +#define VERSION "0.86" #ifndef PROC_SYS_MODPROBE #define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe" @@ -197,6 +192,7 @@ static struct option original_opts[] = { #define OPTION_OFFSET 256 +struct nfct_handle *cth; static struct option *opts = original_opts; static unsigned int global_option_offset = 0; @@ -236,12 +232,53 @@ char *lib_dir = CONNTRACK_LIB_DIR; LIST_HEAD(proto_list); -char *proto2str[IPPROTO_MAX] = { - [IPPROTO_TCP] = "tcp", - [IPPROTO_UDP] = "udp", - [IPPROTO_ICMP] = "icmp", - [IPPROTO_SCTP] = "sctp" -}; +void register_proto(struct ctproto_handler *h) +{ + if (strcmp(h->version, LIBCT_VERSION) != 0) { + fprintf(stderr, "plugin `%s': version %s (I'm %s)\n", + h->name, h->version, LIBCT_VERSION); + exit(1); + } + list_add(&h->head, &proto_list); +} + +void unregister_proto(struct ctproto_handler *h) +{ + list_del(&h->head); +} + +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("CONNTRACK_LIB_DIR"); + if (!lib_dir) + lib_dir = CONNTRACK_LIB_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("libct_proto_.so") + + strlen(name) + strlen(lib_dir)]; + sprintf(path, "%s/libct_proto_%s.so", lib_dir, name); + if (dlopen(path, RTLD_NOW)) + handler = findproto(name); + else + fprintf(stderr, "%s\n", dlerror()); + } + + return handler; +} enum exittype { OTHER_PROBLEM = 1, @@ -383,7 +420,9 @@ err2str(int err, enum action command) { CT_GET, -EAFNOSUPPORT, "protocol not supported" }, { CT_CREATE, -ETIME, "conntrack has expired" }, { EXP_CREATE, -ENOENT, "master conntrack not found" }, - { EXP_CREATE, -EINVAL, "invalid parameters" } + { EXP_CREATE, -EINVAL, "invalid parameters" }, + { ~0UL, -EPERM, "sorry, you must be root or get " + "CAP_NET_ADMIN capability to do this"} }; for (i = 0; i < sizeof(table)/sizeof(struct table_struct); i++) { @@ -394,7 +433,7 @@ err2str(int err, enum action command) return strerror(err); } -static void dump_tuple(struct ctnl_tuple *tp) +static void 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, @@ -553,7 +592,7 @@ int iptables_insmod(const char *modname, const char *modprobe) /* Shamelessly stolen from libipt_DNAT ;). Ranges expected in network order. */ static void -nat_parse(char *arg, int portok, struct ctnl_nat *range) +nat_parse(char *arg, int portok, struct nfct_nat *range) { char *colon, *dash, *error; unsigned long ip; @@ -625,6 +664,13 @@ nat_parse(char *arg, int portok, struct ctnl_nat *range) range->max_ip = range->min_ip; } +static void event_sighandler(int s) +{ + fprintf(stdout, "Now closing conntrack event dumping...\n"); + nfct_close(cth); + exit(0); +} + void usage(char *prog) { fprintf(stdout, "Tool to manipulate conntrack and expectations. Version %s\n", VERSION); fprintf(stdout, "Usage: %s [commands] [options]\n", prog); @@ -659,11 +705,11 @@ int main(int argc, char *argv[]) { char c; unsigned int command = 0, options = 0; - struct ctnl_tuple orig, reply, mask, *o = NULL, *r = NULL; - struct ctnl_tuple exptuple; + struct nfct_tuple orig, reply, mask, *o = NULL, *r = NULL; + struct nfct_tuple exptuple; struct ctproto_handler *h = NULL; - union ctnl_protoinfo proto; - struct ctnl_nat range; + union nfct_protoinfo proto; + struct nfct_nat range; unsigned long timeout = 0; unsigned int status = IPS_CONFIRMED; unsigned long id = 0; @@ -671,13 +717,13 @@ int main(int argc, char *argv[]) int manip = -1; int res = 0, retry = 2; - memset(&proto, 0, sizeof(union ctnl_protoinfo)); - memset(&orig, 0, sizeof(struct ctnl_tuple)); - memset(&reply, 0, sizeof(struct ctnl_tuple)); - memset(&mask, 0, sizeof(struct ctnl_tuple)); - memset(&exptuple, 0, sizeof(struct ctnl_tuple)); - memset(&range, 0, sizeof(struct ctnl_nat)); - + memset(&proto, 0, sizeof(union nfct_protoinfo)); + memset(&orig, 0, sizeof(struct nfct_tuple)); + memset(&reply, 0, sizeof(struct nfct_tuple)); + memset(&mask, 0, sizeof(struct nfct_tuple)); + memset(&exptuple, 0, sizeof(struct nfct_tuple)); + memset(&range, 0, sizeof(struct nfct_nat)); + while ((c = getopt_long(argc, argv, "L::I::U::D::G::E::F::hVs:d:r:q:p:t:u:e:a:z[:]:{:}:", opts, NULL)) != -1) { @@ -846,14 +892,24 @@ int main(int argc, char *argv[]) retry--; switch(command) { case CT_LIST: + cth = nfct_open(CONNTRACK, 0); + if (!cth) + exit_error(OTHER_PROBLEM, "Not enough memory"); + nfct_set_callback(cth, nfct_default_conntrack_display); if (options & CT_OPT_ZERO) - res = dump_conntrack_table(1); + res = nfct_dump_conntrack_table_zero(cth); else - res = dump_conntrack_table(0); + res = nfct_dump_conntrack_table(cth); break; + nfct_close(cth); case EXP_LIST: - res = dump_expect_list(); + cth = nfct_open(EXPECT, 0); + if (!cth) + exit_error(OTHER_PROBLEM, "Not enough memory"); + nfct_set_callback(cth, nfct_default_expect_display); + res = nfct_dump_expect_list(cth); + nfct_close(cth); break; case CT_CREATE: @@ -866,25 +922,43 @@ int main(int argc, char *argv[]) orig.src.v4 = reply.dst.v4; orig.dst.v4 = reply.src.v4; } + cth = nfct_open(CONNTRACK, 0); + if (!cth) + exit_error(OTHER_PROBLEM, "Not enough memory"); if (options & CT_OPT_NATRANGE) - res = create_conntrack(&orig, &reply, timeout, - &proto, status, &range); + res = nfct_create_conntrack_nat(cth, + &orig, + &reply, + timeout, + &proto, + status, + &range); else - res = create_conntrack(&orig, &reply, timeout, - &proto, status, NULL); + res = nfct_create_conntrack(cth, &orig, + &reply, + timeout, + &proto, + status); + nfct_close(cth); break; case EXP_CREATE: + cth = nfct_open(EXPECT, 0); + if (!cth) + exit_error(OTHER_PROBLEM, "Not enough memory"); if (options & CT_OPT_ORIG) - res = create_expectation(&orig, - &exptuple, - &mask, - timeout); + res = nfct_create_expectation(cth, + &orig, + &exptuple, + &mask, + timeout); else if (options & CT_OPT_REPL) - res = create_expectation(&reply, - &exptuple, - &mask, - timeout); + res = nfct_create_expectation(cth, + &reply, + &exptuple, + &mask, + timeout); + nfct_close(cth); break; case CT_UPDATE: @@ -897,60 +971,117 @@ int main(int argc, char *argv[]) orig.src.v4 = reply.dst.v4; orig.dst.v4 = reply.src.v4; } - res = update_conntrack(&orig, &reply, timeout, - &proto, status); + cth = nfct_open(CONNTRACK, 0); + if (!cth) + exit_error(OTHER_PROBLEM, "Not enough memory"); + res = nfct_update_conntrack(cth, &orig, &reply, + timeout, &proto, + status); + nfct_close(cth); break; case CT_DELETE: + cth = nfct_open(CONNTRACK, 0); + if (!cth) + exit_error(OTHER_PROBLEM, "Not enough memory"); if (options & CT_OPT_ORIG) - res = delete_conntrack(&orig, CTA_TUPLE_ORIG, - CTNL_DIR_ORIGINAL); + res = nfct_delete_conntrack(cth,&orig, + NFCT_DIR_ORIGINAL); else if (options & CT_OPT_REPL) - res = delete_conntrack(&reply, CTA_TUPLE_REPLY, - CTNL_DIR_REPLY); + res = nfct_delete_conntrack(cth,&reply, + NFCT_DIR_REPLY); + nfct_close(cth); break; case EXP_DELETE: + cth = nfct_open(EXPECT, 0); + if (!cth) + exit_error(OTHER_PROBLEM, "Not enough memory"); if (options & CT_OPT_ORIG) - res = delete_expectation(&orig); + res = nfct_delete_expectation(cth,&orig); else if (options & CT_OPT_REPL) - res = delete_expectation(&reply); + res = nfct_delete_expectation(cth,&reply); + nfct_close(cth); break; case CT_GET: + cth = nfct_open(CONNTRACK, 0); + if (!cth) + exit_error(OTHER_PROBLEM, "Not enough memory"); if (options & CT_OPT_ORIG) - res = get_conntrack(&orig, id); + res = nfct_get_conntrack(cth,&orig, id); else if (options & CT_OPT_REPL) - res = get_conntrack(&reply, id); + res = nfct_get_conntrack(cth,&reply, id); + nfct_close(cth); break; case EXP_GET: + cth = nfct_open(EXPECT, 0); + if (!cth) + exit_error(OTHER_PROBLEM, "Not enough memory"); if (options & CT_OPT_ORIG) - res = get_expect(&orig, CTA_TUPLE_ORIG); + res = nfct_get_expectation(cth,&orig); else if (options & CT_OPT_REPL) - res = get_expect(&reply, CTA_TUPLE_REPLY); + res = nfct_get_expectation(cth,&reply); + nfct_close(cth); break; case CT_FLUSH: - res = flush_conntrack(); + cth = nfct_open(CONNTRACK, 0); + if (!cth) + exit_error(OTHER_PROBLEM, "Not enough memory"); + res = nfct_flush_conntrack_table(cth); + nfct_close(cth); break; case EXP_FLUSH: - res = flush_expectation(); + cth = nfct_open(EXPECT, 0); + if (!cth) + exit_error(OTHER_PROBLEM, "Not enough memory"); + res = nfct_flush_expectation_table(cth); + nfct_close(cth); break; case CT_EVENT: - if (options & CT_OPT_EVENT_MASK) - res = event_conntrack(event_mask); - else - res = event_conntrack(~0U); + if (options & CT_OPT_EVENT_MASK) { + cth = nfct_open(CONNTRACK, event_mask); + if (!cth) + exit_error(OTHER_PROBLEM, + "Not enough memory"); + signal(SIGINT, event_sighandler); + nfct_set_callback(cth, nfct_default_conntrack_display); + res = nfct_event_conntrack(cth); + } else { + cth = nfct_open(CONNTRACK, ~0U); + if (!cth) + exit_error(OTHER_PROBLEM, + "Not enough memory"); + signal(SIGINT, event_sighandler); + nfct_set_callback(cth, nfct_default_conntrack_display); + res = nfct_event_conntrack(cth); + } + nfct_close(cth); break; case EXP_EVENT: - if (options & CT_OPT_EVENT_MASK) - res = event_expectation(event_mask); - else - res = event_expectation(~0U); + if (options & CT_OPT_EVENT_MASK) { + cth = nfct_open(EXPECT, event_mask); + if (!cth) + exit_error(OTHER_PROBLEM, + "Not enough memory"); + signal(SIGINT, event_sighandler); + nfct_set_callback(cth, nfct_default_expect_display); + res = nfct_event_expectation(cth); + } else { + cth = nfct_open(EXPECT, ~0U); + if (!cth) + exit_error(OTHER_PROBLEM, + "Not enough memory"); + signal(SIGINT, event_sighandler); + nfct_set_callback(cth, nfct_default_expect_display); + res = nfct_event_expectation(cth); + } + nfct_close(cth); break; case CT_VERSION: diff --git a/src/libct.c b/src/libct.c deleted file mode 100644 index 36aacbd..0000000 --- a/src/libct.c +++ /dev/null @@ -1,660 +0,0 @@ -/* - * (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 -/* From kernel.h */ -#define INT_MAX ((int)(~0U>>1)) -#define INT_MIN (-INT_MAX - 1) -#include -#include "linux_list.h" -#include "libct_proto.h" - -#if 0 -#define DEBUGP printf -#else -#define DEBUGP -#endif - -static struct ctnl_handle cth; -extern char *lib_dir; -extern struct list_head proto_list; -extern char *proto2str[]; - -static void dump_tuple(struct ctnl_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 void print_status(unsigned int status) -{ - if (status & IPS_ASSURED) - fprintf(stdout, "[ASSURED] "); - if (!(status & IPS_SEEN_REPLY)) - fprintf(stdout, "[UNREPLIED] "); -} - -static void parse_ip(struct nfattr *attr, struct ctnl_tuple *tuple) -{ - struct nfattr *tb[CTA_IP_MAX]; - - memset(tb, 0, CTA_IP_MAX * sizeof(struct nfattr *)); - - 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 ctnl_tuple *tuple) -{ - struct nfattr *tb[CTA_PROTO_MAX]; - struct ctproto_handler *h; - int dir = CTNL_DIR_REPLY; - - memset(tb, 0, CTA_PROTO_MAX * sizeof(struct nfattr *)); - - 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 ctnl_tuple *tuple) -{ - struct nfattr *tb[CTA_TUPLE_MAX]; - - memset(tb, 0, CTA_TUPLE_MAX*sizeof(struct nfattr *)); - - 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 ctnl_conntrack *ct) -{ - struct nfattr *tb[CTA_PROTOINFO_MAX]; - struct ctproto_handler *h; - - memset(tb, 0, CTA_PROTOINFO_MAX*sizeof(struct nfattr *)); - - nfnl_parse_nested(tb,CTA_PROTOINFO_MAX, attr); - - h = findproto(proto2str[ct->tuple[CTNL_DIR_ORIGINAL].protonum]); - if (h && h->parse_protoinfo) - h->parse_protoinfo(tb, ct); -} - -/* Pablo: What is the equivalence of be64_to_cpu in userspace? - * - * Harald: Good question. I don't think there's a standard way [yet?], - * so I'd suggest manually implementing it by "#if little endian" bitshift - * operations in C (at least for now). - * - * All the payload of any nfattr will always be in network byte order. - * This would allow easy transport over a real network in the future - * (e.g. jamal's netlink2). - * - * Pablo: I've called it __be64_to_cpu instead of be64_to_cpu, since maybe - * there will one in the userspace headers someday. We don't want to - * pollute POSIX space naming, - */ - -#include -#if __BYTE_ORDER == __BIG_ENDIAN -# define __be64_to_cpu(x) (x) -# else -# if __BYTE_ORDER == __LITTLE_ENDIAN -# define __be64_to_cpu(x) __bswap_64(x) -# endif -#endif - -static void parse_counters(struct nfattr *attr, struct ctnl_conntrack *ct, - enum ctattr_type parent) -{ - struct nfattr *tb[CTA_COUNTERS_MAX]; - int dir = (parent == CTA_COUNTERS_ORIG ? CTNL_DIR_REPLY - : CTNL_DIR_ORIGINAL); - - memset(tb, 0, CTA_COUNTERS_MAX*sizeof(struct nfattr *)); - - 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])); -} - -/* Some people seem to like counting in decimal... */ -#define STATUS 1 -#define PROTOINFO 2 -#define TIMEOUT 4 -#define MARK 8 -#define COUNTERS 16 -#define USE 32 -#define ID 64 - -static int handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void *arg) -{ - struct nfgenmsg *nfmsg; - struct nfattr *nfa; - int min_len = sizeof(struct nfgenmsg);; - struct ctproto_handler *h = NULL; - struct nfattr *attr = NFM_NFA(NLMSG_DATA(nlh)); - int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); - struct ctnl_conntrack ct; - unsigned int flags = 0; - - memset(&ct, 0, sizeof(struct ctnl_conntrack)); - - nfmsg = NLMSG_DATA(nlh); - - if (nlh->nlmsg_len < min_len) - return -EINVAL; - - while (NFA_OK(attr, attrlen)) { - switch(attr->nfa_type) { - case CTA_TUPLE_ORIG: - parse_tuple(attr, &ct.tuple[CTNL_DIR_ORIGINAL]); - break; - case CTA_TUPLE_REPLY: - parse_tuple(attr, &ct.tuple[CTNL_DIR_REPLY]); - break; - case CTA_STATUS: - ct.status = ntohl(*(u_int32_t *)NFA_DATA(attr)); - flags |= STATUS; - break; - case CTA_PROTOINFO: - parse_protoinfo(attr, &ct); - flags |= PROTOINFO; - break; - case CTA_TIMEOUT: - ct.timeout = ntohl(*(u_int32_t *)NFA_DATA(attr)); - flags |= TIMEOUT; - break; - case CTA_MARK: - ct.mark = ntohl(*(u_int32_t *)NFA_DATA(attr)); - flags |= MARK; - break; - case CTA_COUNTERS_ORIG: - case CTA_COUNTERS_REPLY: - parse_counters(attr, &ct, attr->nfa_type-1); - flags |= COUNTERS; - break; - case CTA_USE: - ct.use = ntohl(*(u_int32_t *)NFA_DATA(attr)); - flags |= USE; - break; - case CTA_ID: - ct.id = ntohl(*(u_int32_t *)NFA_DATA(attr)); - flags |= ID; - break; - } - attr = NFA_NEXT(attr, attrlen); - } - - fprintf(stdout, "%-8s %u ", - proto2str[ct.tuple[CTNL_DIR_ORIGINAL].protonum] == NULL ? - "unknown" : proto2str[ct.tuple[CTNL_DIR_ORIGINAL].protonum], - ct.tuple[CTNL_DIR_ORIGINAL].protonum); - - if (flags & TIMEOUT) - fprintf(stdout, "%lu ", ct.timeout); - - h = findproto(proto2str[ct.tuple[CTNL_DIR_ORIGINAL].protonum]); - if ((flags & PROTOINFO) && h && h->print_protoinfo) - h->print_protoinfo(&ct.protoinfo); - - fprintf(stdout, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ", - NIPQUAD(ct.tuple[CTNL_DIR_ORIGINAL].src.v4), - NIPQUAD(ct.tuple[CTNL_DIR_ORIGINAL].dst.v4)); - - if (h && h->print_proto) - h->print_proto(&ct.tuple[CTNL_DIR_ORIGINAL]); - - if (flags & COUNTERS) - fprintf(stdout, "packets=%llu bytes=%llu ", - ct.counters[CTNL_DIR_ORIGINAL].packets, - ct.counters[CTNL_DIR_ORIGINAL].bytes); - - fprintf(stdout, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ", - NIPQUAD(ct.tuple[CTNL_DIR_REPLY].src.v4), - NIPQUAD(ct.tuple[CTNL_DIR_REPLY].dst.v4)); - - h = findproto(proto2str[ct.tuple[CTNL_DIR_ORIGINAL].protonum]); - if (h && h->print_proto) - h->print_proto(&ct.tuple[CTNL_DIR_REPLY]); - - if (flags & COUNTERS) - fprintf(stdout, "packets=%llu bytes=%llu ", - ct.counters[CTNL_DIR_REPLY].packets, - ct.counters[CTNL_DIR_REPLY].bytes); - - if (flags & STATUS) - print_status(ct.status); - - if (flags & MARK) - fprintf(stdout, "mark=%lu ", ct.mark); - if (flags & USE) - fprintf(stdout, "use=%u ", ct.use); - if (flags & ID) - fprintf(stdout, "id=%u ", ct.id); - - fprintf(stdout, "\n"); - - return 0; -} - -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 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 handler(sock, nlh, arg); -} - -static int expect_handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void *arg) -{ - struct nfgenmsg *nfmsg; - struct nfattr *nfa; - int min_len = sizeof(struct nfgenmsg);; - struct ctproto_handler *h = NULL; - struct nfattr *attr = NFM_NFA(NLMSG_DATA(nlh)); - int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); - struct ctnl_tuple tuple, mask; - unsigned long timeout = 0; - u_int32_t id = 0; - unsigned int flags; - - memset(&tuple, 0, sizeof(struct ctnl_tuple)); - memset(&mask, 0, sizeof(struct ctnl_tuple)); - - nfmsg = NLMSG_DATA(nlh); - - if (nlh->nlmsg_len < min_len) - return -EINVAL; - - while (NFA_OK(attr, attrlen)) { - switch(attr->nfa_type) { - - case CTA_EXPECT_TUPLE: - parse_tuple(attr, &tuple); - break; - case CTA_EXPECT_MASK: - parse_tuple(attr, &mask); - break; - case CTA_EXPECT_TIMEOUT: - timeout = htonl(*(unsigned long *) - NFA_DATA(attr)); - break; - case CTA_EXPECT_ID: - id = htonl(*(u_int32_t *)NFA_DATA(attr)); - break; - } - attr = NFA_NEXT(attr, attrlen); - } - fprintf(stdout, "%ld proto=%d ", timeout, tuple.protonum); - - fprintf(stdout, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ", - NIPQUAD(tuple.src.v4), - NIPQUAD(tuple.dst.v4)); - - fprintf(stdout, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ", - NIPQUAD(mask.src.v4), - NIPQUAD(mask.dst.v4)); - - fprintf(stdout, "id=%u ", id); - - fputc('\n', stdout); - - return 0; -} - -int create_conntrack(struct ctnl_tuple *orig, - struct ctnl_tuple *reply, - unsigned long timeout, - union ctnl_protoinfo *proto, - unsigned int status, - struct ctnl_nat *range) -{ - struct ctnl_conntrack ct; - int ret; - - memset(&ct, 0, sizeof(struct ctnl_conntrack)); - ct.tuple[CTNL_DIR_ORIGINAL] = *orig; - ct.tuple[CTNL_DIR_REPLY] = *reply; - ct.timeout = htonl(timeout); - ct.status = status; - ct.protoinfo = *proto; - if (range) - ct.nat = *range; - - if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK, 0)) < 0) - return ret; - - ret = ctnl_new_conntrack(&cth, &ct); - - ctnl_close(&cth); - - return ret; -} - -int update_conntrack(struct ctnl_tuple *orig, - struct ctnl_tuple *reply, - unsigned long timeout, - union ctnl_protoinfo *proto, - unsigned int status) -{ - struct ctnl_conntrack ct; - int ret; - - memset(&ct, 0, sizeof(struct ctnl_conntrack)); - ct.tuple[CTNL_DIR_ORIGINAL] = *orig; - ct.tuple[CTNL_DIR_REPLY] = *reply; - ct.timeout = htonl(timeout); - ct.status = status; - ct.protoinfo = *proto; - - if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK, 0)) < 0) - return ret; - - ret = ctnl_upd_conntrack(&cth, &ct); - - ctnl_close(&cth); - - return ret; -} - -int delete_conntrack(struct ctnl_tuple *tuple, int dir) -{ - int ret; - - if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK, 0)) < 0) - return ret; - - ret = ctnl_del_conntrack(&cth, tuple, dir); - ctnl_close(&cth); - - return ret; -} - -/* get_conntrack_handler */ -int get_conntrack(struct ctnl_tuple *tuple, int dir) -{ - struct ctnl_msg_handler h = { - .type = 0, - .handler = handler - }; - int ret; - - if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK, 0)) < 0) - return ret; - - ctnl_register_handler(&cth, &h); - - ret = ctnl_get_conntrack(&cth, tuple, dir); - ctnl_close(&cth); - - return ret; -} - -int dump_conntrack_table(int zero) -{ - int ret; - struct ctnl_msg_handler h = { - .type = IPCTNL_MSG_CT_NEW, /* Hm... really? */ - .handler = handler - }; - - if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK, 0)) < 0) - return ret; - - ctnl_register_handler(&cth, &h); - - if (zero) { - ret = ctnl_list_conntrack_zero_counters(&cth, AF_INET); - } else - ret = ctnl_list_conntrack(&cth, AF_INET); - - ctnl_close(&cth); - - return ret; -} - -static void event_sighandler(int s) -{ - fprintf(stdout, "Now closing conntrack event dumping...\n"); - ctnl_close(&cth); - exit(0); -} - -int event_conntrack(unsigned int event_mask) -{ - struct ctnl_msg_handler hnew = { - .type = IPCTNL_MSG_CT_NEW, - .handler = event_handler - }; - struct ctnl_msg_handler hdestroy = { - .type = IPCTNL_MSG_CT_DELETE, - .handler = event_handler - }; - int ret; - - if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK, event_mask)) < 0) - return ret; - - signal(SIGINT, event_sighandler); - ctnl_register_handler(&cth, &hnew); - ctnl_register_handler(&cth, &hdestroy); - ret = ctnl_event_conntrack(&cth, AF_INET); - ctnl_close(&cth); - - return 0; -} - -struct ctproto_handler *findproto(char *name) -{ - void *h = NULL; - struct list_head *i; - struct ctproto_handler *cur = NULL, *handler = NULL; - - if (!name) - return handler; - - lib_dir = getenv("CONNTRACK_LIB_DIR"); - if (!lib_dir) - lib_dir = CONNTRACK_LIB_DIR; - - list_for_each(i, &proto_list) { - cur = (struct ctproto_handler *) i; - if (strcmp(cur->name, name) == 0) { - handler = cur; - break; - } - } - - if (!handler) { - char path[sizeof("libct_proto_.so") - + strlen(name) + strlen(lib_dir)]; - sprintf(path, "%s/libct_proto_%s.so", lib_dir, name); - if (dlopen(path, RTLD_NOW)) - handler = findproto(name); - else - DEBUGP(stderr, "%s\n", dlerror()); - } - - return handler; -} - -void register_proto(struct ctproto_handler *h) -{ - if (strcmp(h->version, LIBCT_VERSION) != 0) { - fprintf(stderr, "plugin `%s': version %s (I'm %s)\n", - h->name, h->version, LIBCT_VERSION); - exit(1); - } - list_add(&h->head, &proto_list); -} - -void unregister_proto(struct ctproto_handler *h) -{ - list_del(&h->head); -} - -int dump_expect_list() -{ - struct ctnl_msg_handler h = { - .type = IPCTNL_MSG_EXP_NEW, - .handler = expect_handler - }; - int ret; - - if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK_EXP, 0)) < 0) - return ret; - - ctnl_register_handler(&cth, &h); - - ret = ctnl_list_expect(&cth, AF_INET); - ctnl_close(&cth); - - return ret; -} - -int flush_conntrack() -{ - int ret; - - if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK, 0)) < 0) - return ret; - - ret = ctnl_flush_conntrack(&cth); - ctnl_close(&cth); - - return ret; -} - -int get_expect(struct ctnl_tuple *tuple) -{ - struct ctnl_msg_handler h = { - .type = IPCTNL_MSG_EXP_NEW, - .handler = expect_handler - }; - int ret; - - if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK_EXP, 0)) < 0) - return 0; - - ctnl_register_handler(&cth, &h); - - ret = ctnl_get_expect(&cth, tuple); - ctnl_close(&cth); - - return ret; -} - -int create_expectation(struct ctnl_tuple *tuple, - struct ctnl_tuple *exptuple, - struct ctnl_tuple *mask, - unsigned long timeout) -{ - int ret; - - if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK_EXP, 0)) < 0) - return ret; - - - ret = ctnl_new_expect(&cth, tuple, exptuple, mask, timeout); - ctnl_close(&cth); - - return ret; -} - -int delete_expectation(struct ctnl_tuple *tuple) -{ - int ret; - - if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK_EXP, 0)) < 0) - return ret; - - ret = ctnl_del_expect(&cth, tuple); - ctnl_close(&cth); - - return ret; -} - -int event_expectation(unsigned int event_mask) -{ - struct ctnl_msg_handler hnew = { - .type = IPCTNL_MSG_EXP_NEW, - .handler = expect_handler - }; - struct ctnl_msg_handler hdestroy = { - .type = IPCTNL_MSG_EXP_DELETE, - .handler = expect_handler - }; - int ret; - - if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK_EXP, event_mask)) < 0) - return ret; - - ctnl_register_handler(&cth, &hnew); - ctnl_register_handler(&cth, &hdestroy); - ret = ctnl_event_expect(&cth, AF_INET); - ctnl_close(&cth); - - return ret; -} - -int flush_expectation() -{ - int ret; - - if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK_EXP, 0)) < 0) - return ret; - - ret = ctnl_flush_expect(&cth); - ctnl_close(&cth); - - return ret; -} - -- cgit v1.2.3 From bc7c1f1a4a6a5e003f66df2bab082fa521e9bb5e 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 21:46:30 +0000 Subject: See ChangeLog --- ChangeLog | 6 ++++ config.h.in | 65 ------------------------------------------- extensions/libct_proto_icmp.c | 2 +- extensions/libct_proto_sctp.c | 31 +-------------------- extensions/libct_proto_tcp.c | 2 +- extensions/libct_proto_udp.c | 2 +- include/conntrack.h | 53 +++++++++++++++++++++++++++++++++++ include/libct_proto.h | 53 ----------------------------------- src/conntrack.c | 2 +- 9 files changed, 64 insertions(+), 152 deletions(-) delete mode 100644 config.h.in create mode 100644 include/conntrack.h delete mode 100644 include/libct_proto.h (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 2942f78..6622c89 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2005-10-16 + + o Rename libct_proto.h to conntrack.h + o Remove config.h.in from svn, it's autogenerated by the autocrap :) + o Remove dead functions in the SCTP protocol helper + 2005-10-14 o Kill config.h.in, it's generated by the autocrap diff --git a/config.h.in b/config.h.in deleted file mode 100644 index 9045dbb..0000000 --- a/config.h.in +++ /dev/null @@ -1,65 +0,0 @@ -/* config.h.in. Generated from configure.in by autoheader. */ - -/* Define to 1 if you have the header file. */ -#undef HAVE_DLFCN_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_INTTYPES_H - -/* Define to 1 if you have the `dl' library (-ldl). */ -#undef HAVE_LIBDL - -/* Define to 1 if you have the `nfnetlink' library (-lnfnetlink). */ -#undef HAVE_LIBNFNETLINK - -/* Define to 1 if you have the `nfnetlink_conntrack' library - (-lnfnetlink_conntrack). */ -#undef HAVE_LIBNFNETLINK_CONNTRACK - -/* Define to 1 if you have the header file. */ -#undef HAVE_MEMORY_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDINT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDLIB_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STRINGS_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STRING_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_STAT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_TYPES_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_UNISTD_H - -/* Name of package */ -#undef PACKAGE - -/* Define to the address where bug reports for this package should be sent. */ -#undef PACKAGE_BUGREPORT - -/* Define to the full name of this package. */ -#undef PACKAGE_NAME - -/* Define to the full name and version of this package. */ -#undef PACKAGE_STRING - -/* Define to the one symbol short name of this package. */ -#undef PACKAGE_TARNAME - -/* Define to the version of this package. */ -#undef PACKAGE_VERSION - -/* Define to 1 if you have the ANSI C header files. */ -#undef STDC_HEADERS - -/* Version number of package */ -#undef VERSION diff --git a/extensions/libct_proto_icmp.c b/extensions/libct_proto_icmp.c index 7142fa7..d7d9d5a 100644 --- a/extensions/libct_proto_icmp.c +++ b/extensions/libct_proto_icmp.c @@ -14,7 +14,7 @@ #include /* For htons */ #include #include -#include "libct_proto.h" +#include "conntrack.h" static struct option opts[] = { {"icmp-type", 1, 0, '1'}, diff --git a/extensions/libct_proto_sctp.c b/extensions/libct_proto_sctp.c index bc91966..5e96dc1 100644 --- a/extensions/libct_proto_sctp.c +++ b/extensions/libct_proto_sctp.c @@ -12,7 +12,7 @@ #include #include #include /* For htons */ -#include "libct_proto.h" +#include "conntrack.h" #include static struct option opts[] = { @@ -136,35 +136,6 @@ int final_check(unsigned int flags, return 0; } -void parse_proto(struct nfattr *cda[], struct nfct_tuple *tuple) -{ - if (cda[CTA_PROTO_SRC_PORT-1]) - tuple->l4src.sctp.port = - *(u_int16_t *)NFA_DATA(cda[CTA_PROTO_SRC_PORT-1]); - if (cda[CTA_PROTO_DST_PORT-1]) - tuple->l4dst.sctp.port = - *(u_int16_t *)NFA_DATA(cda[CTA_PROTO_DST_PORT-1]); -} - -void parse_protoinfo(struct nfattr *cda[], struct nfct_conntrack *ct) -{ -/* if (cda[CTA_PROTOINFO_SCTP_STATE-1]) - ct->protoinfo.sctp.state = - *(u_int8_t *)NFA_DATA(cda[CTA_PROTOINFO_SCTP_STATE-1]); -*/ -} - -void print_protoinfo(union nfct_protoinfo *protoinfo) -{ -/* fprintf(stdout, "%s ", states[protoinfo->sctp.state]); */ -} - -void print_proto(struct nfct_tuple *tuple) -{ - fprintf(stdout, "sport=%u dport=%u ", htons(tuple->l4src.sctp.port), - htons(tuple->l4dst.sctp.port)); -} - static struct ctproto_handler sctp = { .name = "sctp", .protonum = IPPROTO_SCTP, diff --git a/extensions/libct_proto_tcp.c b/extensions/libct_proto_tcp.c index 3b06aa2..97646ab 100644 --- a/extensions/libct_proto_tcp.c +++ b/extensions/libct_proto_tcp.c @@ -14,7 +14,7 @@ #include /* For htons */ #include -#include "libct_proto.h" +#include "conntrack.h" static struct option opts[] = { {"orig-port-src", 1, 0, '1'}, diff --git a/extensions/libct_proto_udp.c b/extensions/libct_proto_udp.c index 8e77f0c..0da7bb5 100644 --- a/extensions/libct_proto_udp.c +++ b/extensions/libct_proto_udp.c @@ -11,7 +11,7 @@ #include #include #include /* For htons */ -#include "libct_proto.h" +#include "conntrack.h" #include static struct option opts[] = { diff --git a/include/conntrack.h b/include/conntrack.h new file mode 100644 index 0000000..db434d6 --- /dev/null +++ b/include/conntrack.h @@ -0,0 +1,53 @@ +#ifndef _LIBCT_PROTO_H +#define _LIBCT_PROTO_H + +#include "linux_list.h" +#include +#include + +#define LIBCT_VERSION "0.1.0" + +/* FIXME: These should be independent from kernel space */ +#define IPS_ASSURED (1 << 2) +#define IPS_SEEN_REPLY (1 << 1) +#define IPS_SRC_NAT_DONE (1 << 7) +#define IPS_DST_NAT_DONE (1 << 8) +#define IPS_CONFIRMED (1 << 3) + +struct ctproto_handler { + struct list_head head; + + char *name; + u_int16_t protonum; + char *version; + + enum ctattr_protoinfo protoinfo_attr; + + int (*parse_opts)(char c, char *argv[], + struct nfct_tuple *orig, + struct nfct_tuple *reply, + struct nfct_tuple *mask, + union nfct_protoinfo *proto, + unsigned int *flags); + + int (*final_check)(unsigned int flags, + struct nfct_tuple *orig, + struct nfct_tuple *reply); + + void (*help)(); + + struct option *opts; + + unsigned int option_offset; +}; + +extern void register_proto(struct ctproto_handler *h); +extern void unregister_proto(struct ctproto_handler *h); + +#define NIPQUAD(addr) \ + ((unsigned char *)&addr)[0], \ + ((unsigned char *)&addr)[1], \ + ((unsigned char *)&addr)[2], \ + ((unsigned char *)&addr)[3] + +#endif diff --git a/include/libct_proto.h b/include/libct_proto.h deleted file mode 100644 index db434d6..0000000 --- a/include/libct_proto.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef _LIBCT_PROTO_H -#define _LIBCT_PROTO_H - -#include "linux_list.h" -#include -#include - -#define LIBCT_VERSION "0.1.0" - -/* FIXME: These should be independent from kernel space */ -#define IPS_ASSURED (1 << 2) -#define IPS_SEEN_REPLY (1 << 1) -#define IPS_SRC_NAT_DONE (1 << 7) -#define IPS_DST_NAT_DONE (1 << 8) -#define IPS_CONFIRMED (1 << 3) - -struct ctproto_handler { - struct list_head head; - - char *name; - u_int16_t protonum; - char *version; - - enum ctattr_protoinfo protoinfo_attr; - - int (*parse_opts)(char c, char *argv[], - struct nfct_tuple *orig, - struct nfct_tuple *reply, - struct nfct_tuple *mask, - union nfct_protoinfo *proto, - unsigned int *flags); - - int (*final_check)(unsigned int flags, - struct nfct_tuple *orig, - struct nfct_tuple *reply); - - void (*help)(); - - struct option *opts; - - unsigned int option_offset; -}; - -extern void register_proto(struct ctproto_handler *h); -extern void unregister_proto(struct ctproto_handler *h); - -#define NIPQUAD(addr) \ - ((unsigned char *)&addr)[0], \ - ((unsigned char *)&addr)[1], \ - ((unsigned char *)&addr)[2], \ - ((unsigned char *)&addr)[3] - -#endif diff --git a/src/conntrack.c b/src/conntrack.c index 8132dcb..6946d66 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -45,7 +45,7 @@ #include #include #include "linux_list.h" -#include "libct_proto.h" +#include "conntrack.h" #include #define PROGNAME "conntrack" -- cgit v1.2.3 From b5eb87aa99bbf444082b17870088ea20e7e9dd09 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: Fri, 21 Oct 2005 02:46:24 +0000 Subject: See ChangeLog --- ChangeLog | 1 + src/conntrack.c | 96 +++++++++++++++++++++++++++++++++------------------------ 2 files changed, 56 insertions(+), 41 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index d9d7d12..5bb098b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,7 @@ 2005-10-20 o Kill some more files that generated by the autocrap + o Resync with the lastest libnetfilter_conntrack API changes 2005-10-16 diff --git a/src/conntrack.c b/src/conntrack.c index 6946d66..3d67ab4 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -710,6 +710,8 @@ int main(int argc, char *argv[]) struct ctproto_handler *h = NULL; union nfct_protoinfo proto; struct nfct_nat range; + struct nfct_conntrack *ct; + struct nfct_expect *exp; unsigned long timeout = 0; unsigned int status = IPS_CONFIRMED; unsigned long id = 0; @@ -897,7 +899,7 @@ int main(int argc, char *argv[]) exit_error(OTHER_PROBLEM, "Not enough memory"); nfct_set_callback(cth, nfct_default_conntrack_display); if (options & CT_OPT_ZERO) - res = nfct_dump_conntrack_table_zero(cth); + res = nfct_dump_conntrack_table_reset_counters(cth); else res = nfct_dump_conntrack_table(cth); break; @@ -922,42 +924,44 @@ int main(int argc, char *argv[]) orig.src.v4 = reply.dst.v4; orig.dst.v4 = reply.src.v4; } - cth = nfct_open(CONNTRACK, 0); - if (!cth) - exit_error(OTHER_PROBLEM, "Not enough memory"); if (options & CT_OPT_NATRANGE) - res = nfct_create_conntrack_nat(cth, - &orig, - &reply, - timeout, - &proto, - status, - &range); + ct = nfct_conntrack_alloc(&orig, &reply, + timeout, &proto, + status, &range); else - res = nfct_create_conntrack(cth, &orig, - &reply, - timeout, - &proto, - status); + ct = nfct_conntrack_alloc(&orig, &reply, + timeout, &proto, + status, NULL); + if (!ct) + exit_error(OTHER_PROBLEM, "Not Enough memory"); + + cth = nfct_open(CONNTRACK, 0); + if (!cth) { + nfct_conntrack_free(ct); + exit_error(OTHER_PROBLEM, "Not enough memory"); + } + res = nfct_create_conntrack(cth, ct); nfct_close(cth); + nfct_conntrack_free(ct); break; case EXP_CREATE: - cth = nfct_open(EXPECT, 0); - if (!cth) - exit_error(OTHER_PROBLEM, "Not enough memory"); if (options & CT_OPT_ORIG) - res = nfct_create_expectation(cth, - &orig, - &exptuple, - &mask, - timeout); + exp = nfct_expect_alloc(&orig, &exptuple, + &mask, timeout); else if (options & CT_OPT_REPL) - res = nfct_create_expectation(cth, - &reply, - &exptuple, - &mask, - timeout); + exp = nfct_expect_alloc(&reply, &exptuple, + &mask, timeout); + if (!exp) + exit_error(OTHER_PROBLEM, "Not enough memory"); + + cth = nfct_open(EXPECT, 0); + if (!cth) { + nfct_expect_free(exp); + exit_error(OTHER_PROBLEM, "Not enough memory"); + } + res = nfct_create_expectation(cth, exp); + nfct_expect_free(exp); nfct_close(cth); break; @@ -971,12 +975,18 @@ int main(int argc, char *argv[]) orig.src.v4 = reply.dst.v4; orig.dst.v4 = reply.src.v4; } + ct = nfct_conntrack_alloc(&orig, &reply, timeout, + &proto, status, NULL); + if (!ct) + exit_error(OTHER_PROBLEM, "Not enough memory"); + cth = nfct_open(CONNTRACK, 0); - if (!cth) + if (!cth) { + nfct_conntrack_free(ct); exit_error(OTHER_PROBLEM, "Not enough memory"); - res = nfct_update_conntrack(cth, &orig, &reply, - timeout, &proto, - status); + } + res = nfct_update_conntrack(cth, ct); + nfct_conntrack_free(ct); nfct_close(cth); break; @@ -985,10 +995,10 @@ int main(int argc, char *argv[]) if (!cth) exit_error(OTHER_PROBLEM, "Not enough memory"); if (options & CT_OPT_ORIG) - res = nfct_delete_conntrack(cth,&orig, + res = nfct_delete_conntrack(cth, &orig, NFCT_DIR_ORIGINAL); else if (options & CT_OPT_REPL) - res = nfct_delete_conntrack(cth,&reply, + res = nfct_delete_conntrack(cth, &reply, NFCT_DIR_REPLY); nfct_close(cth); break; @@ -998,9 +1008,9 @@ int main(int argc, char *argv[]) if (!cth) exit_error(OTHER_PROBLEM, "Not enough memory"); if (options & CT_OPT_ORIG) - res = nfct_delete_expectation(cth,&orig); + res = nfct_delete_expectation(cth, &orig); else if (options & CT_OPT_REPL) - res = nfct_delete_expectation(cth,&reply); + res = nfct_delete_expectation(cth, &reply); nfct_close(cth); break; @@ -1008,10 +1018,13 @@ int main(int argc, char *argv[]) cth = nfct_open(CONNTRACK, 0); if (!cth) exit_error(OTHER_PROBLEM, "Not enough memory"); + nfct_set_callback(cth, nfct_default_conntrack_display); if (options & CT_OPT_ORIG) - res = nfct_get_conntrack(cth,&orig, id); + res = nfct_get_conntrack(cth, &orig, + NFCT_DIR_ORIGINAL); else if (options & CT_OPT_REPL) - res = nfct_get_conntrack(cth,&reply, id); + res = nfct_get_conntrack(cth, &reply, + NFCT_DIR_REPLY); nfct_close(cth); break; @@ -1019,10 +1032,11 @@ int main(int argc, char *argv[]) cth = nfct_open(EXPECT, 0); if (!cth) exit_error(OTHER_PROBLEM, "Not enough memory"); + nfct_set_callback(cth, nfct_default_expect_display); if (options & CT_OPT_ORIG) - res = nfct_get_expectation(cth,&orig); + res = nfct_get_expectation(cth, &orig); else if (options & CT_OPT_REPL) - res = nfct_get_expectation(cth,&reply); + res = nfct_get_expectation(cth, &reply); nfct_close(cth); break; -- cgit v1.2.3 From 05c632cf7ff2f7214d51b70e263355de2e9cb5f9 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: Fri, 21 Oct 2005 18:22:28 +0000 Subject: See ChangeLog --- ChangeLog | 5 ++++ src/conntrack.c | 90 +++++++++++++++++++++++++++++++++++---------------------- 2 files changed, 61 insertions(+), 34 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 5bb098b..b079871 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2005-10-21 + + o Bumped version to 0.90 + o Add support for id and marks + 2005-10-20 o Kill some more files that generated by the autocrap diff --git a/src/conntrack.c b/src/conntrack.c index 3d67ab4..6ce945f 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -49,7 +49,7 @@ #include #define PROGNAME "conntrack" -#define VERSION "0.86" +#define VERSION "0.90" #ifndef PROC_SYS_MODPROBE #define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe" @@ -157,11 +157,19 @@ enum options { CT_OPT_NATRANGE_BIT = 13, CT_OPT_NATRANGE = (1 << CT_OPT_NATRANGE_BIT), + + CT_OPT_MARK_BIT = 14, + CT_OPT_MARK = (1 << CT_OPT_MARK_BIT), + + CT_OPT_ID_BIT = 15, + CT_OPT_ID = (1 << CT_OPT_ID_BIT), + + CT_OPT_MAX = CT_OPT_ID }; -#define NUMBER_OF_OPT 14 +#define NUMBER_OF_OPT CT_OPT_MAX static const char optflags[NUMBER_OF_OPT] -= {'s','d','r','q','p','t','u','z','e','[',']','{','}','a'}; += {'s','d','r','q','p','t','u','z','e','[',']','{','}','a','i','m'}; static struct option original_opts[] = { {"dump", 2, 0, 'L'}, @@ -187,6 +195,8 @@ static struct option original_opts[] = { {"mask-src", 1, 0, '{'}, {"mask-dst", 1, 0, '}'}, {"nat-range", 1, 0, 'a'}, + {"mark", 1, 0, 'm'}, + {"id", 1, 0, 'i'}, {0, 0, 0, 0} }; @@ -210,22 +220,22 @@ static unsigned int global_option_offset = 0; static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = /* Well, it's better than "Re: Linux vs FreeBSD" */ { - /* -s -d -r -q -p -t -u -z -e -x -y -k -l -a */ -/*CT_LIST*/ {'x','x','x','x','x','x','x',' ','x','x','x','x','x','x'}, -/*CT_CREATE*/ {' ',' ',' ',' ','+','+','+','x','x','x','x','x','x',' '}, -/*CT_UPDATE*/ {' ',' ',' ',' ','+','+','+','x','x','x','x','x','x','x'}, -/*CT_DELETE*/ {' ',' ',' ',' ',' ','x','x','x','x','x','x','x','x','x'}, -/*CT_GET*/ {' ',' ',' ',' ','+','x','x','x','x','x','x','x','x','x'}, -/*CT_FLUSH*/ {'x','x','x','x','x','x','x','x','x','x','x','x','x','x'}, -/*CT_EVENT*/ {'x','x','x','x','x','x','x','x',' ','x','x','x','x','x'}, -/*VERSION*/ {'x','x','x','x','x','x','x','x','x','x','x','x','x','x'}, -/*HELP*/ {'x','x','x','x',' ','x','x','x','x','x','x','x','x','x'}, -/*EXP_LIST*/ {'x','x','x','x','x','x','x','x','x','x','x','x','x','x'}, -/*EXP_CREATE*/{'+','+',' ',' ','+','+',' ','x','x','+','+','+','+','x'}, -/*EXP_DELETE*/{'+','+',' ',' ','+','x','x','x','x','x','x','x','x','x'}, -/*EXP_GET*/ {'+','+',' ',' ','+','x','x','x','x','x','x','x','x','x'}, -/*EXP_FLUSH*/ {'x','x','x','x','x','x','x','x','x','x','x','x','x','x'}, -/*EXP_EVENT*/ {'x','x','x','x','x','x','x','x','x','x','x','x','x','x'}, + /* -s -d -r -q -p -t -u -z -e -x -y -k -l -a -m -i*/ +/*CT_LIST*/ {'x','x','x','x','x','x','x',' ','x','x','x','x','x','x','x','x'}, +/*CT_CREATE*/ {' ',' ',' ',' ','+','+','+','x','x','x','x','x','x',' ',' ','x'}, +/*CT_UPDATE*/ {' ',' ',' ',' ','+','+','+','x','x','x','x','x','x','x',' ',' '}, +/*CT_DELETE*/ {' ',' ',' ',' ',' ','x','x','x','x','x','x','x','x','x','x',' '}, +/*CT_GET*/ {' ',' ',' ',' ','+','x','x','x','x','x','x','x','x','x','x',' '}, +/*CT_FLUSH*/ {'x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x'}, +/*CT_EVENT*/ {'x','x','x','x','x','x','x','x',' ','x','x','x','x','x','x','x'}, +/*VERSION*/ {'x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x'}, +/*HELP*/ {'x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x'}, +/*EXP_LIST*/ {'x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x'}, +/*EXP_CREATE*/{'+','+',' ',' ','+','+',' ','x','x','+','+','+','+','x','x','x'}, +/*EXP_DELETE*/{'+','+',' ',' ','+','x','x','x','x','x','x','x','x','x','x','x'}, +/*EXP_GET*/ {'+','+',' ',' ','+','x','x','x','x','x','x','x','x','x','x','x'}, +/*EXP_FLUSH*/ {'x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x'}, +/*EXP_EVENT*/ {'x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x'}, }; char *lib_dir = CONNTRACK_LIB_DIR; @@ -714,7 +724,8 @@ int main(int argc, char *argv[]) struct nfct_expect *exp; unsigned long timeout = 0; unsigned int status = IPS_CONFIRMED; - unsigned long id = 0; + unsigned int mark = 0; + unsigned int id = NFCT_ANY_ID; unsigned int type = 0, extra_flags = 0, event_mask = 0; int manip = -1; int res = 0, retry = 2; @@ -727,7 +738,7 @@ int main(int argc, char *argv[]) memset(&range, 0, sizeof(struct nfct_nat)); while ((c = getopt_long(argc, argv, - "L::I::U::D::G::E::F::hVs:d:r:q:p:t:u:e:a:z[:]:{:}:", + "L::I::U::D::G::E::F::hVs:d:r:q:p:t:u:e:a:z[:]:{:}:m:i:", opts, NULL)) != -1) { switch(c) { case 'L': @@ -862,6 +873,12 @@ int main(int argc, char *argv[]) options |= CT_OPT_NATRANGE; nat_parse(optarg, 1, &range); break; + case 'm': + mark = atol(optarg); + break; + case 'i': + id = atol(optarg); + break; default: if (h && h->parse_opts &&!h->parse_opts(c - h->option_offset, argv, &orig, @@ -927,11 +944,13 @@ int main(int argc, char *argv[]) if (options & CT_OPT_NATRANGE) ct = nfct_conntrack_alloc(&orig, &reply, timeout, &proto, - status, &range); + status, mark, id, + &range); else ct = nfct_conntrack_alloc(&orig, &reply, timeout, &proto, - status, NULL); + status, mark, id, + NULL); if (!ct) exit_error(OTHER_PROBLEM, "Not Enough memory"); @@ -948,10 +967,10 @@ int main(int argc, char *argv[]) case EXP_CREATE: if (options & CT_OPT_ORIG) exp = nfct_expect_alloc(&orig, &exptuple, - &mask, timeout); + &mask, timeout, id); else if (options & CT_OPT_REPL) exp = nfct_expect_alloc(&reply, &exptuple, - &mask, timeout); + &mask, timeout, id); if (!exp) exit_error(OTHER_PROBLEM, "Not enough memory"); @@ -976,7 +995,8 @@ int main(int argc, char *argv[]) orig.dst.v4 = reply.src.v4; } ct = nfct_conntrack_alloc(&orig, &reply, timeout, - &proto, status, NULL); + &proto, status, mark, id, + NULL); if (!ct) exit_error(OTHER_PROBLEM, "Not enough memory"); @@ -996,10 +1016,12 @@ int main(int argc, char *argv[]) exit_error(OTHER_PROBLEM, "Not enough memory"); if (options & CT_OPT_ORIG) res = nfct_delete_conntrack(cth, &orig, - NFCT_DIR_ORIGINAL); + NFCT_DIR_ORIGINAL, + id); else if (options & CT_OPT_REPL) res = nfct_delete_conntrack(cth, &reply, - NFCT_DIR_REPLY); + NFCT_DIR_REPLY, + id); nfct_close(cth); break; @@ -1008,9 +1030,9 @@ int main(int argc, char *argv[]) if (!cth) exit_error(OTHER_PROBLEM, "Not enough memory"); if (options & CT_OPT_ORIG) - res = nfct_delete_expectation(cth, &orig); + res = nfct_delete_expectation(cth, &orig, id); else if (options & CT_OPT_REPL) - res = nfct_delete_expectation(cth, &reply); + res = nfct_delete_expectation(cth, &reply, id); nfct_close(cth); break; @@ -1021,10 +1043,10 @@ int main(int argc, char *argv[]) nfct_set_callback(cth, nfct_default_conntrack_display); if (options & CT_OPT_ORIG) res = nfct_get_conntrack(cth, &orig, - NFCT_DIR_ORIGINAL); + NFCT_DIR_ORIGINAL, id); else if (options & CT_OPT_REPL) res = nfct_get_conntrack(cth, &reply, - NFCT_DIR_REPLY); + NFCT_DIR_REPLY, id); nfct_close(cth); break; @@ -1034,9 +1056,9 @@ int main(int argc, char *argv[]) exit_error(OTHER_PROBLEM, "Not enough memory"); nfct_set_callback(cth, nfct_default_expect_display); if (options & CT_OPT_ORIG) - res = nfct_get_expectation(cth, &orig); + res = nfct_get_expectation(cth, &orig, id); else if (options & CT_OPT_REPL) - res = nfct_get_expectation(cth, &reply); + res = nfct_get_expectation(cth, &reply, id); nfct_close(cth); break; -- cgit v1.2.3 From 0985fa365d2ac7aaf96cd4cdfc76e9ddda940886 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, 23 Oct 2005 22:15:29 +0000 Subject: See ChangeLog --- ChangeLog | 4 ++++ src/conntrack.c | 26 +++++++++++++------------- 2 files changed, 17 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index b079871..86c42eb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2005-10-24 + + o use NFCT_ANY_GROUP flag in nfct_open() + 2005-10-21 o Bumped version to 0.90 diff --git a/src/conntrack.c b/src/conntrack.c index 6ce945f..c6d90f9 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -911,7 +911,7 @@ int main(int argc, char *argv[]) retry--; switch(command) { case CT_LIST: - cth = nfct_open(CONNTRACK, 0); + cth = nfct_open(CONNTRACK, NFCT_ANY_GROUP); if (!cth) exit_error(OTHER_PROBLEM, "Not enough memory"); nfct_set_callback(cth, nfct_default_conntrack_display); @@ -923,7 +923,7 @@ int main(int argc, char *argv[]) nfct_close(cth); case EXP_LIST: - cth = nfct_open(EXPECT, 0); + cth = nfct_open(EXPECT, NFCT_ANY_GROUP); if (!cth) exit_error(OTHER_PROBLEM, "Not enough memory"); nfct_set_callback(cth, nfct_default_expect_display); @@ -954,7 +954,7 @@ int main(int argc, char *argv[]) if (!ct) exit_error(OTHER_PROBLEM, "Not Enough memory"); - cth = nfct_open(CONNTRACK, 0); + cth = nfct_open(CONNTRACK, NFCT_ANY_GROUP); if (!cth) { nfct_conntrack_free(ct); exit_error(OTHER_PROBLEM, "Not enough memory"); @@ -974,7 +974,7 @@ int main(int argc, char *argv[]) if (!exp) exit_error(OTHER_PROBLEM, "Not enough memory"); - cth = nfct_open(EXPECT, 0); + cth = nfct_open(EXPECT, NFCT_ANY_GROUP); if (!cth) { nfct_expect_free(exp); exit_error(OTHER_PROBLEM, "Not enough memory"); @@ -1000,7 +1000,7 @@ int main(int argc, char *argv[]) if (!ct) exit_error(OTHER_PROBLEM, "Not enough memory"); - cth = nfct_open(CONNTRACK, 0); + cth = nfct_open(CONNTRACK, NFCT_ANY_GROUP); if (!cth) { nfct_conntrack_free(ct); exit_error(OTHER_PROBLEM, "Not enough memory"); @@ -1011,7 +1011,7 @@ int main(int argc, char *argv[]) break; case CT_DELETE: - cth = nfct_open(CONNTRACK, 0); + cth = nfct_open(CONNTRACK, NFCT_ANY_GROUP); if (!cth) exit_error(OTHER_PROBLEM, "Not enough memory"); if (options & CT_OPT_ORIG) @@ -1026,7 +1026,7 @@ int main(int argc, char *argv[]) break; case EXP_DELETE: - cth = nfct_open(EXPECT, 0); + cth = nfct_open(EXPECT, NFCT_ANY_GROUP); if (!cth) exit_error(OTHER_PROBLEM, "Not enough memory"); if (options & CT_OPT_ORIG) @@ -1037,7 +1037,7 @@ int main(int argc, char *argv[]) break; case CT_GET: - cth = nfct_open(CONNTRACK, 0); + cth = nfct_open(CONNTRACK, NFCT_ANY_GROUP); if (!cth) exit_error(OTHER_PROBLEM, "Not enough memory"); nfct_set_callback(cth, nfct_default_conntrack_display); @@ -1051,7 +1051,7 @@ int main(int argc, char *argv[]) break; case EXP_GET: - cth = nfct_open(EXPECT, 0); + cth = nfct_open(EXPECT, NFCT_ANY_GROUP); if (!cth) exit_error(OTHER_PROBLEM, "Not enough memory"); nfct_set_callback(cth, nfct_default_expect_display); @@ -1063,7 +1063,7 @@ int main(int argc, char *argv[]) break; case CT_FLUSH: - cth = nfct_open(CONNTRACK, 0); + cth = nfct_open(CONNTRACK, NFCT_ANY_GROUP); if (!cth) exit_error(OTHER_PROBLEM, "Not enough memory"); res = nfct_flush_conntrack_table(cth); @@ -1071,7 +1071,7 @@ int main(int argc, char *argv[]) break; case EXP_FLUSH: - cth = nfct_open(EXPECT, 0); + cth = nfct_open(EXPECT, NFCT_ANY_GROUP); if (!cth) exit_error(OTHER_PROBLEM, "Not enough memory"); res = nfct_flush_expectation_table(cth); @@ -1088,7 +1088,7 @@ int main(int argc, char *argv[]) nfct_set_callback(cth, nfct_default_conntrack_display); res = nfct_event_conntrack(cth); } else { - cth = nfct_open(CONNTRACK, ~0U); + cth = nfct_open(CONNTRACK, NFCT_ANY_GROUP); if (!cth) exit_error(OTHER_PROBLEM, "Not enough memory"); @@ -1109,7 +1109,7 @@ int main(int argc, char *argv[]) nfct_set_callback(cth, nfct_default_expect_display); res = nfct_event_expectation(cth); } else { - cth = nfct_open(EXPECT, ~0U); + cth = nfct_open(EXPECT, NFCT_ANY_GROUP); if (!cth) exit_error(OTHER_PROBLEM, "Not enough memory"); -- cgit v1.2.3 From ab803040bab7a5b02aa99f6ffdb782848163d964 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: Thu, 27 Oct 2005 01:23:35 +0000 Subject: See ChangeLog --- ChangeLog | 7 +++++++ extensions/libct_proto_icmp.c | 2 +- extensions/libct_proto_sctp.c | 2 +- extensions/libct_proto_tcp.c | 2 +- extensions/libct_proto_udp.c | 2 +- include/conntrack.h | 7 ++++--- src/conntrack.c | 19 ++++--------------- 7 files changed, 19 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index b0756c8..8d99d04 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2005-10-27 + + o Use conntrack VERSION instead of the old LIBCT_VERSION + o proto_list and lib_dir are now static + o kill dead code: function dump_tuple + o Bumped version to 0.92 + 2005-10-25 o Add missing autogen.sh file diff --git a/extensions/libct_proto_icmp.c b/extensions/libct_proto_icmp.c index d7d9d5a..ce42021 100644 --- a/extensions/libct_proto_icmp.c +++ b/extensions/libct_proto_icmp.c @@ -105,7 +105,7 @@ static struct ctproto_handler icmp = { .final_check = final_check, .help = help, .opts = opts, - .version = LIBCT_VERSION, + .version = VERSION, }; void __attribute__ ((constructor)) init(void); diff --git a/extensions/libct_proto_sctp.c b/extensions/libct_proto_sctp.c index 5e96dc1..5667d18 100644 --- a/extensions/libct_proto_sctp.c +++ b/extensions/libct_proto_sctp.c @@ -143,7 +143,7 @@ static struct ctproto_handler sctp = { .final_check = final_check, .help = help, .opts = opts, - .version = LIBCT_VERSION, + .version = VERSION, }; void __attribute__ ((constructor)) init(void); diff --git a/extensions/libct_proto_tcp.c b/extensions/libct_proto_tcp.c index 97646ab..4f6e113 100644 --- a/extensions/libct_proto_tcp.c +++ b/extensions/libct_proto_tcp.c @@ -166,7 +166,7 @@ static struct ctproto_handler tcp = { .final_check = final_check, .help = help, .opts = opts, - .version = LIBCT_VERSION, + .version = VERSION, }; void __attribute__ ((constructor)) init(void); diff --git a/extensions/libct_proto_udp.c b/extensions/libct_proto_udp.c index 0da7bb5..02826cd 100644 --- a/extensions/libct_proto_udp.c +++ b/extensions/libct_proto_udp.c @@ -131,7 +131,7 @@ static struct ctproto_handler udp = { .final_check = final_check, .help = help, .opts = opts, - .version = LIBCT_VERSION, + .version = VERSION, }; void __attribute__ ((constructor)) init(void); diff --git a/include/conntrack.h b/include/conntrack.h index db434d6..db96102 100644 --- a/include/conntrack.h +++ b/include/conntrack.h @@ -1,11 +1,12 @@ -#ifndef _LIBCT_PROTO_H -#define _LIBCT_PROTO_H +#ifndef _CONNTRACK_H +#define _CONNTRACK_H #include "linux_list.h" #include #include -#define LIBCT_VERSION "0.1.0" +#define PROGNAME "conntrack" +#define VERSION "0.92" /* FIXME: These should be independent from kernel space */ #define IPS_ASSURED (1 << 2) diff --git a/src/conntrack.c b/src/conntrack.c index c6d90f9..3b3b26a 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -48,9 +48,6 @@ #include "conntrack.h" #include -#define PROGNAME "conntrack" -#define VERSION "0.90" - #ifndef PROC_SYS_MODPROBE #define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe" #endif @@ -238,15 +235,15 @@ static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = /*EXP_EVENT*/ {'x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x'}, }; -char *lib_dir = CONNTRACK_LIB_DIR; +static char *lib_dir = CONNTRACK_LIB_DIR; -LIST_HEAD(proto_list); +static LIST_HEAD(proto_list); void register_proto(struct ctproto_handler *h) { - if (strcmp(h->version, LIBCT_VERSION) != 0) { + if (strcmp(h->version, VERSION) != 0) { fprintf(stderr, "plugin `%s': version %s (I'm %s)\n", - h->name, h->version, LIBCT_VERSION); + h->name, h->version, VERSION); exit(1); } list_add(&h->head, &proto_list); @@ -443,14 +440,6 @@ err2str(int err, enum action command) return strerror(err); } -static void 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)); -} - #define PARSE_STATUS 0 #define PARSE_EVENT 1 #define PARSE_MAX 2 -- cgit v1.2.3 From 0291945051adc675b6e322c453364a0c5a9a6b02 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: Fri, 28 Oct 2005 00:29:24 +0000 Subject: See ChangeLog --- ChangeLog | 10 ++++++++ extensions/libct_proto_icmp.c | 6 ----- extensions/libct_proto_sctp.c | 6 ----- extensions/libct_proto_tcp.c | 6 ----- extensions/libct_proto_udp.c | 6 ----- include/conntrack.h | 3 +-- src/conntrack.c | 53 +++++++++++++++++++------------------------ 7 files changed, 34 insertions(+), 56 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 8d99d04..0b1d9ef 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2005-10-28 + + o New option -i for dumping: conntrack -L [-i] + o Fixed warning in findproto due to a stupid wrong type definition + o sed 's/nfct_set_callback/nfct_register_callback/g' + o killed the 'retry' logic, *sigh* it is broken in some cases + o killed broken and unneeded protocol handler destructors (fini) + o killed unregister_proto + o Bumped version to 0.93 + 2005-10-27 o Use conntrack VERSION instead of the old LIBCT_VERSION diff --git a/extensions/libct_proto_icmp.c b/extensions/libct_proto_icmp.c index ce42021..7b2b24a 100644 --- a/extensions/libct_proto_icmp.c +++ b/extensions/libct_proto_icmp.c @@ -109,14 +109,8 @@ static struct ctproto_handler icmp = { }; void __attribute__ ((constructor)) init(void); -void __attribute__ ((destructor)) fini(void); void init(void) { register_proto(&icmp); } - -void fini(void) -{ - unregister_proto(&icmp); -} diff --git a/extensions/libct_proto_sctp.c b/extensions/libct_proto_sctp.c index 5667d18..f2ced21 100644 --- a/extensions/libct_proto_sctp.c +++ b/extensions/libct_proto_sctp.c @@ -147,14 +147,8 @@ static struct ctproto_handler sctp = { }; void __attribute__ ((constructor)) init(void); -void __attribute__ ((destructor)) fini(void); void init(void) { register_proto(&sctp); } - -void fini(void) -{ - unregister_proto(&sctp); -} diff --git a/extensions/libct_proto_tcp.c b/extensions/libct_proto_tcp.c index 4f6e113..8969b48 100644 --- a/extensions/libct_proto_tcp.c +++ b/extensions/libct_proto_tcp.c @@ -170,14 +170,8 @@ static struct ctproto_handler tcp = { }; void __attribute__ ((constructor)) init(void); -void __attribute__ ((destructor)) fini(void); void init(void) { register_proto(&tcp); } - -void fini(void) -{ - unregister_proto(&tcp); -} diff --git a/extensions/libct_proto_udp.c b/extensions/libct_proto_udp.c index 02826cd..19af6f1 100644 --- a/extensions/libct_proto_udp.c +++ b/extensions/libct_proto_udp.c @@ -135,14 +135,8 @@ static struct ctproto_handler udp = { }; void __attribute__ ((constructor)) init(void); -void __attribute__ ((destructor)) fini(void); void init(void) { register_proto(&udp); } - -void fini(void) -{ - unregister_proto(&udp); -} diff --git a/include/conntrack.h b/include/conntrack.h index db96102..4aabd09 100644 --- a/include/conntrack.h +++ b/include/conntrack.h @@ -6,7 +6,7 @@ #include #define PROGNAME "conntrack" -#define VERSION "0.92" +#define VERSION "0.93" /* FIXME: These should be independent from kernel space */ #define IPS_ASSURED (1 << 2) @@ -43,7 +43,6 @@ struct ctproto_handler { }; extern void register_proto(struct ctproto_handler *h); -extern void unregister_proto(struct ctproto_handler *h); #define NIPQUAD(addr) \ ((unsigned char *)&addr)[0], \ diff --git a/src/conntrack.c b/src/conntrack.c index 3b3b26a..01f5e46 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -193,7 +193,7 @@ static struct option original_opts[] = { {"mask-dst", 1, 0, '}'}, {"nat-range", 1, 0, 'a'}, {"mark", 1, 0, 'm'}, - {"id", 1, 0, 'i'}, + {"id", 2, 0, 'i'}, {0, 0, 0, 0} }; @@ -218,7 +218,7 @@ static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = /* Well, it's better than "Re: Linux vs FreeBSD" */ { /* -s -d -r -q -p -t -u -z -e -x -y -k -l -a -m -i*/ -/*CT_LIST*/ {'x','x','x','x','x','x','x',' ','x','x','x','x','x','x','x','x'}, +/*CT_LIST*/ {'x','x','x','x','x','x','x',' ','x','x','x','x','x','x','x',' '}, /*CT_CREATE*/ {' ',' ',' ',' ','+','+','+','x','x','x','x','x','x',' ',' ','x'}, /*CT_UPDATE*/ {' ',' ',' ',' ','+','+','+','x','x','x','x','x','x','x',' ',' '}, /*CT_DELETE*/ {' ',' ',' ',' ',' ','x','x','x','x','x','x','x','x','x','x',' '}, @@ -249,15 +249,10 @@ void register_proto(struct ctproto_handler *h) list_add(&h->head, &proto_list); } -void unregister_proto(struct ctproto_handler *h) -{ - list_del(&h->head); -} - -static struct nfct_proto *findproto(char *name) +static struct ctproto_handler *findproto(char *name) { struct list_head *i; - struct nfct_proto *cur = NULL, *handler = NULL; + struct ctproto_handler *cur = NULL, *handler = NULL; if (!name) return handler; @@ -267,7 +262,7 @@ static struct nfct_proto *findproto(char *name) lib_dir = CONNTRACK_LIB_DIR; list_for_each(i, &proto_list) { - cur = (struct nfct_proto *) i; + cur = (struct ctproto_handler *) i; if (strcmp(cur->name, name) == 0) { handler = cur; break; @@ -717,7 +712,7 @@ int main(int argc, char *argv[]) unsigned int id = NFCT_ANY_ID; unsigned int type = 0, extra_flags = 0, event_mask = 0; int manip = -1; - int res = 0, retry = 2; + int res = 0; memset(&proto, 0, sizeof(union nfct_protoinfo)); memset(&orig, 0, sizeof(struct nfct_tuple)); @@ -727,7 +722,7 @@ int main(int argc, char *argv[]) memset(&range, 0, sizeof(struct nfct_nat)); while ((c = getopt_long(argc, argv, - "L::I::U::D::G::E::F::hVs:d:r:q:p:t:u:e:a:z[:]:{:}:m:i:", + "L::I::U::D::G::E::F::hVs:d:r:q:p:t:u:e:a:z[:]:{:}:m:i::", opts, NULL)) != -1) { switch(c) { case 'L': @@ -866,7 +861,9 @@ int main(int argc, char *argv[]) mark = atol(optarg); break; case 'i': - id = atol(optarg); + options |= CT_OPT_ID; + if (optarg) + id = atol(optarg); break; default: if (h && h->parse_opts @@ -896,14 +893,17 @@ int main(int argc, char *argv[]) exit_error(PARAMETER_PROBLEM, "Missing protocol arguments!\n"); } - while (retry > 0) { - retry--; switch(command) { case CT_LIST: cth = nfct_open(CONNTRACK, NFCT_ANY_GROUP); if (!cth) exit_error(OTHER_PROBLEM, "Not enough memory"); - nfct_set_callback(cth, nfct_default_conntrack_display); + + if (options & CT_OPT_ID) + nfct_register_callback(cth, nfct_default_conntrack_display_id); + else + nfct_register_callback(cth, nfct_default_conntrack_display); + if (options & CT_OPT_ZERO) res = nfct_dump_conntrack_table_reset_counters(cth); else @@ -915,7 +915,7 @@ int main(int argc, char *argv[]) cth = nfct_open(EXPECT, NFCT_ANY_GROUP); if (!cth) exit_error(OTHER_PROBLEM, "Not enough memory"); - nfct_set_callback(cth, nfct_default_expect_display); + nfct_register_callback(cth, nfct_default_expect_display); res = nfct_dump_expect_list(cth); nfct_close(cth); break; @@ -1029,7 +1029,7 @@ int main(int argc, char *argv[]) cth = nfct_open(CONNTRACK, NFCT_ANY_GROUP); if (!cth) exit_error(OTHER_PROBLEM, "Not enough memory"); - nfct_set_callback(cth, nfct_default_conntrack_display); + nfct_register_callback(cth, nfct_default_conntrack_display); if (options & CT_OPT_ORIG) res = nfct_get_conntrack(cth, &orig, NFCT_DIR_ORIGINAL, id); @@ -1043,7 +1043,7 @@ int main(int argc, char *argv[]) cth = nfct_open(EXPECT, NFCT_ANY_GROUP); if (!cth) exit_error(OTHER_PROBLEM, "Not enough memory"); - nfct_set_callback(cth, nfct_default_expect_display); + nfct_register_callback(cth, nfct_default_expect_display); if (options & CT_OPT_ORIG) res = nfct_get_expectation(cth, &orig, id); else if (options & CT_OPT_REPL) @@ -1074,7 +1074,7 @@ int main(int argc, char *argv[]) exit_error(OTHER_PROBLEM, "Not enough memory"); signal(SIGINT, event_sighandler); - nfct_set_callback(cth, nfct_default_conntrack_display); + nfct_register_callback(cth, nfct_default_conntrack_display); res = nfct_event_conntrack(cth); } else { cth = nfct_open(CONNTRACK, NFCT_ANY_GROUP); @@ -1082,7 +1082,7 @@ int main(int argc, char *argv[]) exit_error(OTHER_PROBLEM, "Not enough memory"); signal(SIGINT, event_sighandler); - nfct_set_callback(cth, nfct_default_conntrack_display); + nfct_register_callback(cth, nfct_default_conntrack_display); res = nfct_event_conntrack(cth); } nfct_close(cth); @@ -1095,7 +1095,7 @@ int main(int argc, char *argv[]) exit_error(OTHER_PROBLEM, "Not enough memory"); signal(SIGINT, event_sighandler); - nfct_set_callback(cth, nfct_default_expect_display); + nfct_register_callback(cth, nfct_default_expect_display); res = nfct_event_expectation(cth); } else { cth = nfct_open(EXPECT, NFCT_ANY_GROUP); @@ -1103,7 +1103,7 @@ int main(int argc, char *argv[]) exit_error(OTHER_PROBLEM, "Not enough memory"); signal(SIGINT, event_sighandler); - nfct_set_callback(cth, nfct_default_expect_display); + nfct_register_callback(cth, nfct_default_expect_display); res = nfct_event_expectation(cth); } nfct_close(cth); @@ -1121,13 +1121,6 @@ int main(int argc, char *argv[]) usage(argv[0]); break; } - /* Maybe ip_conntrack_netlink isn't insmod'ed */ - if (res < 0 && retry) - /* Give it a try just once */ - iptables_insmod("ip_conntrack_netlink", NULL); - else - retry--; - } if (opts != original_opts) { free(opts); -- cgit v1.2.3 From e56951deca51348dd616f34e74d458f437ed7ab8 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: Fri, 28 Oct 2005 00:41:23 +0000 Subject: See ChangeLog. This fixes an indentation problem in conntrack.c, I've separated this minor change from the previous *important* and very very recent commit. Why? Just to keep important things separated from aesthetic stuff like this ;) --- ChangeLog | 1 + src/conntrack.c | 412 ++++++++++++++++++++++++++++---------------------------- 2 files changed, 206 insertions(+), 207 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 0b1d9ef..e387e10 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,6 +6,7 @@ o killed the 'retry' logic, *sigh* it is broken in some cases o killed broken and unneeded protocol handler destructors (fini) o killed unregister_proto + o Fixed code indentation in the command selector o Bumped version to 0.93 2005-10-27 diff --git a/src/conntrack.c b/src/conntrack.c index 01f5e46..83bbf70 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -893,234 +893,232 @@ int main(int argc, char *argv[]) exit_error(PARAMETER_PROBLEM, "Missing protocol arguments!\n"); } - switch(command) { - case CT_LIST: - cth = nfct_open(CONNTRACK, NFCT_ANY_GROUP); - if (!cth) - exit_error(OTHER_PROBLEM, "Not enough memory"); + switch(command) { - if (options & CT_OPT_ID) - nfct_register_callback(cth, nfct_default_conntrack_display_id); - else - nfct_register_callback(cth, nfct_default_conntrack_display); - - if (options & CT_OPT_ZERO) - res = nfct_dump_conntrack_table_reset_counters(cth); - else - res = nfct_dump_conntrack_table(cth); - break; - nfct_close(cth); + case CT_LIST: + cth = nfct_open(CONNTRACK, NFCT_ANY_GROUP); + if (!cth) + exit_error(OTHER_PROBLEM, "Not enough memory"); - case EXP_LIST: - cth = nfct_open(EXPECT, NFCT_ANY_GROUP); - if (!cth) - exit_error(OTHER_PROBLEM, "Not enough memory"); - nfct_register_callback(cth, nfct_default_expect_display); - res = nfct_dump_expect_list(cth); - nfct_close(cth); - break; + if (options & CT_OPT_ID) + nfct_register_callback(cth, + nfct_default_conntrack_display_id); + else + nfct_register_callback(cth, + nfct_default_conntrack_display); - case CT_CREATE: - if ((options & CT_OPT_ORIG) - && !(options & CT_OPT_REPL)) { - reply.src.v4 = orig.dst.v4; - reply.dst.v4 = orig.src.v4; - } else if (!(options & CT_OPT_ORIG) - && (options & CT_OPT_REPL)) { - orig.src.v4 = reply.dst.v4; - orig.dst.v4 = reply.src.v4; - } - if (options & CT_OPT_NATRANGE) - ct = nfct_conntrack_alloc(&orig, &reply, - timeout, &proto, - status, mark, id, - &range); - else - ct = nfct_conntrack_alloc(&orig, &reply, - timeout, &proto, - status, mark, id, - NULL); - if (!ct) - exit_error(OTHER_PROBLEM, "Not Enough memory"); + if (options & CT_OPT_ZERO) + res = nfct_dump_conntrack_table_reset_counters(cth); + else + res = nfct_dump_conntrack_table(cth); + nfct_close(cth); + break; + + case EXP_LIST: + cth = nfct_open(EXPECT, NFCT_ANY_GROUP); + if (!cth) + exit_error(OTHER_PROBLEM, "Not enough memory"); + nfct_register_callback(cth, nfct_default_expect_display); + res = nfct_dump_expect_list(cth); + nfct_close(cth); + break; - cth = nfct_open(CONNTRACK, NFCT_ANY_GROUP); - if (!cth) { - nfct_conntrack_free(ct); - exit_error(OTHER_PROBLEM, "Not enough memory"); - } - res = nfct_create_conntrack(cth, ct); - nfct_close(cth); - nfct_conntrack_free(ct); - break; - - case EXP_CREATE: - if (options & CT_OPT_ORIG) - exp = nfct_expect_alloc(&orig, &exptuple, - &mask, timeout, id); - else if (options & CT_OPT_REPL) - exp = nfct_expect_alloc(&reply, &exptuple, - &mask, timeout, id); - if (!exp) - exit_error(OTHER_PROBLEM, "Not enough memory"); - - cth = nfct_open(EXPECT, NFCT_ANY_GROUP); - if (!cth) { - nfct_expect_free(exp); - exit_error(OTHER_PROBLEM, "Not enough memory"); - } - res = nfct_create_expectation(cth, exp); - nfct_expect_free(exp); - nfct_close(cth); - break; - - case CT_UPDATE: - if ((options & CT_OPT_ORIG) - && !(options & CT_OPT_REPL)) { - reply.src.v4 = orig.dst.v4; - reply.dst.v4 = orig.src.v4; - } else if (!(options & CT_OPT_ORIG) - && (options & CT_OPT_REPL)) { - orig.src.v4 = reply.dst.v4; - orig.dst.v4 = reply.src.v4; - } - ct = nfct_conntrack_alloc(&orig, &reply, timeout, + case CT_CREATE: + if ((options & CT_OPT_ORIG) + && !(options & CT_OPT_REPL)) { + reply.src.v4 = orig.dst.v4; + reply.dst.v4 = orig.src.v4; + } else if (!(options & CT_OPT_ORIG) + && (options & CT_OPT_REPL)) { + orig.src.v4 = reply.dst.v4; + orig.dst.v4 = reply.src.v4; + } + if (options & CT_OPT_NATRANGE) + ct = nfct_conntrack_alloc(&orig, &reply, timeout, + &proto, status, mark, id, + &range); + else + ct = nfct_conntrack_alloc(&orig, &reply, timeout, &proto, status, mark, id, NULL); - if (!ct) - exit_error(OTHER_PROBLEM, "Not enough memory"); - - cth = nfct_open(CONNTRACK, NFCT_ANY_GROUP); - if (!cth) { - nfct_conntrack_free(ct); - exit_error(OTHER_PROBLEM, "Not enough memory"); - } - res = nfct_update_conntrack(cth, ct); + if (!ct) + exit_error(OTHER_PROBLEM, "Not Enough memory"); + + cth = nfct_open(CONNTRACK, NFCT_ANY_GROUP); + if (!cth) { nfct_conntrack_free(ct); - nfct_close(cth); - break; - - case CT_DELETE: - cth = nfct_open(CONNTRACK, NFCT_ANY_GROUP); - if (!cth) - exit_error(OTHER_PROBLEM, "Not enough memory"); - if (options & CT_OPT_ORIG) - res = nfct_delete_conntrack(cth, &orig, - NFCT_DIR_ORIGINAL, - id); - else if (options & CT_OPT_REPL) - res = nfct_delete_conntrack(cth, &reply, - NFCT_DIR_REPLY, - id); - nfct_close(cth); - break; - - case EXP_DELETE: - cth = nfct_open(EXPECT, NFCT_ANY_GROUP); + exit_error(OTHER_PROBLEM, "Not enough memory"); + } + res = nfct_create_conntrack(cth, ct); + nfct_close(cth); + nfct_conntrack_free(ct); + break; + + case EXP_CREATE: + if (options & CT_OPT_ORIG) + exp = nfct_expect_alloc(&orig, &exptuple, + &mask, timeout, id); + else if (options & CT_OPT_REPL) + exp = nfct_expect_alloc(&reply, &exptuple, + &mask, timeout, id); + if (!exp) + exit_error(OTHER_PROBLEM, "Not enough memory"); + + cth = nfct_open(EXPECT, NFCT_ANY_GROUP); + if (!cth) { + nfct_expect_free(exp); + exit_error(OTHER_PROBLEM, "Not enough memory"); + } + res = nfct_create_expectation(cth, exp); + nfct_expect_free(exp); + nfct_close(cth); + break; + + case CT_UPDATE: + if ((options & CT_OPT_ORIG) + && !(options & CT_OPT_REPL)) { + reply.src.v4 = orig.dst.v4; + reply.dst.v4 = orig.src.v4; + } else if (!(options & CT_OPT_ORIG) + && (options & CT_OPT_REPL)) { + orig.src.v4 = reply.dst.v4; + orig.dst.v4 = reply.src.v4; + } + ct = nfct_conntrack_alloc(&orig, &reply, timeout, + &proto, status, mark, id, + NULL); + if (!ct) + exit_error(OTHER_PROBLEM, "Not enough memory"); + + cth = nfct_open(CONNTRACK, NFCT_ANY_GROUP); + if (!cth) { + nfct_conntrack_free(ct); + exit_error(OTHER_PROBLEM, "Not enough memory"); + } + res = nfct_update_conntrack(cth, ct); + nfct_conntrack_free(ct); + nfct_close(cth); + break; + + case CT_DELETE: + cth = nfct_open(CONNTRACK, NFCT_ANY_GROUP); + if (!cth) + exit_error(OTHER_PROBLEM, "Not enough memory"); + if (options & CT_OPT_ORIG) + res = nfct_delete_conntrack(cth, &orig, + NFCT_DIR_ORIGINAL, + id); + else if (options & CT_OPT_REPL) + res = nfct_delete_conntrack(cth, &reply, + NFCT_DIR_REPLY, + id); + nfct_close(cth); + break; + + case EXP_DELETE: + cth = nfct_open(EXPECT, NFCT_ANY_GROUP); + if (!cth) + exit_error(OTHER_PROBLEM, "Not enough memory"); + if (options & CT_OPT_ORIG) + res = nfct_delete_expectation(cth, &orig, id); + else if (options & CT_OPT_REPL) + res = nfct_delete_expectation(cth, &reply, id); + nfct_close(cth); + break; + + case CT_GET: + cth = nfct_open(CONNTRACK, NFCT_ANY_GROUP); + if (!cth) + exit_error(OTHER_PROBLEM, "Not enough memory"); + nfct_register_callback(cth, nfct_default_conntrack_display); + if (options & CT_OPT_ORIG) + res = nfct_get_conntrack(cth, &orig, + NFCT_DIR_ORIGINAL, id); + else if (options & CT_OPT_REPL) + res = nfct_get_conntrack(cth, &reply, + NFCT_DIR_REPLY, id); + nfct_close(cth); + break; + + case EXP_GET: + cth = nfct_open(EXPECT, NFCT_ANY_GROUP); + if (!cth) + exit_error(OTHER_PROBLEM, "Not enough memory"); + nfct_register_callback(cth, nfct_default_expect_display); + if (options & CT_OPT_ORIG) + res = nfct_get_expectation(cth, &orig, id); + else if (options & CT_OPT_REPL) + res = nfct_get_expectation(cth, &reply, id); + nfct_close(cth); + break; + + case CT_FLUSH: + cth = nfct_open(CONNTRACK, NFCT_ANY_GROUP); + if (!cth) + exit_error(OTHER_PROBLEM, "Not enough memory"); + res = nfct_flush_conntrack_table(cth); + nfct_close(cth); + break; + + case EXP_FLUSH: + cth = nfct_open(EXPECT, NFCT_ANY_GROUP); + if (!cth) + exit_error(OTHER_PROBLEM, "Not enough memory"); + res = nfct_flush_expectation_table(cth); + nfct_close(cth); + break; + + case CT_EVENT: + if (options & CT_OPT_EVENT_MASK) { + cth = nfct_open(CONNTRACK, event_mask); if (!cth) exit_error(OTHER_PROBLEM, "Not enough memory"); - if (options & CT_OPT_ORIG) - res = nfct_delete_expectation(cth, &orig, id); - else if (options & CT_OPT_REPL) - res = nfct_delete_expectation(cth, &reply, id); - nfct_close(cth); - break; - - case CT_GET: + signal(SIGINT, event_sighandler); + nfct_register_callback(cth, + nfct_default_conntrack_display); + res = nfct_event_conntrack(cth); + } else { cth = nfct_open(CONNTRACK, NFCT_ANY_GROUP); if (!cth) exit_error(OTHER_PROBLEM, "Not enough memory"); + signal(SIGINT, event_sighandler); nfct_register_callback(cth, nfct_default_conntrack_display); - if (options & CT_OPT_ORIG) - res = nfct_get_conntrack(cth, &orig, - NFCT_DIR_ORIGINAL, id); - else if (options & CT_OPT_REPL) - res = nfct_get_conntrack(cth, &reply, - NFCT_DIR_REPLY, id); - nfct_close(cth); - break; + res = nfct_event_conntrack(cth); + } + nfct_close(cth); + break; - case EXP_GET: - cth = nfct_open(EXPECT, NFCT_ANY_GROUP); + case EXP_EVENT: + if (options & CT_OPT_EVENT_MASK) { + cth = nfct_open(EXPECT, event_mask); if (!cth) exit_error(OTHER_PROBLEM, "Not enough memory"); + signal(SIGINT, event_sighandler); nfct_register_callback(cth, nfct_default_expect_display); - if (options & CT_OPT_ORIG) - res = nfct_get_expectation(cth, &orig, id); - else if (options & CT_OPT_REPL) - res = nfct_get_expectation(cth, &reply, id); - nfct_close(cth); - break; - - case CT_FLUSH: - cth = nfct_open(CONNTRACK, NFCT_ANY_GROUP); - if (!cth) - exit_error(OTHER_PROBLEM, "Not enough memory"); - res = nfct_flush_conntrack_table(cth); - nfct_close(cth); - break; - - case EXP_FLUSH: + res = nfct_event_expectation(cth); + } else { cth = nfct_open(EXPECT, NFCT_ANY_GROUP); if (!cth) exit_error(OTHER_PROBLEM, "Not enough memory"); - res = nfct_flush_expectation_table(cth); - nfct_close(cth); - break; - - case CT_EVENT: - if (options & CT_OPT_EVENT_MASK) { - cth = nfct_open(CONNTRACK, event_mask); - if (!cth) - exit_error(OTHER_PROBLEM, - "Not enough memory"); - signal(SIGINT, event_sighandler); - nfct_register_callback(cth, nfct_default_conntrack_display); - res = nfct_event_conntrack(cth); - } else { - cth = nfct_open(CONNTRACK, NFCT_ANY_GROUP); - if (!cth) - exit_error(OTHER_PROBLEM, - "Not enough memory"); - signal(SIGINT, event_sighandler); - nfct_register_callback(cth, nfct_default_conntrack_display); - res = nfct_event_conntrack(cth); - } - nfct_close(cth); - break; - - case EXP_EVENT: - if (options & CT_OPT_EVENT_MASK) { - cth = nfct_open(EXPECT, event_mask); - if (!cth) - exit_error(OTHER_PROBLEM, - "Not enough memory"); - signal(SIGINT, event_sighandler); - nfct_register_callback(cth, nfct_default_expect_display); - res = nfct_event_expectation(cth); - } else { - cth = nfct_open(EXPECT, NFCT_ANY_GROUP); - if (!cth) - exit_error(OTHER_PROBLEM, - "Not enough memory"); - signal(SIGINT, event_sighandler); - nfct_register_callback(cth, nfct_default_expect_display); - res = nfct_event_expectation(cth); - } - nfct_close(cth); - break; - - case CT_VERSION: - fprintf(stdout, "%s v%s\n", PROGNAME, VERSION); - break; - case CT_HELP: - usage(argv[0]); - if (options & CT_OPT_PROTO) - extension_help(h); - break; - default: - usage(argv[0]); - break; + signal(SIGINT, event_sighandler); + nfct_register_callback(cth, nfct_default_expect_display); + res = nfct_event_expectation(cth); } + nfct_close(cth); + break; + + case CT_VERSION: + fprintf(stdout, "%s v%s\n", PROGNAME, VERSION); + break; + case CT_HELP: + usage(argv[0]); + if (options & CT_OPT_PROTO) + extension_help(h); + break; + default: + usage(argv[0]); + break; + } if (opts != original_opts) { free(opts); -- cgit v1.2.3 From 1f948dd83a806ddbfa6d232e4e5df75634004631 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: Mon, 31 Oct 2005 04:25:58 +0000 Subject: See ChangeLog --- ChangeLog | 12 +++++++ extensions/libct_proto_icmp.c | 2 +- extensions/libct_proto_sctp.c | 2 +- extensions/libct_proto_tcp.c | 2 +- extensions/libct_proto_udp.c | 2 +- include/conntrack.h | 2 +- src/conntrack.c | 75 +++++++++++++++++++++++-------------------- 7 files changed, 57 insertions(+), 40 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index e387e10..fdb8c75 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2005-10-30 + + Special thanks to Deti Fiegl from the Leibniz Supercomputing Centre in + Munich, Germany for providing the "fast" hardware to reproduce + spurious bugs ;) + + o Replace misleading message "Not enough memory" by "Can't open handler" + o New option -i for expectation dumping: conntrack -L expect [-i] + o sed 's/VERSION/CONNTRACK_VERSION/g' + o Fix nfct_open flags, now uses NFCT_ALL_GROUPS when needed + o Bumped version to 0.94 + 2005-10-28 o New option -i for dumping: conntrack -L [-i] diff --git a/extensions/libct_proto_icmp.c b/extensions/libct_proto_icmp.c index 7b2b24a..d9c5cb3 100644 --- a/extensions/libct_proto_icmp.c +++ b/extensions/libct_proto_icmp.c @@ -105,7 +105,7 @@ static struct ctproto_handler icmp = { .final_check = final_check, .help = help, .opts = opts, - .version = VERSION, + .version = CONNTRACK_VERSION, }; void __attribute__ ((constructor)) init(void); diff --git a/extensions/libct_proto_sctp.c b/extensions/libct_proto_sctp.c index f2ced21..2b1a337 100644 --- a/extensions/libct_proto_sctp.c +++ b/extensions/libct_proto_sctp.c @@ -143,7 +143,7 @@ static struct ctproto_handler sctp = { .final_check = final_check, .help = help, .opts = opts, - .version = VERSION, + .version = CONNTRACK_VERSION, }; void __attribute__ ((constructor)) init(void); diff --git a/extensions/libct_proto_tcp.c b/extensions/libct_proto_tcp.c index 8969b48..4aa6587 100644 --- a/extensions/libct_proto_tcp.c +++ b/extensions/libct_proto_tcp.c @@ -166,7 +166,7 @@ static struct ctproto_handler tcp = { .final_check = final_check, .help = help, .opts = opts, - .version = VERSION, + .version = CONNTRACK_VERSION, }; void __attribute__ ((constructor)) init(void); diff --git a/extensions/libct_proto_udp.c b/extensions/libct_proto_udp.c index 19af6f1..b33ba7d 100644 --- a/extensions/libct_proto_udp.c +++ b/extensions/libct_proto_udp.c @@ -131,7 +131,7 @@ static struct ctproto_handler udp = { .final_check = final_check, .help = help, .opts = opts, - .version = VERSION, + .version = CONNTRACK_VERSION, }; void __attribute__ ((constructor)) init(void); diff --git a/include/conntrack.h b/include/conntrack.h index 4aabd09..256fa00 100644 --- a/include/conntrack.h +++ b/include/conntrack.h @@ -6,7 +6,7 @@ #include #define PROGNAME "conntrack" -#define VERSION "0.93" +#define CONNTRACK_VERSION "0.94" /* FIXME: These should be independent from kernel space */ #define IPS_ASSURED (1 << 2) diff --git a/src/conntrack.c b/src/conntrack.c index 83bbf70..4f9a687 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -227,7 +227,7 @@ static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = /*CT_EVENT*/ {'x','x','x','x','x','x','x','x',' ','x','x','x','x','x','x','x'}, /*VERSION*/ {'x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x'}, /*HELP*/ {'x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x'}, -/*EXP_LIST*/ {'x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x'}, +/*EXP_LIST*/ {'x','x','x','x','x','x','x','x','x','x','x','x','x','x','x',' '}, /*EXP_CREATE*/{'+','+',' ',' ','+','+',' ','x','x','+','+','+','+','x','x','x'}, /*EXP_DELETE*/{'+','+',' ',' ','+','x','x','x','x','x','x','x','x','x','x','x'}, /*EXP_GET*/ {'+','+',' ',' ','+','x','x','x','x','x','x','x','x','x','x','x'}, @@ -241,9 +241,9 @@ static LIST_HEAD(proto_list); void register_proto(struct ctproto_handler *h) { - if (strcmp(h->version, VERSION) != 0) { + if (strcmp(h->version, CONNTRACK_VERSION) != 0) { fprintf(stderr, "plugin `%s': version %s (I'm %s)\n", - h->name, h->version, VERSION); + h->name, h->version, CONNTRACK_VERSION); exit(1); } list_add(&h->head, &proto_list); @@ -316,7 +316,7 @@ exit_error(enum exittype status, char *msg, ...) global_option_offset = 0; } va_start(args, msg); - fprintf(stderr,"%s v%s: ", PROGNAME, VERSION); + fprintf(stderr,"%s v%s: ", PROGNAME, CONNTRACK_VERSION); vfprintf(stderr, msg, args); va_end(args); fprintf(stderr, "\n"); @@ -666,7 +666,7 @@ static void event_sighandler(int s) } void usage(char *prog) { -fprintf(stdout, "Tool to manipulate conntrack and expectations. Version %s\n", VERSION); +fprintf(stdout, "Tool to manipulate conntrack and expectations. Version %s\n", CONNTRACK_VERSION); fprintf(stdout, "Usage: %s [commands] [options]\n", prog); fprintf(stdout, "\n"); fprintf(stdout, "Commands:\n"); @@ -896,9 +896,9 @@ int main(int argc, char *argv[]) switch(command) { case CT_LIST: - cth = nfct_open(CONNTRACK, NFCT_ANY_GROUP); + cth = nfct_open(CONNTRACK, 0); if (!cth) - exit_error(OTHER_PROBLEM, "Not enough memory"); + exit_error(OTHER_PROBLEM, "Can't open handler"); if (options & CT_OPT_ID) nfct_register_callback(cth, @@ -915,10 +915,15 @@ int main(int argc, char *argv[]) break; case EXP_LIST: - cth = nfct_open(EXPECT, NFCT_ANY_GROUP); + cth = nfct_open(EXPECT, 0); if (!cth) - exit_error(OTHER_PROBLEM, "Not enough memory"); - nfct_register_callback(cth, nfct_default_expect_display); + exit_error(OTHER_PROBLEM, "Can't open handler"); + if (options & CT_OPT_ID) + nfct_register_callback(cth, + nfct_default_expect_display_id); + else + nfct_register_callback(cth, + nfct_default_expect_display); res = nfct_dump_expect_list(cth); nfct_close(cth); break; @@ -944,10 +949,10 @@ int main(int argc, char *argv[]) if (!ct) exit_error(OTHER_PROBLEM, "Not Enough memory"); - cth = nfct_open(CONNTRACK, NFCT_ANY_GROUP); + cth = nfct_open(CONNTRACK, 0); if (!cth) { nfct_conntrack_free(ct); - exit_error(OTHER_PROBLEM, "Not enough memory"); + exit_error(OTHER_PROBLEM, "Can't open handler"); } res = nfct_create_conntrack(cth, ct); nfct_close(cth); @@ -964,10 +969,10 @@ int main(int argc, char *argv[]) if (!exp) exit_error(OTHER_PROBLEM, "Not enough memory"); - cth = nfct_open(EXPECT, NFCT_ANY_GROUP); + cth = nfct_open(EXPECT, 0); if (!cth) { nfct_expect_free(exp); - exit_error(OTHER_PROBLEM, "Not enough memory"); + exit_error(OTHER_PROBLEM, "Can't open handler"); } res = nfct_create_expectation(cth, exp); nfct_expect_free(exp); @@ -990,10 +995,10 @@ int main(int argc, char *argv[]) if (!ct) exit_error(OTHER_PROBLEM, "Not enough memory"); - cth = nfct_open(CONNTRACK, NFCT_ANY_GROUP); + cth = nfct_open(CONNTRACK, 0); if (!cth) { nfct_conntrack_free(ct); - exit_error(OTHER_PROBLEM, "Not enough memory"); + exit_error(OTHER_PROBLEM, "Can't open handler"); } res = nfct_update_conntrack(cth, ct); nfct_conntrack_free(ct); @@ -1001,9 +1006,9 @@ int main(int argc, char *argv[]) break; case CT_DELETE: - cth = nfct_open(CONNTRACK, NFCT_ANY_GROUP); + cth = nfct_open(CONNTRACK, 0); if (!cth) - exit_error(OTHER_PROBLEM, "Not enough memory"); + exit_error(OTHER_PROBLEM, "Can't open handler"); if (options & CT_OPT_ORIG) res = nfct_delete_conntrack(cth, &orig, NFCT_DIR_ORIGINAL, @@ -1016,9 +1021,9 @@ int main(int argc, char *argv[]) break; case EXP_DELETE: - cth = nfct_open(EXPECT, NFCT_ANY_GROUP); + cth = nfct_open(EXPECT, 0); if (!cth) - exit_error(OTHER_PROBLEM, "Not enough memory"); + exit_error(OTHER_PROBLEM, "Can't open handler"); if (options & CT_OPT_ORIG) res = nfct_delete_expectation(cth, &orig, id); else if (options & CT_OPT_REPL) @@ -1027,9 +1032,9 @@ int main(int argc, char *argv[]) break; case CT_GET: - cth = nfct_open(CONNTRACK, NFCT_ANY_GROUP); + cth = nfct_open(CONNTRACK, 0); if (!cth) - exit_error(OTHER_PROBLEM, "Not enough memory"); + exit_error(OTHER_PROBLEM, "Can't open handler"); nfct_register_callback(cth, nfct_default_conntrack_display); if (options & CT_OPT_ORIG) res = nfct_get_conntrack(cth, &orig, @@ -1041,9 +1046,9 @@ int main(int argc, char *argv[]) break; case EXP_GET: - cth = nfct_open(EXPECT, NFCT_ANY_GROUP); + cth = nfct_open(EXPECT, 0); if (!cth) - exit_error(OTHER_PROBLEM, "Not enough memory"); + exit_error(OTHER_PROBLEM, "Can't open handler"); nfct_register_callback(cth, nfct_default_expect_display); if (options & CT_OPT_ORIG) res = nfct_get_expectation(cth, &orig, id); @@ -1053,17 +1058,17 @@ int main(int argc, char *argv[]) break; case CT_FLUSH: - cth = nfct_open(CONNTRACK, NFCT_ANY_GROUP); + cth = nfct_open(CONNTRACK, 0); if (!cth) - exit_error(OTHER_PROBLEM, "Not enough memory"); + exit_error(OTHER_PROBLEM, "Can't open handler"); res = nfct_flush_conntrack_table(cth); nfct_close(cth); break; case EXP_FLUSH: - cth = nfct_open(EXPECT, NFCT_ANY_GROUP); + cth = nfct_open(EXPECT, 0); if (!cth) - exit_error(OTHER_PROBLEM, "Not enough memory"); + exit_error(OTHER_PROBLEM, "Can't open handler"); res = nfct_flush_expectation_table(cth); nfct_close(cth); break; @@ -1072,15 +1077,15 @@ int main(int argc, char *argv[]) if (options & CT_OPT_EVENT_MASK) { cth = nfct_open(CONNTRACK, event_mask); if (!cth) - exit_error(OTHER_PROBLEM, "Not enough memory"); + exit_error(OTHER_PROBLEM, "Can't open handler"); signal(SIGINT, event_sighandler); nfct_register_callback(cth, nfct_default_conntrack_display); res = nfct_event_conntrack(cth); } else { - cth = nfct_open(CONNTRACK, NFCT_ANY_GROUP); + cth = nfct_open(CONNTRACK, NFCT_ALL_GROUPS); if (!cth) - exit_error(OTHER_PROBLEM, "Not enough memory"); + exit_error(OTHER_PROBLEM, "Can't open handler"); signal(SIGINT, event_sighandler); nfct_register_callback(cth, nfct_default_conntrack_display); res = nfct_event_conntrack(cth); @@ -1092,14 +1097,14 @@ int main(int argc, char *argv[]) if (options & CT_OPT_EVENT_MASK) { cth = nfct_open(EXPECT, event_mask); if (!cth) - exit_error(OTHER_PROBLEM, "Not enough memory"); + exit_error(OTHER_PROBLEM, "Can't open handler"); signal(SIGINT, event_sighandler); nfct_register_callback(cth, nfct_default_expect_display); res = nfct_event_expectation(cth); } else { - cth = nfct_open(EXPECT, NFCT_ANY_GROUP); + cth = nfct_open(EXPECT, NFCT_ALL_GROUPS); if (!cth) - exit_error(OTHER_PROBLEM, "Not enough memory"); + exit_error(OTHER_PROBLEM, "Can't open handler"); signal(SIGINT, event_sighandler); nfct_register_callback(cth, nfct_default_expect_display); res = nfct_event_expectation(cth); @@ -1108,7 +1113,7 @@ int main(int argc, char *argv[]) break; case CT_VERSION: - fprintf(stdout, "%s v%s\n", PROGNAME, VERSION); + fprintf(stdout, "%s v%s\n", PROGNAME, CONNTRACK_VERSION); break; case CT_HELP: usage(argv[0]); -- cgit v1.2.3 From 527d116c60f1766ca384504e18d08c775109a6cc 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: Tue, 1 Nov 2005 00:36:42 +0000 Subject: See ChangeLog --- ChangeLog | 10 ++++++++++ include/conntrack.h | 2 +- src/conntrack.c | 42 ++++++++++++++++++------------------------ 3 files changed, 29 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index fdb8c75..7d2c085 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2005-11-01 + + o Fix error message describing illegal option -E -i + o -D -i ID requires tuple information: Display an error message + o Use NFCT_ALL_CT_GROUPS flag instead of NFCT_ALL_GROUPS + o Event mask doesn't make sense for expectations, kill dead code + o Bumped version to 0.95 + + o Fix wrong formating in conntrack -h + 2005-10-30 Special thanks to Deti Fiegl from the Leibniz Supercomputing Centre in diff --git a/include/conntrack.h b/include/conntrack.h index 256fa00..58a9170 100644 --- a/include/conntrack.h +++ b/include/conntrack.h @@ -6,7 +6,7 @@ #include #define PROGNAME "conntrack" -#define CONNTRACK_VERSION "0.94" +#define CONNTRACK_VERSION "0.95" /* FIXME: These should be independent from kernel space */ #define IPS_ASSURED (1 << 2) diff --git a/src/conntrack.c b/src/conntrack.c index 4f9a687..fcd0ce4 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -166,7 +166,7 @@ enum options { #define NUMBER_OF_OPT CT_OPT_MAX static const char optflags[NUMBER_OF_OPT] -= {'s','d','r','q','p','t','u','z','e','[',']','{','}','a','i','m'}; += {'s','d','r','q','p','t','u','z','e','[',']','{','}','a','m','i'}; static struct option original_opts[] = { {"dump", 2, 0, 'L'}, @@ -670,13 +670,13 @@ fprintf(stdout, "Tool to manipulate conntrack and expectations. Version %s\n", C fprintf(stdout, "Usage: %s [commands] [options]\n", prog); fprintf(stdout, "\n"); fprintf(stdout, "Commands:\n"); -fprintf(stdout, "-L [table] [-z] List conntrack or expectation table\n"); -fprintf(stdout, "-G [table] parameters Get conntrack or expectation\n"); -fprintf(stdout, "-D [table] parameters Delete conntrack or expectation\n"); -fprintf(stdout, "-I [table] parameters Create a conntrack or expectation\n"); -fprintf(stdout, "-U [table] parameters Update a conntrack\n"); -fprintf(stdout, "-E [table] [options] Show events\n"); -fprintf(stdout, "-F [table] Flush table\n"); +fprintf(stdout, "-L [table] [-z]\t\tList conntrack or expectation table\n"); +fprintf(stdout, "-G [table] parameters\tGet conntrack or expectation\n"); +fprintf(stdout, "-D [table] parameters\tDelete conntrack or expectation\n"); +fprintf(stdout, "-I [table] parameters\tCreate a conntrack or expectation\n"); +fprintf(stdout, "-U [table] parameters\tUpdate a conntrack\n"); +fprintf(stdout, "-E [table] [options]\tShow events\n"); +fprintf(stdout, "-F [table]\t\tFlush table\n"); fprintf(stdout, "\n"); fprintf(stdout, "Options:\n"); fprintf(stdout, "--orig-src ip Source address from original direction\n"); @@ -1006,6 +1006,9 @@ int main(int argc, char *argv[]) break; case CT_DELETE: + if (!(options & CT_OPT_ORIG) && !(options & CT_OPT_REPL)) + exit_error(PARAMETER_PROBLEM, "Can't kill conntracks " + "just by its ID"); cth = nfct_open(CONNTRACK, 0); if (!cth) exit_error(OTHER_PROBLEM, "Can't open handler"); @@ -1083,7 +1086,7 @@ int main(int argc, char *argv[]) nfct_default_conntrack_display); res = nfct_event_conntrack(cth); } else { - cth = nfct_open(CONNTRACK, NFCT_ALL_GROUPS); + cth = nfct_open(CONNTRACK, NFCT_ALL_CT_GROUPS); if (!cth) exit_error(OTHER_PROBLEM, "Can't open handler"); signal(SIGINT, event_sighandler); @@ -1094,21 +1097,12 @@ int main(int argc, char *argv[]) break; case EXP_EVENT: - if (options & CT_OPT_EVENT_MASK) { - cth = nfct_open(EXPECT, event_mask); - if (!cth) - exit_error(OTHER_PROBLEM, "Can't open handler"); - signal(SIGINT, event_sighandler); - nfct_register_callback(cth, nfct_default_expect_display); - res = nfct_event_expectation(cth); - } else { - cth = nfct_open(EXPECT, NFCT_ALL_GROUPS); - if (!cth) - exit_error(OTHER_PROBLEM, "Can't open handler"); - signal(SIGINT, event_sighandler); - nfct_register_callback(cth, nfct_default_expect_display); - res = nfct_event_expectation(cth); - } + cth = nfct_open(EXPECT, NF_NETLINK_CONNTRACK_EXP_NEW); + if (!cth) + exit_error(OTHER_PROBLEM, "Can't open handler"); + signal(SIGINT, event_sighandler); + nfct_register_callback(cth, nfct_default_expect_display); + res = nfct_event_expectation(cth); nfct_close(cth); break; -- cgit v1.2.3 From c08c0ed43a565d192707dbc3ae6ffc895bb6b3f9 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: Tue, 1 Nov 2005 20:14:13 +0000 Subject: o Fix --id parameter parsing --- src/conntrack.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index fcd0ce4..0823de1 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -860,11 +860,19 @@ int main(int argc, char *argv[]) case 'm': mark = atol(optarg); break; - case 'i': + case 'i': { + char *s = NULL; options |= CT_OPT_ID; if (optarg) - id = atol(optarg); + break; + else if (optind < argc && argv[optind][0] != '-' + && argv[optind][0] != '!') + s = argv[optind++]; + + if (s) + id = atol(s); break; + } default: if (h && h->parse_opts &&!h->parse_opts(c - h->option_offset, argv, &orig, -- cgit v1.2.3 From 1c54be2dc910783f897034dbe16fe83b6901c2f2 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: Thu, 3 Nov 2005 12:37:50 +0000 Subject: See ChangeLog --- ChangeLog | 6 ++++++ src/Makefile.am | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 7d2c085..7ce1169 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2005-11-03 + + o moves conntrack tool from bin to sbin directory since this + application is an administration utility and it requires uid==0 or + CAP_NET_ADMIN + 2005-11-01 o Fix error message describing illegal option -E -i diff --git a/src/Makefile.am b/src/Makefile.am index 71ad3d5..0116de2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,4 +1,4 @@ -bin_PROGRAMS = conntrack +sbin_PROGRAMS = conntrack conntrack_SOURCES = conntrack.c INCLUDES= $(all_includes) -I$(top_srcdir)/include -I${KERNELDIR} -- cgit v1.2.3 From a13351816d27350930e35ac6284fa4498f80d5e7 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: Thu, 3 Nov 2005 20:47:17 +0000 Subject: See ChangeLog --- ChangeLog | 7 +++ extensions/libct_proto_icmp.c | 1 + extensions/libct_proto_sctp.c | 8 +-- extensions/libct_proto_tcp.c | 8 +-- extensions/libct_proto_udp.c | 1 + include/conntrack.h | 119 +++++++++++++++++++++++++++++++++++++----- src/conntrack.c | 111 +-------------------------------------- 7 files changed, 128 insertions(+), 127 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 51bdeb5..85a3565 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,6 +5,13 @@ CAP_NET_ADMIN o check if --state missing when -p is passed + o command type is passed to final_check: checkings based on the + command can be done now. + o kill duplicated definition of IPS_* bits: Already present in + libnetfilter_conntrack. + o Move action and command enum to conntrack.h + o kill NIPQUAD macro + o make conntrack handler cth static. o Bumped version to 0.96 2005-11-01 diff --git a/extensions/libct_proto_icmp.c b/extensions/libct_proto_icmp.c index d9c5cb3..6fe1e16 100644 --- a/extensions/libct_proto_icmp.c +++ b/extensions/libct_proto_icmp.c @@ -87,6 +87,7 @@ int parse(char c, char *argv[], } int final_check(unsigned int flags, + unsigned int command, struct nfct_tuple *orig, struct nfct_tuple *reply) { diff --git a/extensions/libct_proto_sctp.c b/extensions/libct_proto_sctp.c index 5e96391..6c85f56 100644 --- a/extensions/libct_proto_sctp.c +++ b/extensions/libct_proto_sctp.c @@ -116,6 +116,7 @@ int parse_options(char c, char *argv[], } int final_check(unsigned int flags, + unsigned int command, struct nfct_tuple *orig, struct nfct_tuple *reply) { @@ -136,10 +137,11 @@ int final_check(unsigned int flags, && ((flags & (REPL_SPORT|REPL_DPORT)))) ret = 1; - if (ret & (flags & STATE)) - return 1; + /* --state is missing and we are trying to create a conntrack */ + if (ret && (command & CT_CREATE) && (!(flags & STATE))) + ret = 0; - return 0; + return ret; } static struct ctproto_handler sctp = { diff --git a/extensions/libct_proto_tcp.c b/extensions/libct_proto_tcp.c index 7c1e605..36ef6fc 100644 --- a/extensions/libct_proto_tcp.c +++ b/extensions/libct_proto_tcp.c @@ -139,6 +139,7 @@ int parse_options(char c, char *argv[], } int final_check(unsigned int flags, + unsigned int command, struct nfct_tuple *orig, struct nfct_tuple *reply) { @@ -159,10 +160,11 @@ int final_check(unsigned int flags, && ((flags & (REPL_SPORT|REPL_DPORT)))) ret = 1; - if (ret && (flags & STATE)) - return 1; + /* --state is missing and we are trying to create a conntrack */ + if (ret && (command & CT_CREATE) && (!(flags & STATE))) + ret = 0; - return 0; + return ret; } static struct ctproto_handler tcp = { diff --git a/extensions/libct_proto_udp.c b/extensions/libct_proto_udp.c index b33ba7d..2c812c6 100644 --- a/extensions/libct_proto_udp.c +++ b/extensions/libct_proto_udp.c @@ -103,6 +103,7 @@ int parse_options(char c, char *argv[], } int final_check(unsigned int flags, + unsigned int command, struct nfct_tuple *orig, struct nfct_tuple *reply) { diff --git a/include/conntrack.h b/include/conntrack.h index efe4417..3993f89 100644 --- a/include/conntrack.h +++ b/include/conntrack.h @@ -8,12 +8,112 @@ #define PROGNAME "conntrack" #define CONNTRACK_VERSION "0.96" -/* FIXME: These should be independent from kernel space */ -#define IPS_ASSURED (1 << 2) -#define IPS_SEEN_REPLY (1 << 1) -#define IPS_SRC_NAT_DONE (1 << 7) -#define IPS_DST_NAT_DONE (1 << 8) -#define IPS_CONFIRMED (1 << 3) +enum action { + CT_NONE = 0, + + CT_LIST_BIT = 0, + CT_LIST = (1 << CT_LIST_BIT), + + CT_CREATE_BIT = 1, + CT_CREATE = (1 << CT_CREATE_BIT), + + CT_UPDATE_BIT = 2, + CT_UPDATE = (1 << CT_UPDATE_BIT), + + CT_DELETE_BIT = 3, + CT_DELETE = (1 << CT_DELETE_BIT), + + CT_GET_BIT = 4, + CT_GET = (1 << CT_GET_BIT), + + CT_FLUSH_BIT = 5, + CT_FLUSH = (1 << CT_FLUSH_BIT), + + CT_EVENT_BIT = 6, + CT_EVENT = (1 << CT_EVENT_BIT), + + CT_VERSION_BIT = 7, + CT_VERSION = (1 << CT_VERSION_BIT), + + CT_HELP_BIT = 8, + CT_HELP = (1 << CT_HELP_BIT), + + EXP_LIST_BIT = 9, + EXP_LIST = (1 << EXP_LIST_BIT), + + EXP_CREATE_BIT = 10, + EXP_CREATE = (1 << EXP_CREATE_BIT), + + EXP_DELETE_BIT = 11, + EXP_DELETE = (1 << EXP_DELETE_BIT), + + EXP_GET_BIT = 12, + EXP_GET = (1 << EXP_GET_BIT), + + EXP_FLUSH_BIT = 13, + EXP_FLUSH = (1 << EXP_FLUSH_BIT), + + EXP_EVENT_BIT = 14, + EXP_EVENT = (1 << EXP_EVENT_BIT), +}; +#define NUMBER_OF_CMD 15 + +enum options { + CT_OPT_ORIG_SRC_BIT = 0, + CT_OPT_ORIG_SRC = (1 << CT_OPT_ORIG_SRC_BIT), + + CT_OPT_ORIG_DST_BIT = 1, + CT_OPT_ORIG_DST = (1 << CT_OPT_ORIG_DST_BIT), + + CT_OPT_ORIG = (CT_OPT_ORIG_SRC | CT_OPT_ORIG_DST), + + CT_OPT_REPL_SRC_BIT = 2, + CT_OPT_REPL_SRC = (1 << CT_OPT_REPL_SRC_BIT), + + CT_OPT_REPL_DST_BIT = 3, + CT_OPT_REPL_DST = (1 << CT_OPT_REPL_DST_BIT), + + CT_OPT_REPL = (CT_OPT_REPL_SRC | CT_OPT_REPL_DST), + + CT_OPT_PROTO_BIT = 4, + CT_OPT_PROTO = (1 << CT_OPT_PROTO_BIT), + + CT_OPT_TIMEOUT_BIT = 5, + CT_OPT_TIMEOUT = (1 << CT_OPT_TIMEOUT_BIT), + + CT_OPT_STATUS_BIT = 6, + CT_OPT_STATUS = (1 << CT_OPT_STATUS_BIT), + + CT_OPT_ZERO_BIT = 7, + CT_OPT_ZERO = (1 << CT_OPT_ZERO_BIT), + + CT_OPT_EVENT_MASK_BIT = 8, + CT_OPT_EVENT_MASK = (1 << CT_OPT_EVENT_MASK_BIT), + + CT_OPT_EXP_SRC_BIT = 9, + CT_OPT_EXP_SRC = (1 << CT_OPT_EXP_SRC_BIT), + + CT_OPT_EXP_DST_BIT = 10, + CT_OPT_EXP_DST = (1 << CT_OPT_EXP_DST_BIT), + + CT_OPT_MASK_SRC_BIT = 11, + CT_OPT_MASK_SRC = (1 << CT_OPT_MASK_SRC_BIT), + + CT_OPT_MASK_DST_BIT = 12, + CT_OPT_MASK_DST = (1 << CT_OPT_MASK_DST_BIT), + + CT_OPT_NATRANGE_BIT = 13, + CT_OPT_NATRANGE = (1 << CT_OPT_NATRANGE_BIT), + + CT_OPT_MARK_BIT = 14, + CT_OPT_MARK = (1 << CT_OPT_MARK_BIT), + + CT_OPT_ID_BIT = 15, + CT_OPT_ID = (1 << CT_OPT_ID_BIT), + + CT_OPT_MAX = CT_OPT_ID +}; +#define NUMBER_OF_OPT CT_OPT_MAX struct ctproto_handler { struct list_head head; @@ -32,6 +132,7 @@ struct ctproto_handler { unsigned int *flags); int (*final_check)(unsigned int flags, + unsigned int command, struct nfct_tuple *orig, struct nfct_tuple *reply); @@ -44,10 +145,4 @@ struct ctproto_handler { extern void register_proto(struct ctproto_handler *h); -#define NIPQUAD(addr) \ - ((unsigned char *)&addr)[0], \ - ((unsigned char *)&addr)[1], \ - ((unsigned char *)&addr)[2], \ - ((unsigned char *)&addr)[3] - #endif diff --git a/src/conntrack.c b/src/conntrack.c index 0823de1..1c8a849 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -52,119 +52,12 @@ #define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe" #endif -enum action { - CT_NONE = 0, - - CT_LIST_BIT = 0, - CT_LIST = (1 << CT_LIST_BIT), - - CT_CREATE_BIT = 1, - CT_CREATE = (1 << CT_CREATE_BIT), - - CT_UPDATE_BIT = 2, - CT_UPDATE = (1 << CT_UPDATE_BIT), - - CT_DELETE_BIT = 3, - CT_DELETE = (1 << CT_DELETE_BIT), - - CT_GET_BIT = 4, - CT_GET = (1 << CT_GET_BIT), - - CT_FLUSH_BIT = 5, - CT_FLUSH = (1 << CT_FLUSH_BIT), - - CT_EVENT_BIT = 6, - CT_EVENT = (1 << CT_EVENT_BIT), - - CT_VERSION_BIT = 7, - CT_VERSION = (1 << CT_VERSION_BIT), - - CT_HELP_BIT = 8, - CT_HELP = (1 << CT_HELP_BIT), - - EXP_LIST_BIT = 9, - EXP_LIST = (1 << EXP_LIST_BIT), - - EXP_CREATE_BIT = 10, - EXP_CREATE = (1 << EXP_CREATE_BIT), - - EXP_DELETE_BIT = 11, - EXP_DELETE = (1 << EXP_DELETE_BIT), - - EXP_GET_BIT = 12, - EXP_GET = (1 << EXP_GET_BIT), - - EXP_FLUSH_BIT = 13, - EXP_FLUSH = (1 << EXP_FLUSH_BIT), - - EXP_EVENT_BIT = 14, - EXP_EVENT = (1 << EXP_EVENT_BIT), -}; -#define NUMBER_OF_CMD 15 - static const char cmdflags[NUMBER_OF_CMD] = {'L','I','U','D','G','F','E','V','h','L','I','D','G','F','E'}; static const char cmd_need_param[NUMBER_OF_CMD] = {' ','x','x','x','x',' ',' ',' ',' ',' ','x','x','x',' ',' '}; -enum options { - CT_OPT_ORIG_SRC_BIT = 0, - CT_OPT_ORIG_SRC = (1 << CT_OPT_ORIG_SRC_BIT), - - CT_OPT_ORIG_DST_BIT = 1, - CT_OPT_ORIG_DST = (1 << CT_OPT_ORIG_DST_BIT), - - CT_OPT_ORIG = (CT_OPT_ORIG_SRC | CT_OPT_ORIG_DST), - - CT_OPT_REPL_SRC_BIT = 2, - CT_OPT_REPL_SRC = (1 << CT_OPT_REPL_SRC_BIT), - - CT_OPT_REPL_DST_BIT = 3, - CT_OPT_REPL_DST = (1 << CT_OPT_REPL_DST_BIT), - - CT_OPT_REPL = (CT_OPT_REPL_SRC | CT_OPT_REPL_DST), - - CT_OPT_PROTO_BIT = 4, - CT_OPT_PROTO = (1 << CT_OPT_PROTO_BIT), - - CT_OPT_TIMEOUT_BIT = 5, - CT_OPT_TIMEOUT = (1 << CT_OPT_TIMEOUT_BIT), - - CT_OPT_STATUS_BIT = 6, - CT_OPT_STATUS = (1 << CT_OPT_STATUS_BIT), - - CT_OPT_ZERO_BIT = 7, - CT_OPT_ZERO = (1 << CT_OPT_ZERO_BIT), - - CT_OPT_EVENT_MASK_BIT = 8, - CT_OPT_EVENT_MASK = (1 << CT_OPT_EVENT_MASK_BIT), - - CT_OPT_EXP_SRC_BIT = 9, - CT_OPT_EXP_SRC = (1 << CT_OPT_EXP_SRC_BIT), - - CT_OPT_EXP_DST_BIT = 10, - CT_OPT_EXP_DST = (1 << CT_OPT_EXP_DST_BIT), - - CT_OPT_MASK_SRC_BIT = 11, - CT_OPT_MASK_SRC = (1 << CT_OPT_MASK_SRC_BIT), - - CT_OPT_MASK_DST_BIT = 12, - CT_OPT_MASK_DST = (1 << CT_OPT_MASK_DST_BIT), - - CT_OPT_NATRANGE_BIT = 13, - CT_OPT_NATRANGE = (1 << CT_OPT_NATRANGE_BIT), - - CT_OPT_MARK_BIT = 14, - CT_OPT_MARK = (1 << CT_OPT_MARK_BIT), - - CT_OPT_ID_BIT = 15, - CT_OPT_ID = (1 << CT_OPT_ID_BIT), - - CT_OPT_MAX = CT_OPT_ID -}; -#define NUMBER_OF_OPT CT_OPT_MAX - static const char optflags[NUMBER_OF_OPT] = {'s','d','r','q','p','t','u','z','e','[',']','{','}','a','m','i'}; @@ -199,7 +92,7 @@ static struct option original_opts[] = { #define OPTION_OFFSET 256 -struct nfct_handle *cth; +static struct nfct_handle *cth; static struct option *opts = original_opts; static unsigned int global_option_offset = 0; @@ -895,7 +788,7 @@ int main(int argc, char *argv[]) if (!(command & CT_HELP) && h && h->final_check - && !h->final_check(extra_flags, &orig, &reply)) { + && !h->final_check(extra_flags, command, &orig, &reply)) { usage(argv[0]); extension_help(h); exit_error(PARAMETER_PROBLEM, "Missing protocol arguments!\n"); -- cgit v1.2.3 From 1faf3aa3876aa2d54df7fa160f4986891ac07f6e Mon Sep 17 00:00:00 2001 From: "/C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=laforge/emailAddress=laforge@netfilter.org" Date: Fri, 4 Nov 2005 14:35:18 +0000 Subject: add extra argument to nfct_register_callback() to accomodate change in libnetfilter_conntrack --- src/conntrack.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index 1c8a849..2799c83 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -803,10 +803,12 @@ int main(int argc, char *argv[]) if (options & CT_OPT_ID) nfct_register_callback(cth, - nfct_default_conntrack_display_id); + nfct_default_conntrack_display_id, + NULL); else nfct_register_callback(cth, - nfct_default_conntrack_display); + nfct_default_conntrack_display, + NULL); if (options & CT_OPT_ZERO) res = nfct_dump_conntrack_table_reset_counters(cth); @@ -821,10 +823,12 @@ int main(int argc, char *argv[]) exit_error(OTHER_PROBLEM, "Can't open handler"); if (options & CT_OPT_ID) nfct_register_callback(cth, - nfct_default_expect_display_id); + nfct_default_expect_display_id, + NULL); else nfct_register_callback(cth, - nfct_default_expect_display); + nfct_default_expect_display, + NULL); res = nfct_dump_expect_list(cth); nfct_close(cth); break; @@ -939,7 +943,8 @@ int main(int argc, char *argv[]) cth = nfct_open(CONNTRACK, 0); if (!cth) exit_error(OTHER_PROBLEM, "Can't open handler"); - nfct_register_callback(cth, nfct_default_conntrack_display); + nfct_register_callback(cth, nfct_default_conntrack_display, + NULL); if (options & CT_OPT_ORIG) res = nfct_get_conntrack(cth, &orig, NFCT_DIR_ORIGINAL, id); @@ -953,7 +958,8 @@ int main(int argc, char *argv[]) cth = nfct_open(EXPECT, 0); if (!cth) exit_error(OTHER_PROBLEM, "Can't open handler"); - nfct_register_callback(cth, nfct_default_expect_display); + nfct_register_callback(cth, nfct_default_expect_display, + NULL); if (options & CT_OPT_ORIG) res = nfct_get_expectation(cth, &orig, id); else if (options & CT_OPT_REPL) @@ -984,14 +990,16 @@ int main(int argc, char *argv[]) exit_error(OTHER_PROBLEM, "Can't open handler"); signal(SIGINT, event_sighandler); nfct_register_callback(cth, - nfct_default_conntrack_display); + nfct_default_conntrack_display, NULL); res = nfct_event_conntrack(cth); } else { cth = nfct_open(CONNTRACK, NFCT_ALL_CT_GROUPS); if (!cth) exit_error(OTHER_PROBLEM, "Can't open handler"); signal(SIGINT, event_sighandler); - nfct_register_callback(cth, nfct_default_conntrack_display); + nfct_register_callback(cth, + nfct_default_conntrack_display, + NULL); res = nfct_event_conntrack(cth); } nfct_close(cth); @@ -1002,7 +1010,8 @@ int main(int argc, char *argv[]) if (!cth) exit_error(OTHER_PROBLEM, "Can't open handler"); signal(SIGINT, event_sighandler); - nfct_register_callback(cth, nfct_default_expect_display); + nfct_register_callback(cth, nfct_default_expect_display, + NULL); res = nfct_event_expectation(cth); nfct_close(cth); break; -- cgit v1.2.3 From 67832c77b05afc8d0f59244854181b13efdbefeb 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, 6 Nov 2005 03:09:43 +0000 Subject: See ChangeLog --- ChangeLog | 11 +++++- configure.in | 4 +- extensions/libct_proto_icmp.c | 4 +- extensions/libct_proto_sctp.c | 2 +- extensions/libct_proto_tcp.c | 2 +- extensions/libct_proto_udp.c | 2 +- include/conntrack.h | 1 - src/conntrack.c | 86 +++++++++++++++++++++++++++---------------- 8 files changed, 70 insertions(+), 42 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index ecde2eb..789060e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,9 +1,16 @@ +2005-11-05 + + o -t and -u are optional at update. + o Improved conntrack -h output + o add htons for icmp id. + + o Fixed versioning :( + o Bumped version to 0.97 + 2005-11-03 o Use extra 'data' argument of nfct_register_callback() function that I've introduced in libetfilter_conntrack. - -2005-11-03 o moves conntrack tool from bin to sbin directory since this application is an administration utility and it requires uid==0 or diff --git a/configure.in b/configure.in index 0f0fc5f..4f96878 100644 --- a/configure.in +++ b/configure.in @@ -2,8 +2,8 @@ AC_INIT AC_CANONICAL_SYSTEM -AM_INIT_AUTOMAKE(conntrack, 0.63) -AM_CONFIG_HEADER(config.h) +AM_INIT_AUTOMAKE(conntrack, 0.97) +#AM_CONFIG_HEADER(config.h) AC_PROG_CC AM_PROG_LIBTOOL diff --git a/extensions/libct_proto_icmp.c b/extensions/libct_proto_icmp.c index 6fe1e16..dc7374e 100644 --- a/extensions/libct_proto_icmp.c +++ b/extensions/libct_proto_icmp.c @@ -77,7 +77,7 @@ int parse(char c, char *argv[], break; case '3': if (optarg) { - orig->l4src.icmp.id = atoi(optarg); + orig->l4src.icmp.id = htons(atoi(optarg)); reply->l4dst.icmp.id = 0; *flags |= ICMP_ID; } @@ -106,7 +106,7 @@ static struct ctproto_handler icmp = { .final_check = final_check, .help = help, .opts = opts, - .version = CONNTRACK_VERSION, + .version = VERSION, }; void __attribute__ ((constructor)) init(void); diff --git a/extensions/libct_proto_sctp.c b/extensions/libct_proto_sctp.c index 6c85f56..64cfd23 100644 --- a/extensions/libct_proto_sctp.c +++ b/extensions/libct_proto_sctp.c @@ -151,7 +151,7 @@ static struct ctproto_handler sctp = { .final_check = final_check, .help = help, .opts = opts, - .version = CONNTRACK_VERSION, + .version = VERSION, }; void __attribute__ ((constructor)) init(void); diff --git a/extensions/libct_proto_tcp.c b/extensions/libct_proto_tcp.c index 36ef6fc..3a01c0a 100644 --- a/extensions/libct_proto_tcp.c +++ b/extensions/libct_proto_tcp.c @@ -174,7 +174,7 @@ static struct ctproto_handler tcp = { .final_check = final_check, .help = help, .opts = opts, - .version = CONNTRACK_VERSION, + .version = VERSION, }; void __attribute__ ((constructor)) init(void); diff --git a/extensions/libct_proto_udp.c b/extensions/libct_proto_udp.c index 2c812c6..958d464 100644 --- a/extensions/libct_proto_udp.c +++ b/extensions/libct_proto_udp.c @@ -132,7 +132,7 @@ static struct ctproto_handler udp = { .final_check = final_check, .help = help, .opts = opts, - .version = CONNTRACK_VERSION, + .version = VERSION, }; void __attribute__ ((constructor)) init(void); diff --git a/include/conntrack.h b/include/conntrack.h index 3993f89..fd51880 100644 --- a/include/conntrack.h +++ b/include/conntrack.h @@ -6,7 +6,6 @@ #include #define PROGNAME "conntrack" -#define CONNTRACK_VERSION "0.96" enum action { CT_NONE = 0, diff --git a/src/conntrack.c b/src/conntrack.c index 2799c83..fe4095d 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -113,7 +113,7 @@ static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = /* -s -d -r -q -p -t -u -z -e -x -y -k -l -a -m -i*/ /*CT_LIST*/ {'x','x','x','x','x','x','x',' ','x','x','x','x','x','x','x',' '}, /*CT_CREATE*/ {' ',' ',' ',' ','+','+','+','x','x','x','x','x','x',' ',' ','x'}, -/*CT_UPDATE*/ {' ',' ',' ',' ','+','+','+','x','x','x','x','x','x','x',' ',' '}, +/*CT_UPDATE*/ {' ',' ',' ',' ','+',' ',' ','x','x','x','x','x','x','x',' ',' '}, /*CT_DELETE*/ {' ',' ',' ',' ',' ','x','x','x','x','x','x','x','x','x','x',' '}, /*CT_GET*/ {' ',' ',' ',' ','+','x','x','x','x','x','x','x','x','x','x',' '}, /*CT_FLUSH*/ {'x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x'}, @@ -134,9 +134,9 @@ static LIST_HEAD(proto_list); void register_proto(struct ctproto_handler *h) { - if (strcmp(h->version, CONNTRACK_VERSION) != 0) { + if (strcmp(h->version, VERSION) != 0) { fprintf(stderr, "plugin `%s': version %s (I'm %s)\n", - h->name, h->version, CONNTRACK_VERSION); + h->name, h->version, VERSION); exit(1); } list_add(&h->head, &proto_list); @@ -209,7 +209,7 @@ exit_error(enum exittype status, char *msg, ...) global_option_offset = 0; } va_start(args, msg); - fprintf(stderr,"%s v%s: ", PROGNAME, CONNTRACK_VERSION); + fprintf(stderr,"%s v%s: ", PROGNAME, VERSION); vfprintf(stderr, msg, args); va_end(args); fprintf(stderr, "\n"); @@ -558,34 +558,56 @@ static void event_sighandler(int s) exit(0); } +static const char usage_commands[] = + "Commands:\n" + " -L [table] [options]\t\tList conntrack or expectation table\n" + " -G [table] parameters\t\tGet conntrack or expectation\n" + " -D [table] parameters\t\tDelete conntrack or expectation\n" + " -I [table] parameters\t\tCreate a conntrack or expectation\n" + " -U [table] parameters\t\tUpdate a conntrack\n" + " -E [table] [options]\t\tShow events\n" + " -F [table]\t\t\tFlush table\n"; + +static const char usage_tables[] = + "Tables: conntrack, expect\n"; + +static const char usage_conntrack_parameters[] = + "Conntrack parameters and options:\n" + " -a, --nat-range min_ip[-max_ip]\tNAT ip range\n" + " -m, --mark mark\t\t\tSet mark\n" + " -e, --event-mask eventmask\t\tEvent mask, eg. NEW,DESTROY\n" + " -z, --zero \t\t\t\tZero counters while listing\n" + ; + +static const char usage_expectation_parameters[] = + "Expectation parameters and options:\n" + " --tuple-src ip\tSource address in expect tuple\n" + " --tuple-dst ip\tDestination address in expect tuple\n" + " --mask-src ip\t\tSource mask address\n" + " --mask-dst ip\t\tDestination mask address\n"; + +static const char usage_parameters[] = + "Common parameters and options:\n" + " -s, --orig-src ip\t\tSource address from original direction\n" + " -d, --orig-dst ip\t\tDestination address from original direction\n" + " -r, --reply-src ip\t\tSource addres from reply direction\n" + " -q, --reply-dst ip\t\tDestination address from reply direction\n" + " -p, --protonum proto\t\tLayer 4 Protocol, eg. 'tcp'\n" + " -t, --timeout timeout\t\tSet timeout\n" + " -u, --status status\t\tSet status, eg. ASSURED\n" + " -i, --id [id]\t\t\tShow or set conntrack ID\n" + ; + + void usage(char *prog) { -fprintf(stdout, "Tool to manipulate conntrack and expectations. Version %s\n", CONNTRACK_VERSION); -fprintf(stdout, "Usage: %s [commands] [options]\n", prog); -fprintf(stdout, "\n"); -fprintf(stdout, "Commands:\n"); -fprintf(stdout, "-L [table] [-z]\t\tList conntrack or expectation table\n"); -fprintf(stdout, "-G [table] parameters\tGet conntrack or expectation\n"); -fprintf(stdout, "-D [table] parameters\tDelete conntrack or expectation\n"); -fprintf(stdout, "-I [table] parameters\tCreate a conntrack or expectation\n"); -fprintf(stdout, "-U [table] parameters\tUpdate a conntrack\n"); -fprintf(stdout, "-E [table] [options]\tShow events\n"); -fprintf(stdout, "-F [table]\t\tFlush table\n"); -fprintf(stdout, "\n"); -fprintf(stdout, "Options:\n"); -fprintf(stdout, "--orig-src ip Source address from original direction\n"); -fprintf(stdout, "--orig-dst ip Destination address from original direction\n"); -fprintf(stdout, "--reply-src ip Source addres from reply direction\n"); -fprintf(stdout, "--reply-dst ip Destination address from reply direction\n"); -fprintf(stdout, "--tuple-src ip Source address in expect tuple\n"); -fprintf(stdout, "--tuple-dst ip Destination address in expect tuple\n"); -fprintf(stdout, "--mask-src ip Source mask address for expectation\n"); -fprintf(stdout, "--mask-dst ip Destination mask address for expectations\n"); -fprintf(stdout, "-p proto Layer 4 Protocol\n"); -fprintf(stdout, "-t timeout Set timeout\n"); -fprintf(stdout, "-u status Set status\n"); -fprintf(stdout, "-e eventmask Set event mask\n"); -fprintf(stdout, "-a min_ip[-max_ip] NAT ip range\n"); -fprintf(stdout, "-z Zero Counters\n"); + fprintf(stdout, "Tool to manipulate conntrack and expectations. Version %s\n", VERSION); + fprintf(stdout, "Usage: %s [commands] [options]\n", prog); + + fprintf(stdout, "\n%s", usage_commands); + fprintf(stdout, "\n%s", usage_tables); + fprintf(stdout, "\n%s", usage_conntrack_parameters); + fprintf(stdout, "\n%s", usage_expectation_parameters); + fprintf(stdout, "\n%s", usage_parameters); } int main(int argc, char *argv[]) @@ -1017,7 +1039,7 @@ int main(int argc, char *argv[]) break; case CT_VERSION: - fprintf(stdout, "%s v%s\n", PROGNAME, CONNTRACK_VERSION); + fprintf(stdout, "%s v%s\n", PROGNAME, VERSION); break; case CT_HELP: usage(argv[0]); -- cgit v1.2.3 From fa30b0bb403466c319c9f3c77a0ec8e9dae0d323 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: Tue, 8 Nov 2005 02:05:44 +0000 Subject: See ChangeLog --- ChangeLog | 8 +++++++- src/conntrack.c | 50 +++++++++++++++++++++++++++++++------------------- 2 files changed, 38 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 789060e..3df5019 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,9 +1,15 @@ +2005-11-08 + + o Fix warnings generated by gcc -Wall + o Fix conntrack exit value at error + o Replace obsolete inet_addr by inet_aton + 2005-11-05 - o -t and -u are optional at update. o Improved conntrack -h output o add htons for icmp id. + o -t and -u are optional at update. o Fixed versioning :( o Bumped version to 0.97 diff --git a/src/conntrack.c b/src/conntrack.c index fe4095d..e6ac96a 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -38,9 +38,12 @@ #include #include #include +#include #include #include #include +#include +#include #include #include #include @@ -477,6 +480,18 @@ int iptables_insmod(const char *modname, const char *modprobe) return -1; } +in_addr_t parse_inetaddr(const char *cp) +{ + struct in_addr addr; + + if (inet_aton(cp, &addr)) { + return addr.s_addr; + } + + exit_error(PARAMETER_PROBLEM, "Invalid IP address `%s'.", cp); + +} + /* Shamelessly stolen from libipt_DNAT ;). Ranges expected in network order. */ static void nat_parse(char *arg, int portok, struct nfct_nat *range) @@ -536,16 +551,10 @@ nat_parse(char *arg, int portok, struct nfct_nat *range) if (dash) *dash = '\0'; - ip = inet_addr(arg); - if (!ip) - exit_error(PARAMETER_PROBLEM, "Bad IP address `%s'\n", - arg); + ip = parse_inetaddr(arg); range->min_ip = ip; if (dash) { - ip = inet_addr(dash+1); - if (!ip) - exit_error(PARAMETER_PROBLEM, "Bad IP address `%s'\n", - dash+1); + ip = parse_inetaddr(dash+1); range->max_ip = ip; } else range->max_ip = range->min_ip; @@ -614,7 +623,7 @@ int main(int argc, char *argv[]) { char c; unsigned int command = 0, options = 0; - struct nfct_tuple orig, reply, mask, *o = NULL, *r = NULL; + struct nfct_tuple orig, reply, mask; struct nfct_tuple exptuple; struct ctproto_handler *h = NULL; union nfct_protoinfo proto; @@ -626,7 +635,6 @@ int main(int argc, char *argv[]) unsigned int mark = 0; unsigned int id = NFCT_ANY_ID; unsigned int type = 0, extra_flags = 0, event_mask = 0; - int manip = -1; int res = 0; memset(&proto, 0, sizeof(union nfct_protoinfo)); @@ -699,22 +707,22 @@ int main(int argc, char *argv[]) case 's': options |= CT_OPT_ORIG_SRC; if (optarg) - orig.src.v4 = inet_addr(optarg); + orig.src.v4 = parse_inetaddr(optarg); break; case 'd': options |= CT_OPT_ORIG_DST; if (optarg) - orig.dst.v4 = inet_addr(optarg); + orig.dst.v4 = parse_inetaddr(optarg); break; case 'r': options |= CT_OPT_REPL_SRC; if (optarg) - reply.src.v4 = inet_addr(optarg); + reply.src.v4 = parse_inetaddr(optarg); break; case 'q': options |= CT_OPT_REPL_DST; if (optarg) - reply.dst.v4 = inet_addr(optarg); + reply.dst.v4 = parse_inetaddr(optarg); break; case 'p': options |= CT_OPT_PROTO; @@ -751,22 +759,22 @@ int main(int argc, char *argv[]) case '{': options |= CT_OPT_MASK_SRC; if (optarg) - mask.src.v4 = inet_addr(optarg); + mask.src.v4 = parse_inetaddr(optarg); break; case '}': options |= CT_OPT_MASK_DST; if (optarg) - mask.dst.v4 = inet_addr(optarg); + mask.dst.v4 = parse_inetaddr(optarg); break; case '[': options |= CT_OPT_EXP_SRC; if (optarg) - exptuple.src.v4 = inet_addr(optarg); + exptuple.src.v4 = parse_inetaddr(optarg); break; case ']': options |= CT_OPT_EXP_DST; if (optarg) - exptuple.dst.v4 = inet_addr(optarg); + exptuple.dst.v4 = parse_inetaddr(optarg); break; case 'a': options |= CT_OPT_NATRANGE; @@ -1057,6 +1065,10 @@ int main(int argc, char *argv[]) global_option_offset = 0; } - if (res < 0) + if (res < 0) { fprintf(stderr, "Operation failed: %s\n", err2str(res, command)); + exit(OTHER_PROBLEM); + } + + return 0; } -- cgit v1.2.3 From 95393d12b5b330ccd4e6d6a3391cc1d28208ebdf 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: Wed, 9 Nov 2005 20:21:27 +0000 Subject: See ChangeLog --- ChangeLog | 6 ++++++ configure.in | 2 +- src/conntrack.c | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 3df5019..02434f6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2005-11-09 + + o set status to zero, libnetfilter_conntrack now activate + IPS_CONFIRMED since all conntrack in hash must be confirmed. + o Bumped version to 0.98 + 2005-11-08 o Fix warnings generated by gcc -Wall diff --git a/configure.in b/configure.in index 4f96878..088a5f8 100644 --- a/configure.in +++ b/configure.in @@ -2,7 +2,7 @@ AC_INIT AC_CANONICAL_SYSTEM -AM_INIT_AUTOMAKE(conntrack, 0.97) +AM_INIT_AUTOMAKE(conntrack, 0.98) #AM_CONFIG_HEADER(config.h) AC_PROG_CC diff --git a/src/conntrack.c b/src/conntrack.c index e6ac96a..e2fcc16 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -631,7 +631,7 @@ int main(int argc, char *argv[]) struct nfct_conntrack *ct; struct nfct_expect *exp; unsigned long timeout = 0; - unsigned int status = IPS_CONFIRMED; + unsigned int status = 0; unsigned int mark = 0; unsigned int id = NFCT_ANY_ID; unsigned int type = 0, extra_flags = 0, event_mask = 0; -- cgit v1.2.3 From a44a84541c341187bff56f850c8e2cb43315fcb6 Mon Sep 17 00:00:00 2001 From: "/C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=laforge/emailAddress=laforge@netfilter.org" Date: Thu, 10 Nov 2005 17:35:53 +0000 Subject: - rename plugisn to remove 'lib' prefix - move them into 'pkglibdir' --- configure.in | 2 +- extensions/Makefile.am | 16 ++++++++++------ include/Makefile.am | 2 +- src/conntrack.c | 4 ++-- 4 files changed, 14 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/configure.in b/configure.in index 088a5f8..228f365 100644 --- a/configure.in +++ b/configure.in @@ -75,7 +75,7 @@ AC_ARG_WITH(kernel, NF_KERNEL_SOURCE($with_kernel),NF_KERNEL_SOURCE()) if test ! -z "$libdir"; then - MODULE_DIR="\\\"$libdir/\\\"" + MODULE_DIR="\\\"$libdir/conntrack/\\\"" CFLAGS="$CFLAGS -DCONNTRACK_LIB_DIR=$MODULE_DIR" fi diff --git a/extensions/Makefile.am b/extensions/Makefile.am index 1cae1df..5149336 100644 --- a/extensions/Makefile.am +++ b/extensions/Makefile.am @@ -4,10 +4,14 @@ INCLUDES=-I../include -I${KERNELDIR} CFLAGS=-fPIC -Wall LIBS= -lib_LTLIBRARIES = libct_proto_tcp.la libct_proto_udp.la libct_proto_icmp.la \ - libct_proto_sctp.la +pkglib_LTLIBRARIES = ct_proto_tcp.la ct_proto_udp.la \ + ct_proto_icmp.la ct_proto_sctp.la -libct_proto_tcp_la_SOURCES = libct_proto_tcp.c -libct_proto_udp_la_SOURCES = libct_proto_udp.c -libct_proto_icmp_la_SOURCES = libct_proto_icmp.c -libct_proto_sctp_la_SOURCES = libct_proto_sctp.c +ct_proto_tcp_la_SOURCES = libct_proto_tcp.c +ct_proto_tcp_la_LDFLAGS = -module +ct_proto_udp_la_SOURCES = libct_proto_udp.c +ct_proto_udp_la_LDFLAGS = -module +ct_proto_icmp_la_SOURCES = libct_proto_icmp.c +ct_proto_icmp_la_LDFLAGS = -module +ct_proto_sctp_la_SOURCES = libct_proto_sctp.c +ct_proto_sctp_la_LDFLAGS = -module diff --git a/include/Makefile.am b/include/Makefile.am index f91ed48..832da6d 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -1,2 +1,2 @@ -include_HEADERS = libct_proto.h linux_list.h +pkginclude_HEADERS = conntrack.h linux_list.h diff --git a/src/conntrack.c b/src/conntrack.c index e2fcc16..59b95a4 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -166,9 +166,9 @@ static struct ctproto_handler *findproto(char *name) } if (!handler) { - char path[sizeof("libct_proto_.so") + char path[sizeof("ct_proto_.so") + strlen(name) + strlen(lib_dir)]; - sprintf(path, "%s/libct_proto_%s.so", lib_dir, name); + sprintf(path, "%s/ct_proto_%s.so", lib_dir, name); if (dlopen(path, RTLD_NOW)) handler = findproto(name); else -- cgit v1.2.3 From 9ed5ff2dace70b5235682d336a90faaf28377e6e Mon Sep 17 00:00:00 2001 From: "/C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=laforge/emailAddress=laforge@netfilter.org" Date: Mon, 14 Nov 2005 16:37:04 +0000 Subject: - get rid of KERNELDIR - use Make_global.am --- Make_global.am | 1 + Makefile.am | 5 +++-- extensions/Makefile.am | 3 +-- src/Makefile.am | 5 ++--- 4 files changed, 7 insertions(+), 7 deletions(-) create mode 100644 Make_global.am (limited to 'src') diff --git a/Make_global.am b/Make_global.am new file mode 100644 index 0000000..685add7 --- /dev/null +++ b/Make_global.am @@ -0,0 +1 @@ +INCLUDES=$(all_includes) -I$(top_srcdir)/include diff --git a/Makefile.am b/Makefile.am index 46a9220..4962fb4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,12 +1,13 @@ +include Make_global.am + # not a GNU package. You can remove this line, if # have all needed files, that a GNU package needs AUTOMAKE_OPTIONS = foreign dist-bzip2 1.6 man_MANS = conntrack.8 -EXTRA_DIST = $(man_MANS) +EXTRA_DIST = $(man_MANS) Make_global.am -INCLUDES = $(all_includes) -I$(top_srcdir)/include -I${KERNELDIR} SUBDIRS = src extensions DIST_SUBDIRS = include src extensions LINKOPTS = -ldl -lnetfilter_conntrack diff --git a/extensions/Makefile.am b/extensions/Makefile.am index c1f9cb6..1eaf230 100644 --- a/extensions/Makefile.am +++ b/extensions/Makefile.am @@ -1,6 +1,5 @@ -# AUTOMAKE_OPTIONS = no-dependencies foreign +include $(top_srcdir)/Make_global.am -INCLUDES=-I../include -I${KERNELDIR} CFLAGS=-fPIC -Wall LIBS= diff --git a/src/Makefile.am b/src/Makefile.am index 0116de2..fb1410a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,8 +1,7 @@ +include $(top_srcdir)/Make_global.am + sbin_PROGRAMS = conntrack conntrack_SOURCES = conntrack.c -INCLUDES= $(all_includes) -I$(top_srcdir)/include -I${KERNELDIR} conntrack_LDFLAGS = $(all_libraries) -rdynamic -#AM_CFLAGS = -g -#LINKOPTS=-ldl -lnfnetlink -lctnetlink -rdynamic -- cgit v1.2.3 From eb3faafbf715be8489b30cd0b0109232969b4e9d Mon Sep 17 00:00:00 2001 From: "/C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=laforge/emailAddress=laforge@netfilter.org" Date: Mon, 14 Nov 2005 16:48:54 +0000 Subject: linke with libnetfilter_conntrack --- src/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index fb1410a..0dfd3b8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -3,5 +3,5 @@ include $(top_srcdir)/Make_global.am sbin_PROGRAMS = conntrack conntrack_SOURCES = conntrack.c -conntrack_LDFLAGS = $(all_libraries) -rdynamic +conntrack_LDFLAGS = $(all_libraries) -rdynamic -lnetfilter_conntrack -- cgit v1.2.3 From 5891b45e0eee0307a29ed5103fe6d596f6a37ebd 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: Sat, 3 Dec 2005 22:33:53 +0000 Subject: o Add support to filter events. ie: -p tcp --orig-port-dst 80 in conjuction with -E to get all the requests to HTTP servers o Update manpage o Missing static function declaration in the protocol handlers o Use protocol flags defined in libnetfilter_conntrack o Kill leftover #include "conntrack.h" in the ICMP helper o Bumped version to 0.991 --- ChangeLog | 11 ++++++ configure.in | 2 +- conntrack.8 | 14 +++----- extensions/libct_proto_icmp.c | 39 ++++++++-------------- extensions/libct_proto_sctp.c | 44 ++++++++---------------- extensions/libct_proto_tcp.c | 78 ++++++++++++++++--------------------------- extensions/libct_proto_udp.c | 71 +++++++++++++++------------------------ src/conntrack.c | 39 +++++++++++++--------- 8 files changed, 123 insertions(+), 175 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 7909f74..befb699 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2005-13-03 + + o Add support to filter events. ie: -p tcp --orig-port-dst 80 in + conjuction with -E to get all the requests to HTTP servers + o Update manpage + o Missing static function declaration in the protocol handlers + o Use protocol flags defined in libnetfilter_conntrack + o Kill leftover #include "conntrack.h" in the ICMP helper + o Bumped version to 0.991 + 2005-11-22 o Fix oversized number of options @@ -10,6 +20,7 @@ o move plugins into pkglibdir o remove 'lib' prefix of plugins, they're not really libraries o remove version information from plugin filenames + o Bumped version to 0.99 2005-11-09 o set status to zero, libnetfilter_conntrack now activate diff --git a/configure.in b/configure.in index a31646f..4dd09c6 100644 --- a/configure.in +++ b/configure.in @@ -2,7 +2,7 @@ AC_INIT AC_CANONICAL_SYSTEM -AM_INIT_AUTOMAKE(conntrack, 0.99) +AM_INIT_AUTOMAKE(conntrack, 0.991) #AM_CONFIG_HEADER(config.h) AC_PROG_CC diff --git a/conntrack.8 b/conntrack.8 index 8c9d963..8dbecb5 100644 --- a/conntrack.8 +++ b/conntrack.8 @@ -74,17 +74,11 @@ Flush the whole given table Atomically zero counters after reading them. This option is only valid in combination with the "-L, --dump" command options. .TP -.BI "-e, --event-mask " "[ALL|NEW|RELATED|DESTROY|REFRESH|STATUS|PROTOINFO|HELPER|HELPINFO|NATINFO][,...]" +.BI "-e, --event-mask " "[ALL|NEW|UPDATES|DESTROY][,...]" Set the bitmask of events that are to be generated by the in-kernel ctnetlink event code. Using this parameter, you can reduce the event messages generated by the kernel to those types to those that you are actually interested in. . -Please note that this is a system-wide setting, so make sure to not disable some events that other ctnetlink-using processes might need! -This option can only be used in conjunction with "-E, --event". -.TP -.BI "-g, --group-mask " "[ALL|TCP|UDP|ICMP][,...]" -Set the group bitmask to those netlink groups (resembling layer 4 protocols) -that you're actually interested in. This option can only be used in conjunction with "-E, --event". .SS FILTER PARAMETERS .TP @@ -106,11 +100,13 @@ Specify layer four (TCP, UDP, ...) protocol. .BI "-t, --timeout " "TIMEOUT" Specify the timeout. .TP -.BI "-u, --status " "[EXPECTED|ASSURED|SEEN_REPLY|CONFIRMED|SNAT|DNAT|SEQ_ADJUST|UNSET][,...]" +.BI "-u, --status " "[ASSURED|SEEN_REPLY|UNSET|SRC_NAT|DST_NAT][,...]" Specify the conntrack status. .TP .BI "-i, --id " "ID" -Specify the conntrack ID. +Specify the conntrack ID. +. +This option can only be used in conjunction with "-L, --dump" to display the conntrack IDs. .TP .BI "--tuple-src " IP_ADDRESS Specify the tuple source address of an expectation. diff --git a/extensions/libct_proto_icmp.c b/extensions/libct_proto_icmp.c index dc7374e..afae25e 100644 --- a/extensions/libct_proto_icmp.c +++ b/extensions/libct_proto_icmp.c @@ -14,7 +14,7 @@ #include /* For htons */ #include #include -#include "conntrack.h" +#include static struct option opts[] = { {"icmp-type", 1, 0, '1'}, @@ -23,18 +23,7 @@ static struct option opts[] = { {0, 0, 0, 0} }; -enum icmp_param_flags { - ICMP_TYPE_BIT = 0, - ICMP_TYPE = (1 << ICMP_TYPE_BIT), - - ICMP_CODE_BIT = 1, - ICMP_CODE = (1 << ICMP_CODE_BIT), - - ICMP_ID_BIT = 2, - ICMP_ID = (1 << ICMP_ID_BIT) -}; - -void help() +static void help() { fprintf(stdout, "--icmp-type icmp type\n"); fprintf(stdout, "--icmp-code icmp code\n"); @@ -52,12 +41,12 @@ static u_int8_t invmap[] [ICMP_ADDRESS] = ICMP_ADDRESSREPLY + 1, [ICMP_ADDRESSREPLY] = ICMP_ADDRESS + 1}; -int parse(char c, char *argv[], - struct nfct_tuple *orig, - struct nfct_tuple *reply, - struct nfct_tuple *mask, - union nfct_protoinfo *proto, - unsigned int *flags) +static int parse(char c, char *argv[], + struct nfct_tuple *orig, + struct nfct_tuple *reply, + struct nfct_tuple *mask, + union nfct_protoinfo *proto, + unsigned int *flags) { switch(c) { case '1': @@ -86,10 +75,10 @@ int parse(char c, char *argv[], return 1; } -int final_check(unsigned int flags, - unsigned int command, - struct nfct_tuple *orig, - struct nfct_tuple *reply) +static int final_check(unsigned int flags, + unsigned int command, + struct nfct_tuple *orig, + struct nfct_tuple *reply) { if (!(flags & ICMP_TYPE)) return 0; @@ -109,9 +98,9 @@ static struct ctproto_handler icmp = { .version = VERSION, }; -void __attribute__ ((constructor)) init(void); +static void __attribute__ ((constructor)) init(void); -void init(void) +static void init(void) { register_proto(&icmp); } diff --git a/extensions/libct_proto_sctp.c b/extensions/libct_proto_sctp.c index 64cfd23..7ff1dcf 100644 --- a/extensions/libct_proto_sctp.c +++ b/extensions/libct_proto_sctp.c @@ -14,6 +14,7 @@ #include /* For htons */ #include "conntrack.h" #include +#include static struct option opts[] = { {"orig-port-src", 1, 0, '1'}, @@ -24,23 +25,6 @@ static struct option opts[] = { {0, 0, 0, 0} }; -enum sctp_param_flags { - ORIG_SPORT_BIT = 0, - ORIG_SPORT = (1 << ORIG_SPORT_BIT), - - ORIG_DPORT_BIT = 1, - ORIG_DPORT = (1 << ORIG_DPORT_BIT), - - REPL_SPORT_BIT = 2, - REPL_SPORT = (1 << REPL_SPORT_BIT), - - REPL_DPORT_BIT = 3, - REPL_DPORT = (1 << REPL_DPORT_BIT), - - STATE_BIT = 4, - STATE = (1 << STATE_BIT) -}; - static const char *states[] = { "NONE", "CLOSED", @@ -52,7 +36,7 @@ static const char *states[] = { "SHUTDOWN_ACK_SENT", }; -void help() +static void help() { fprintf(stdout, "--orig-port-src original source port\n"); fprintf(stdout, "--orig-port-dst original destination port\n"); @@ -61,12 +45,12 @@ void help() fprintf(stdout, "--state SCTP state, fe. ESTABLISHED\n"); } -int parse_options(char c, char *argv[], - struct nfct_tuple *orig, - struct nfct_tuple *reply, - struct nfct_tuple *mask, - union nfct_protoinfo *proto, - unsigned int *flags) +static int parse_options(char c, char *argv[], + struct nfct_tuple *orig, + struct nfct_tuple *reply, + struct nfct_tuple *mask, + union nfct_protoinfo *proto, + unsigned int *flags) { switch(c) { case '1': @@ -115,10 +99,10 @@ int parse_options(char c, char *argv[], return 1; } -int final_check(unsigned int flags, - unsigned int command, - struct nfct_tuple *orig, - struct nfct_tuple *reply) +static int final_check(unsigned int flags, + unsigned int command, + struct nfct_tuple *orig, + struct nfct_tuple *reply) { int ret = 0; @@ -154,9 +138,9 @@ static struct ctproto_handler sctp = { .version = VERSION, }; -void __attribute__ ((constructor)) init(void); +static void __attribute__ ((constructor)) init(void); -void init(void) +static void init(void) { register_proto(&sctp); } diff --git a/extensions/libct_proto_tcp.c b/extensions/libct_proto_tcp.c index 3a01c0a..35fa292 100644 --- a/extensions/libct_proto_tcp.c +++ b/extensions/libct_proto_tcp.c @@ -13,6 +13,7 @@ #include #include /* For htons */ #include +#include #include "conntrack.h" @@ -27,29 +28,6 @@ static struct option opts[] = { {0, 0, 0, 0} }; -enum tcp_param_flags { - ORIG_SPORT_BIT = 0, - ORIG_SPORT = (1 << ORIG_SPORT_BIT), - - ORIG_DPORT_BIT = 1, - ORIG_DPORT = (1 << ORIG_DPORT_BIT), - - REPL_SPORT_BIT = 2, - REPL_SPORT = (1 << REPL_SPORT_BIT), - - REPL_DPORT_BIT = 3, - REPL_DPORT = (1 << REPL_DPORT_BIT), - - MASK_SPORT_BIT = 4, - MASK_SPORT = (1 << MASK_SPORT_BIT), - - MASK_DPORT_BIT = 5, - MASK_DPORT = (1 << MASK_DPORT_BIT), - - STATE_BIT = 6, - STATE = (1 << STATE_BIT) -}; - static const char *states[] = { "NONE", "SYN_SENT", @@ -63,7 +41,7 @@ static const char *states[] = { "LISTEN" }; -void help() +static void help() { fprintf(stdout, "--orig-port-src original source port\n"); fprintf(stdout, "--orig-port-dst original destination port\n"); @@ -74,48 +52,48 @@ void help() fprintf(stdout, "--state TCP state, fe. ESTABLISHED\n"); } -int parse_options(char c, char *argv[], - struct nfct_tuple *orig, - struct nfct_tuple *reply, - struct nfct_tuple *mask, - union nfct_protoinfo *proto, - unsigned int *flags) +static int parse_options(char c, char *argv[], + struct nfct_tuple *orig, + struct nfct_tuple *reply, + struct nfct_tuple *mask, + union nfct_protoinfo *proto, + unsigned int *flags) { switch(c) { case '1': if (optarg) { orig->l4src.tcp.port = htons(atoi(optarg)); - *flags |= ORIG_SPORT; + *flags |= TCP_ORIG_SPORT; } break; case '2': if (optarg) { orig->l4dst.tcp.port = htons(atoi(optarg)); - *flags |= ORIG_DPORT; + *flags |= TCP_ORIG_DPORT; } break; case '3': if (optarg) { reply->l4src.tcp.port = htons(atoi(optarg)); - *flags |= REPL_SPORT; + *flags |= TCP_REPL_SPORT; } break; case '4': if (optarg) { reply->l4dst.tcp.port = htons(atoi(optarg)); - *flags |= REPL_DPORT; + *flags |= TCP_REPL_DPORT; } break; case '5': if (optarg) { mask->l4src.tcp.port = htons(atoi(optarg)); - *flags |= MASK_SPORT; + *flags |= TCP_MASK_SPORT; } break; case '6': if (optarg) { mask->l4dst.tcp.port = htons(atoi(optarg)); - *flags |= MASK_DPORT; + *flags |= TCP_MASK_DPORT; } break; case '7': @@ -131,37 +109,37 @@ int parse_options(char c, char *argv[], printf("doh?\n"); return 0; } - *flags |= STATE; + *flags |= TCP_STATE; } break; } return 1; } -int final_check(unsigned int flags, - unsigned int command, - struct nfct_tuple *orig, - struct nfct_tuple *reply) +static int final_check(unsigned int flags, + unsigned int command, + struct nfct_tuple *orig, + struct nfct_tuple *reply) { int ret = 0; - if ((flags & (ORIG_SPORT|ORIG_DPORT)) - && !(flags & (REPL_SPORT|REPL_DPORT))) { + if ((flags & (TCP_ORIG_SPORT|TCP_ORIG_DPORT)) + && !(flags & (TCP_REPL_SPORT|TCP_REPL_DPORT))) { reply->l4src.tcp.port = orig->l4dst.tcp.port; reply->l4dst.tcp.port = orig->l4src.tcp.port; ret = 1; - } else if (!(flags & (ORIG_SPORT|ORIG_DPORT)) - && (flags & (REPL_SPORT|REPL_DPORT))) { + } else if (!(flags & (TCP_ORIG_SPORT|TCP_ORIG_DPORT)) + && (flags & (TCP_REPL_SPORT|TCP_REPL_DPORT))) { orig->l4src.tcp.port = reply->l4dst.tcp.port; orig->l4dst.tcp.port = reply->l4src.tcp.port; ret = 1; } - if ((flags & (ORIG_SPORT|ORIG_DPORT)) - && ((flags & (REPL_SPORT|REPL_DPORT)))) + if ((flags & (TCP_ORIG_SPORT|TCP_ORIG_DPORT)) + && ((flags & (TCP_REPL_SPORT|TCP_REPL_DPORT)))) ret = 1; /* --state is missing and we are trying to create a conntrack */ - if (ret && (command & CT_CREATE) && (!(flags & STATE))) + if (ret && (command & CT_CREATE) && (!(flags & TCP_STATE))) ret = 0; return ret; @@ -177,9 +155,9 @@ static struct ctproto_handler tcp = { .version = VERSION, }; -void __attribute__ ((constructor)) init(void); +static void __attribute__ ((constructor)) init(void); -void init(void) +static void init(void) { register_proto(&tcp); } diff --git a/extensions/libct_proto_udp.c b/extensions/libct_proto_udp.c index 958d464..974e455 100644 --- a/extensions/libct_proto_udp.c +++ b/extensions/libct_proto_udp.c @@ -13,6 +13,7 @@ #include /* For htons */ #include "conntrack.h" #include +#include static struct option opts[] = { {"orig-port-src", 1, 0, '1'}, @@ -24,27 +25,7 @@ static struct option opts[] = { {0, 0, 0, 0} }; -enum udp_param_flags { - ORIG_SPORT_BIT = 0, - ORIG_SPORT = (1 << ORIG_SPORT_BIT), - - ORIG_DPORT_BIT = 1, - ORIG_DPORT = (1 << ORIG_DPORT_BIT), - - REPL_SPORT_BIT = 2, - REPL_SPORT = (1 << REPL_SPORT_BIT), - - REPL_DPORT_BIT = 3, - REPL_DPORT = (1 << REPL_DPORT_BIT), - - MASK_SPORT_BIT = 4, - MASK_SPORT = (1 << MASK_SPORT_BIT), - - MASK_DPORT_BIT = 5, - MASK_DPORT = (1 << MASK_DPORT_BIT), -}; - -void help() +static void help() { fprintf(stdout, "--orig-port-src original source port\n"); fprintf(stdout, "--orig-port-dst original destination port\n"); @@ -54,72 +35,72 @@ void help() fprintf(stdout, "--mask-port-dst mask destination port\n"); } -int parse_options(char c, char *argv[], - struct nfct_tuple *orig, - struct nfct_tuple *reply, - struct nfct_tuple *mask, - union nfct_protoinfo *proto, - unsigned int *flags) +static int parse_options(char c, char *argv[], + struct nfct_tuple *orig, + struct nfct_tuple *reply, + struct nfct_tuple *mask, + union nfct_protoinfo *proto, + unsigned int *flags) { switch(c) { case '1': if (optarg) { orig->l4src.udp.port = htons(atoi(optarg)); - *flags |= ORIG_SPORT; + *flags |= UDP_ORIG_SPORT; } break; case '2': if (optarg) { orig->l4dst.udp.port = htons(atoi(optarg)); - *flags |= ORIG_DPORT; + *flags |= UDP_ORIG_DPORT; } break; case '3': if (optarg) { reply->l4src.udp.port = htons(atoi(optarg)); - *flags |= REPL_SPORT; + *flags |= UDP_REPL_SPORT; } break; case '4': if (optarg) { reply->l4dst.udp.port = htons(atoi(optarg)); - *flags |= REPL_DPORT; + *flags |= UDP_REPL_DPORT; } break; case '5': if (optarg) { mask->l4src.udp.port = htons(atoi(optarg)); - *flags |= MASK_SPORT; + *flags |= UDP_MASK_SPORT; } break; case '6': if (optarg) { mask->l4dst.udp.port = htons(atoi(optarg)); - *flags |= MASK_DPORT; + *flags |= UDP_MASK_DPORT; } break; } return 1; } -int final_check(unsigned int flags, - unsigned int command, - struct nfct_tuple *orig, - struct nfct_tuple *reply) +static int final_check(unsigned int flags, + unsigned int command, + struct nfct_tuple *orig, + struct nfct_tuple *reply) { - if ((flags & (ORIG_SPORT|ORIG_DPORT)) - && !(flags & (REPL_SPORT|REPL_DPORT))) { + if ((flags & (UDP_ORIG_SPORT|UDP_ORIG_DPORT)) + && !(flags & (UDP_REPL_SPORT|UDP_REPL_DPORT))) { reply->l4src.udp.port = orig->l4dst.udp.port; reply->l4dst.udp.port = orig->l4src.udp.port; return 1; - } else if (!(flags & (ORIG_SPORT|ORIG_DPORT)) - && (flags & (REPL_SPORT|REPL_DPORT))) { + } else if (!(flags & (UDP_ORIG_SPORT|UDP_ORIG_DPORT)) + && (flags & (UDP_REPL_SPORT|UDP_REPL_DPORT))) { orig->l4src.udp.port = reply->l4dst.udp.port; orig->l4dst.udp.port = reply->l4src.udp.port; return 1; } - if ((flags & (ORIG_SPORT|ORIG_DPORT)) - && ((flags & (REPL_SPORT|REPL_DPORT)))) + if ((flags & (UDP_ORIG_SPORT|UDP_ORIG_DPORT)) + && ((flags & (UDP_REPL_SPORT|UDP_REPL_DPORT)))) return 1; return 0; @@ -135,9 +116,9 @@ static struct ctproto_handler udp = { .version = VERSION, }; -void __attribute__ ((constructor)) init(void); +static void __attribute__ ((constructor)) init(void); -void init(void) +static void init(void) { register_proto(&udp); } diff --git a/src/conntrack.c b/src/conntrack.c index 59b95a4..eb9064d 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -120,7 +120,7 @@ static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = /*CT_DELETE*/ {' ',' ',' ',' ',' ','x','x','x','x','x','x','x','x','x','x',' '}, /*CT_GET*/ {' ',' ',' ',' ','+','x','x','x','x','x','x','x','x','x','x',' '}, /*CT_FLUSH*/ {'x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x'}, -/*CT_EVENT*/ {'x','x','x','x','x','x','x','x',' ','x','x','x','x','x','x','x'}, +/*CT_EVENT*/ {'x','x','x','x',' ','x','x','x',' ','x','x','x','x','x','x','x'}, /*VERSION*/ {'x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x'}, /*HELP*/ {'x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x'}, /*EXP_LIST*/ {'x','x','x','x','x','x','x','x','x','x','x','x','x','x','x',' '}, @@ -1014,24 +1014,33 @@ int main(int argc, char *argv[]) break; case CT_EVENT: - if (options & CT_OPT_EVENT_MASK) { + ct = nfct_conntrack_alloc(&orig, &reply, timeout, + &proto, status, mark, id, NULL); + if (!ct) + exit_error(OTHER_PROBLEM, "Not enough memory"); + + if (options & CT_OPT_EVENT_MASK) cth = nfct_open(CONNTRACK, event_mask); - if (!cth) - exit_error(OTHER_PROBLEM, "Can't open handler"); - signal(SIGINT, event_sighandler); - nfct_register_callback(cth, - nfct_default_conntrack_display, NULL); - res = nfct_event_conntrack(cth); - } else { + else cth = nfct_open(CONNTRACK, NFCT_ALL_CT_GROUPS); - if (!cth) - exit_error(OTHER_PROBLEM, "Can't open handler"); - signal(SIGINT, event_sighandler); + + if (!cth) + exit_error(OTHER_PROBLEM, "Can't open handler"); + signal(SIGINT, event_sighandler); + + if (options & CT_OPT_PROTO) { + struct nfct_conntrack_compare cmp = { + .ct = ct, + .flag = 0, + .protoflag = extra_flags + }; nfct_register_callback(cth, - nfct_default_conntrack_display, - NULL); - res = nfct_event_conntrack(cth); + nfct_default_conntrack_display, (void *)&cmp); + } else { + nfct_register_callback(cth, + nfct_default_conntrack_display, NULL); } + res = nfct_event_conntrack(cth); nfct_close(cth); break; -- cgit v1.2.3 From 3b361485bca7bc4eca6ac0d8ec53a2b27b981240 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, 4 Dec 2005 01:07:17 +0000 Subject: o Restore include "conntrack.h" in ICMP handler o Add missing flags coversion in SCTP handler --- ChangeLog | 1 - extensions/libct_proto_icmp.c | 1 + extensions/libct_proto_sctp.c | 24 ++++++++++++------------ src/conntrack.c | 5 +++-- 4 files changed, 16 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index befb699..e5d9bf4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,7 +5,6 @@ o Update manpage o Missing static function declaration in the protocol handlers o Use protocol flags defined in libnetfilter_conntrack - o Kill leftover #include "conntrack.h" in the ICMP helper o Bumped version to 0.991 2005-11-22 diff --git a/extensions/libct_proto_icmp.c b/extensions/libct_proto_icmp.c index afae25e..57a621f 100644 --- a/extensions/libct_proto_icmp.c +++ b/extensions/libct_proto_icmp.c @@ -15,6 +15,7 @@ #include #include #include +#include "conntrack.h" static struct option opts[] = { {"icmp-type", 1, 0, '1'}, diff --git a/extensions/libct_proto_sctp.c b/extensions/libct_proto_sctp.c index 7ff1dcf..825cbd9 100644 --- a/extensions/libct_proto_sctp.c +++ b/extensions/libct_proto_sctp.c @@ -56,25 +56,25 @@ static int parse_options(char c, char *argv[], case '1': if (optarg) { orig->l4src.sctp.port = htons(atoi(optarg)); - *flags |= ORIG_SPORT; + *flags |= SCTP_ORIG_SPORT; } break; case '2': if (optarg) { orig->l4dst.sctp.port = htons(atoi(optarg)); - *flags |= ORIG_DPORT; + *flags |= SCTP_ORIG_DPORT; } break; case '3': if (optarg) { reply->l4src.sctp.port = htons(atoi(optarg)); - *flags |= REPL_SPORT; + *flags |= SCTP_REPL_SPORT; } break; case '4': if (optarg) { reply->l4dst.sctp.port = htons(atoi(optarg)); - *flags |= REPL_DPORT; + *flags |= SCTP_REPL_DPORT; } break; case '5': @@ -92,7 +92,7 @@ static int parse_options(char c, char *argv[], printf("doh?\n"); return 0; } - *flags |= STATE; + *flags |= SCTP_STATE; } break; } @@ -106,23 +106,23 @@ static int final_check(unsigned int flags, { int ret = 0; - if ((flags & (ORIG_SPORT|ORIG_DPORT)) - && !(flags & (REPL_SPORT|REPL_DPORT))) { + if ((flags & (SCTP_ORIG_SPORT|SCTP_ORIG_DPORT)) + && !(flags & (SCTP_REPL_SPORT|SCTP_REPL_DPORT))) { reply->l4src.sctp.port = orig->l4dst.sctp.port; reply->l4dst.sctp.port = orig->l4src.sctp.port; ret = 1; - } else if (!(flags & (ORIG_SPORT|ORIG_DPORT)) - && (flags & (REPL_SPORT|REPL_DPORT))) { + } else if (!(flags & (SCTP_ORIG_SPORT|SCTP_ORIG_DPORT)) + && (flags & (SCTP_REPL_SPORT|SCTP_REPL_DPORT))) { orig->l4src.sctp.port = reply->l4dst.sctp.port; orig->l4dst.sctp.port = reply->l4src.sctp.port; ret = 1; } - if ((flags & (ORIG_SPORT|ORIG_DPORT)) - && ((flags & (REPL_SPORT|REPL_DPORT)))) + if ((flags & (SCTP_ORIG_SPORT|SCTP_ORIG_DPORT)) + && ((flags & (SCTP_REPL_SPORT|SCTP_REPL_DPORT)))) ret = 1; /* --state is missing and we are trying to create a conntrack */ - if (ret && (command & CT_CREATE) && (!(flags & STATE))) + if (ret && (command & CT_CREATE) && (!(flags & SCTP_STATE))) ret = 0; return ret; diff --git a/src/conntrack.c b/src/conntrack.c index eb9064d..1527c50 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -1035,10 +1035,11 @@ int main(int argc, char *argv[]) .protoflag = extra_flags }; nfct_register_callback(cth, - nfct_default_conntrack_display, (void *)&cmp); + nfct_default_conntrack_event_display, + (void *)&cmp); } else { nfct_register_callback(cth, - nfct_default_conntrack_display, NULL); + nfct_default_conntrack_event_display, NULL); } res = nfct_event_conntrack(cth); nfct_close(cth); -- cgit v1.2.3 From ed189ea982809166742143653482e29bab065e6e 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: Mon, 19 Dec 2005 17:53:58 +0000 Subject: We only support ipv4 at the moment, set l3protonum to AF_INET --- ChangeLog | 6 +++++- src/conntrack.c | 8 ++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index e5d9bf4..b6c0c93 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,8 @@ -2005-13-03 +2005-12-19 + + o We only support ipv4 at the moment: set l3protonum to AF_INET + +2005-12-03 o Add support to filter events. ie: -p tcp --orig-port-dst 80 in conjuction with -E to get all the requests to HTTP servers diff --git a/src/conntrack.c b/src/conntrack.c index 1527c50..28328d7 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -644,6 +644,14 @@ int main(int argc, char *argv[]) memset(&exptuple, 0, sizeof(struct nfct_tuple)); memset(&range, 0, sizeof(struct nfct_nat)); + /* + * FIXME: only IPv4 support available at the moment + */ + orig.l3protonum = AF_INET; + reply.l3protonum = AF_INET; + mask.l3protonum = AF_INET; + exptuple.l3protonum = AF_INET; + while ((c = getopt_long(argc, argv, "L::I::U::D::G::E::F::hVs:d:r:q:p:t:u:e:a:z[:]:{:}:m:i::", opts, NULL)) != -1) { -- cgit v1.2.3 From ddea86cb98ddc40f6dfb0ef7081891ea4f53f0c3 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: Mon, 19 Dec 2005 20:31:12 +0000 Subject: More changes to prepare upcoming ipv4 support --- ChangeLog | 1 + src/conntrack.c | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index b6c0c93..f002815 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,7 @@ 2005-12-19 o We only support ipv4 at the moment: set l3protonum to AF_INET + o Minor changes to prepare upcoming ipv6 support 2005-12-03 diff --git a/src/conntrack.c b/src/conntrack.c index 28328d7..145ef24 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -849,9 +849,9 @@ int main(int argc, char *argv[]) NULL); if (options & CT_OPT_ZERO) - res = nfct_dump_conntrack_table_reset_counters(cth); + res = nfct_dump_conntrack_table_reset_counters(cth, AF_INET); else - res = nfct_dump_conntrack_table(cth); + res = nfct_dump_conntrack_table(cth, AF_INET); nfct_close(cth); break; @@ -867,7 +867,7 @@ int main(int argc, char *argv[]) nfct_register_callback(cth, nfct_default_expect_display, NULL); - res = nfct_dump_expect_list(cth); + res = nfct_dump_expect_list(cth, AF_INET); nfct_close(cth); break; @@ -1009,7 +1009,7 @@ int main(int argc, char *argv[]) cth = nfct_open(CONNTRACK, 0); if (!cth) exit_error(OTHER_PROBLEM, "Can't open handler"); - res = nfct_flush_conntrack_table(cth); + res = nfct_flush_conntrack_table(cth, AF_INET); nfct_close(cth); break; @@ -1017,7 +1017,7 @@ int main(int argc, char *argv[]) cth = nfct_open(EXPECT, 0); if (!cth) exit_error(OTHER_PROBLEM, "Can't open handler"); - res = nfct_flush_expectation_table(cth); + res = nfct_flush_expectation_table(cth, AF_INET); nfct_close(cth); break; -- cgit v1.2.3 From 54424b2156918d64d1860f579f538793059b4d5d 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: Mon, 26 Dec 2005 02:49:34 +0000 Subject: o add IPv6 support: main change o removed dead code: iptables_insmod and get_modprobe o compact the commands vs. options table o move working vars from the stack to the BSS section o update manpage o Bumped version to 1.0beta1 o check address family mismatch o fix incomplete copying IPv6 addresses --- ChangeLog | 12 ++ configure.in | 35 +++++- conntrack.8 | 4 + include/conntrack.h | 5 +- src/conntrack.c | 337 +++++++++++++++++++++++++++------------------------- 5 files changed, 230 insertions(+), 163 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index f002815..2685bf6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2005-12-26 + + o add IPv6 support: main change + o removed dead code: iptables_insmod and get_modprobe + o compact the commands vs. options table + o move working vars from the stack to the BSS section + o update manpage + o Bumped version to 1.0beta1 + + o check address family mismatch + o fix incomplete copying IPv6 addresses + 2005-12-19 o We only support ipv4 at the moment: set l3protonum to AF_INET diff --git a/configure.in b/configure.in index 4dd09c6..7dab80f 100644 --- a/configure.in +++ b/configure.in @@ -2,7 +2,7 @@ AC_INIT AC_CANONICAL_SYSTEM -AM_INIT_AUTOMAKE(conntrack, 0.991) +AM_INIT_AUTOMAKE(conntrack, 1.0beta1) #AM_CONFIG_HEADER(config.h) AC_PROG_CC @@ -23,6 +23,39 @@ dnl AC_CHECK_LIB([c], [main]) AC_CHECK_LIB([dl], [dlopen]) AC_CHECK_LIB([netfilter_conntrack], [nfct_dump_conntrack_table] ,,,[-lnetfilter_conntrack]) +AC_CHECK_HEADERS(arpa/inet.h) +dnl check for inet_pton +AC_CHECK_FUNCS(inet_pton) +dnl Some systems have it, but not IPv6 +if test "$ac_cv_func_inet_pton" = "yes" ; then +AC_MSG_CHECKING(if inet_pton supports IPv6) +AC_TRY_RUN( + [ +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +int main() + { + struct in6_addr addr6; + if (inet_pton(AF_INET6, "::1", &addr6) < 1) + exit(1); + else + exit(0); + } + ], [ AC_MSG_RESULT(yes) + AC_DEFINE_UNQUOTED(HAVE_INET_PTON_IPV6, 1, [Define to 1 if inet_pton supports IPv6.]) + ], AC_MSG_RESULT(no), AC_MSG_RESULT(no)) +fi + # Checks for header files. dnl AC_HEADER_STDC dnl AC_CHECK_HEADERS([netinet/in.h stdlib.h]) diff --git a/conntrack.8 b/conntrack.8 index 8dbecb5..307180b 100644 --- a/conntrack.8 +++ b/conntrack.8 @@ -97,6 +97,10 @@ Match only entries whose destination address in the reply direction equals the o .BI "-p, --proto " "PROTO " Specify layer four (TCP, UDP, ...) protocol. .TP +.BI "-f, --family " "PROTO" +Specify layer three (ipv4, ipv6) protocol +This option is only required in conjunction with "-L, --dump". If this option is not passed, the default layer 3 protocol will be IPv4. +.TP .BI "-t, --timeout " "TIMEOUT" Specify the timeout. .TP diff --git a/include/conntrack.h b/include/conntrack.h index 1de5b34..e9f1946 100644 --- a/include/conntrack.h +++ b/include/conntrack.h @@ -115,7 +115,10 @@ enum options { CT_OPT_ID_BIT = 15, CT_OPT_ID = (1 << CT_OPT_ID_BIT), - CT_OPT_MAX_BIT = CT_OPT_ID_BIT + CT_OPT_FAMILY_BIT = 16, + CT_OPT_FAMILY = (1 << CT_OPT_FAMILY_BIT), + + CT_OPT_MAX_BIT = CT_OPT_FAMILY_BIT }; #define NUMBER_OF_OPT CT_OPT_MAX_BIT+1 diff --git a/src/conntrack.c b/src/conntrack.c index 145ef24..b27cf47 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -43,26 +43,26 @@ #include #include #include +#ifdef HAVE_ARPA_INET_H #include +#endif #include #include #include #include "linux_list.h" #include "conntrack.h" #include - -#ifndef PROC_SYS_MODPROBE -#define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe" -#endif +#include +#include static const char cmdflags[NUMBER_OF_CMD] = {'L','I','U','D','G','F','E','V','h','L','I','D','G','F','E'}; static const char cmd_need_param[NUMBER_OF_CMD] -= {' ','x','x','x','x',' ',' ',' ',' ',' ','x','x','x',' ',' '}; += { 2, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, 0, 2, 2 }; static const char optflags[NUMBER_OF_OPT] -= {'s','d','r','q','p','t','u','z','e','[',']','{','}','a','m','i'}; += {'s','d','r','q','p','t','u','z','e','[',']','{','}','a','m','i','f'}; static struct option original_opts[] = { {"dump", 2, 0, 'L'}, @@ -90,6 +90,7 @@ static struct option original_opts[] = { {"nat-range", 1, 0, 'a'}, {"mark", 1, 0, 'm'}, {"id", 2, 0, 'i'}, + {"family", 1, 0, 'f'}, {0, 0, 0, 0} }; @@ -103,32 +104,30 @@ static unsigned int global_option_offset = 0; * given commands make an option legal, that option is legal (applies to * CMD_LIST and CMD_ZERO only). * Key: - * + compulsory - * x illegal - * optional + * 0 illegal + * 1 compulsory + * 2 optional */ -/* FIXME: I'd need something different than this table to catch up some - * particular cases. Better later Pablo */ static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = /* Well, it's better than "Re: Linux vs FreeBSD" */ { - /* -s -d -r -q -p -t -u -z -e -x -y -k -l -a -m -i*/ -/*CT_LIST*/ {'x','x','x','x','x','x','x',' ','x','x','x','x','x','x','x',' '}, -/*CT_CREATE*/ {' ',' ',' ',' ','+','+','+','x','x','x','x','x','x',' ',' ','x'}, -/*CT_UPDATE*/ {' ',' ',' ',' ','+',' ',' ','x','x','x','x','x','x','x',' ',' '}, -/*CT_DELETE*/ {' ',' ',' ',' ',' ','x','x','x','x','x','x','x','x','x','x',' '}, -/*CT_GET*/ {' ',' ',' ',' ','+','x','x','x','x','x','x','x','x','x','x',' '}, -/*CT_FLUSH*/ {'x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x'}, -/*CT_EVENT*/ {'x','x','x','x',' ','x','x','x',' ','x','x','x','x','x','x','x'}, -/*VERSION*/ {'x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x'}, -/*HELP*/ {'x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x'}, -/*EXP_LIST*/ {'x','x','x','x','x','x','x','x','x','x','x','x','x','x','x',' '}, -/*EXP_CREATE*/{'+','+',' ',' ','+','+',' ','x','x','+','+','+','+','x','x','x'}, -/*EXP_DELETE*/{'+','+',' ',' ','+','x','x','x','x','x','x','x','x','x','x','x'}, -/*EXP_GET*/ {'+','+',' ',' ','+','x','x','x','x','x','x','x','x','x','x','x'}, -/*EXP_FLUSH*/ {'x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x'}, -/*EXP_EVENT*/ {'x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x'}, + /* s d r q p t u z e x y k l a m i f*/ +/*CT_LIST*/ {0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,2,2}, +/*CT_CREATE*/ {2,2,2,2,1,1,1,0,0,0,0,0,0,2,2,0,0}, +/*CT_UPDATE*/ {2,2,2,2,1,2,2,0,0,0,0,0,0,0,2,2,0}, +/*CT_DELETE*/ {2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,2,0}, +/*CT_GET*/ {2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,2,0}, +/*CT_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*CT_EVENT*/ {2,2,2,2,2,0,0,0,2,0,0,0,0,0,2,0,0}, +/*VERSION*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*HELP*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*EXP_LIST*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2}, +/*EXP_CREATE*/{1,1,2,2,1,1,2,0,0,1,1,1,1,0,0,0,0}, +/*EXP_DELETE*/{1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0}, +/*EXP_GET*/ {1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0}, +/*EXP_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*EXP_EVENT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, }; static char *lib_dir = CONNTRACK_LIB_DIR; @@ -230,7 +229,7 @@ generic_cmd_check(int command, int options) if (!(command & (1<addr)) + return AF_INET; +#ifdef HAVE_INET_PTON_IPV6 + else if (inet_pton(AF_INET6, cp, &parse->addr6) > 0) + return AF_INET6; +#endif - free(buf); - if (WIFEXITED(status) && WEXITSTATUS(status) == 0) - return 0; - return -1; + exit_error(PARAMETER_PROBLEM, "Invalid IP address `%s'.", cp); } -in_addr_t parse_inetaddr(const char *cp) +int parse_inetaddr(const char *cp, union nfct_address *address) { - struct in_addr addr; - - if (inet_aton(cp, &addr)) { - return addr.s_addr; - } - - exit_error(PARAMETER_PROBLEM, "Invalid IP address `%s'.", cp); + struct addr_parse parse; + int ret; + + if ((ret = __parse_inetaddr(cp, &parse)) == AF_INET) + address->v4 = parse.addr.s_addr; + else if (ret == AF_INET6) + memcpy(address->v6, &parse.addr6, sizeof(parse.addr6)); + return ret; } /* Shamelessly stolen from libipt_DNAT ;). Ranges expected in network order. */ @@ -497,7 +459,7 @@ static void nat_parse(char *arg, int portok, struct nfct_nat *range) { char *colon, *dash, *error; - unsigned long ip; + struct addr_parse parse; memset(range, 0, sizeof(range)); colon = strchr(arg, ':'); @@ -551,13 +513,16 @@ nat_parse(char *arg, int portok, struct nfct_nat *range) if (dash) *dash = '\0'; - ip = parse_inetaddr(arg); - range->min_ip = ip; + if (__parse_inetaddr(arg, &parse) != AF_INET) + return; + + range->min_ip = parse.addr.s_addr; if (dash) { - ip = parse_inetaddr(dash+1); - range->max_ip = ip; + if (__parse_inetaddr(dash+1, &parse) != AF_INET) + return; + range->max_ip = parse.addr.s_addr; } else - range->max_ip = range->min_ip; + range->max_ip = parse.addr.s_addr; } static void event_sighandler(int s) @@ -602,6 +567,7 @@ static const char usage_parameters[] = " -r, --reply-src ip\t\tSource addres from reply direction\n" " -q, --reply-dst ip\t\tDestination address from reply direction\n" " -p, --protonum proto\t\tLayer 4 Protocol, eg. 'tcp'\n" + " -f, --family proto\t\tLayer 3 Protocol, eg. 'ipv6'\n" " -t, --timeout timeout\t\tSet timeout\n" " -u, --status status\t\tSet status, eg. ASSURED\n" " -i, --id [id]\t\t\tShow or set conntrack ID\n" @@ -619,41 +585,29 @@ void usage(char *prog) { fprintf(stdout, "\n%s", usage_parameters); } +static struct nfct_tuple orig, reply, mask; +static struct nfct_tuple exptuple; +static struct ctproto_handler *h; +static union nfct_protoinfo proto; +static struct nfct_nat range; +static struct nfct_conntrack *ct; +static struct nfct_expect *exp; +static unsigned long timeout; +static unsigned int status; +static unsigned int mark; +static unsigned int id = NFCT_ANY_ID; + int main(int argc, char *argv[]) { char c; unsigned int command = 0, options = 0; - struct nfct_tuple orig, reply, mask; - struct nfct_tuple exptuple; - struct ctproto_handler *h = NULL; - union nfct_protoinfo proto; - struct nfct_nat range; - struct nfct_conntrack *ct; - struct nfct_expect *exp; - unsigned long timeout = 0; - unsigned int status = 0; - unsigned int mark = 0; - unsigned int id = NFCT_ANY_ID; - unsigned int type = 0, extra_flags = 0, event_mask = 0; + unsigned int type = 0, event_mask = 0; + unsigned int l3flags = 0, l4flags = 0; int res = 0; - - memset(&proto, 0, sizeof(union nfct_protoinfo)); - memset(&orig, 0, sizeof(struct nfct_tuple)); - memset(&reply, 0, sizeof(struct nfct_tuple)); - memset(&mask, 0, sizeof(struct nfct_tuple)); - memset(&exptuple, 0, sizeof(struct nfct_tuple)); - memset(&range, 0, sizeof(struct nfct_nat)); - - /* - * FIXME: only IPv4 support available at the moment - */ - orig.l3protonum = AF_INET; - reply.l3protonum = AF_INET; - mask.l3protonum = AF_INET; - exptuple.l3protonum = AF_INET; + int family = AF_UNSPEC; while ((c = getopt_long(argc, argv, - "L::I::U::D::G::E::F::hVs:d:r:q:p:t:u:e:a:z[:]:{:}:m:i::", + "L::I::U::D::G::E::F::hVs:d:r:q:p:t:u:e:a:z[:]:{:}:m:i::f:", opts, NULL)) != -1) { switch(c) { case 'L': @@ -714,23 +668,51 @@ int main(int argc, char *argv[]) break; case 's': options |= CT_OPT_ORIG_SRC; - if (optarg) - orig.src.v4 = parse_inetaddr(optarg); + if (optarg) { + orig.l3protonum = + parse_inetaddr(optarg, &orig.src); + set_family(&family, orig.l3protonum); + if (orig.l3protonum == AF_INET) + l3flags |= IPV4_ORIG_SRC; + else if (orig.l3protonum == AF_INET6) + l3flags |= IPV6_ORIG_SRC; + } break; case 'd': options |= CT_OPT_ORIG_DST; - if (optarg) - orig.dst.v4 = parse_inetaddr(optarg); + if (optarg) { + orig.l3protonum = + parse_inetaddr(optarg, &orig.dst); + set_family(&family, orig.l3protonum); + if (orig.l3protonum == AF_INET) + l3flags |= IPV4_ORIG_DST; + else if (orig.l3protonum == AF_INET6) + l3flags |= IPV6_ORIG_DST; + } break; case 'r': options |= CT_OPT_REPL_SRC; - if (optarg) - reply.src.v4 = parse_inetaddr(optarg); + if (optarg) { + reply.l3protonum = + parse_inetaddr(optarg, &reply.src); + set_family(&family, reply.l3protonum); + if (orig.l3protonum == AF_INET) + l3flags |= IPV4_REPL_SRC; + else if (orig.l3protonum == AF_INET6) + l3flags |= IPV6_REPL_SRC; + } break; case 'q': options |= CT_OPT_REPL_DST; - if (optarg) - reply.dst.v4 = parse_inetaddr(optarg); + if (optarg) { + reply.l3protonum = + parse_inetaddr(optarg, &reply.dst); + set_family(&family, reply.l3protonum); + if (orig.l3protonum == AF_INET) + l3flags |= IPV4_REPL_DST; + else if (orig.l3protonum == AF_INET6) + l3flags |= IPV6_REPL_DST; + } break; case 'p': options |= CT_OPT_PROTO; @@ -766,26 +748,39 @@ int main(int argc, char *argv[]) break; case '{': options |= CT_OPT_MASK_SRC; - if (optarg) - mask.src.v4 = parse_inetaddr(optarg); + if (optarg) { + mask.l3protonum = + parse_inetaddr(optarg, &mask.src); + set_family(&family, mask.l3protonum); + } break; case '}': options |= CT_OPT_MASK_DST; - if (optarg) - mask.dst.v4 = parse_inetaddr(optarg); + if (optarg) { + mask.l3protonum = + parse_inetaddr(optarg, &mask.dst); + set_family(&family, mask.l3protonum); + } break; case '[': options |= CT_OPT_EXP_SRC; - if (optarg) - exptuple.src.v4 = parse_inetaddr(optarg); + if (optarg) { + exptuple.l3protonum = + parse_inetaddr(optarg, &exptuple.src); + set_family(&family, exptuple.l3protonum); + } break; case ']': options |= CT_OPT_EXP_DST; - if (optarg) - exptuple.dst.v4 = parse_inetaddr(optarg); + if (optarg) { + exptuple.l3protonum = + parse_inetaddr(optarg, &exptuple.dst); + set_family(&family, exptuple.l3protonum); + } break; case 'a': options |= CT_OPT_NATRANGE; + set_family(&family, AF_INET); nat_parse(optarg, 1, &range); break; case 'm': @@ -804,11 +799,21 @@ int main(int argc, char *argv[]) id = atol(s); break; } + case 'f': + options |= CT_OPT_FAMILY; + if (strncmp(optarg, "ipv4", strlen("ipv4")) == 0) + set_family(&family, AF_INET); + else if (strncmp(optarg, "ipv6", strlen("ipv6")) == 0) + set_family(&family, AF_INET6); + else + exit_error(PARAMETER_PROBLEM, "Unknown " + "protocol family\n"); + break; default: if (h && h->parse_opts &&!h->parse_opts(c - h->option_offset, argv, &orig, &reply, &mask, &proto, - &extra_flags)) + &l4flags)) exit_error(PARAMETER_PROBLEM, "parse error\n"); /* Unknown argument... */ @@ -821,12 +826,16 @@ int main(int argc, char *argv[]) } } + /* default family */ + if (family == AF_UNSPEC) + family = AF_INET; + generic_cmd_check(command, options); generic_opt_check(command, options); if (!(command & CT_HELP) && h && h->final_check - && !h->final_check(extra_flags, command, &orig, &reply)) { + && !h->final_check(l4flags, command, &orig, &reply)) { usage(argv[0]); extension_help(h); exit_error(PARAMETER_PROBLEM, "Missing protocol arguments!\n"); @@ -849,9 +858,10 @@ int main(int argc, char *argv[]) NULL); if (options & CT_OPT_ZERO) - res = nfct_dump_conntrack_table_reset_counters(cth, AF_INET); + res = + nfct_dump_conntrack_table_reset_counters(cth, family); else - res = nfct_dump_conntrack_table(cth, AF_INET); + res = nfct_dump_conntrack_table(cth, family); nfct_close(cth); break; @@ -867,19 +877,21 @@ int main(int argc, char *argv[]) nfct_register_callback(cth, nfct_default_expect_display, NULL); - res = nfct_dump_expect_list(cth, AF_INET); + res = nfct_dump_expect_list(cth, family); nfct_close(cth); break; case CT_CREATE: if ((options & CT_OPT_ORIG) && !(options & CT_OPT_REPL)) { - reply.src.v4 = orig.dst.v4; - reply.dst.v4 = orig.src.v4; + reply.l3protonum = orig.l3protonum; + memcpy(&reply.src, &orig.dst, sizeof(reply.src)); + memcpy(&reply.dst, &orig.src, sizeof(reply.dst)); } else if (!(options & CT_OPT_ORIG) && (options & CT_OPT_REPL)) { - orig.src.v4 = reply.dst.v4; - orig.dst.v4 = reply.src.v4; + orig.l3protonum = reply.l3protonum; + memcpy(&orig.src, &reply.dst, sizeof(orig.src)); + memcpy(&orig.dst, &reply.src, sizeof(orig.dst)); } if (options & CT_OPT_NATRANGE) ct = nfct_conntrack_alloc(&orig, &reply, timeout, @@ -925,12 +937,14 @@ int main(int argc, char *argv[]) case CT_UPDATE: if ((options & CT_OPT_ORIG) && !(options & CT_OPT_REPL)) { - reply.src.v4 = orig.dst.v4; - reply.dst.v4 = orig.src.v4; + reply.l3protonum = orig.l3protonum; + memcpy(&reply.src, &orig.dst, sizeof(reply.src)); + memcpy(&reply.dst, &orig.src, sizeof(reply.dst)); } else if (!(options & CT_OPT_ORIG) && (options & CT_OPT_REPL)) { - orig.src.v4 = reply.dst.v4; - orig.dst.v4 = reply.src.v4; + orig.l3protonum = reply.l3protonum; + memcpy(&orig.src, &reply.dst, sizeof(orig.src)); + memcpy(&orig.dst, &reply.src, sizeof(orig.dst)); } ct = nfct_conntrack_alloc(&orig, &reply, timeout, &proto, status, mark, id, @@ -1036,11 +1050,12 @@ int main(int argc, char *argv[]) exit_error(OTHER_PROBLEM, "Can't open handler"); signal(SIGINT, event_sighandler); - if (options & CT_OPT_PROTO) { + if (options & (CT_OPT_PROTO | CT_OPT_ORIG | CT_OPT_REPL)) { struct nfct_conntrack_compare cmp = { .ct = ct, - .flag = 0, - .protoflag = extra_flags + .flags = 0, + .l3flags = l3flags, + .l4flags = l4flags }; nfct_register_callback(cth, nfct_default_conntrack_event_display, -- cgit v1.2.3 From 01053da6549f4c7bc48574b8dcaa12f565245e6b 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, 15 Jan 2006 03:10:02 +0000 Subject: o Added missing parameters to set the ports of an expectation tuple o Bumped version to 1.00beta2 --- ChangeLog | 5 +++++ configure.in | 2 +- extensions/libct_proto_sctp.c | 20 +++++++++++++++++++- extensions/libct_proto_tcp.c | 17 +++++++++++++++++ extensions/libct_proto_udp.c | 17 +++++++++++++++++ include/conntrack.h | 1 + src/conntrack.c | 2 +- test.sh | 3 ++- 8 files changed, 63 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 2685bf6..7a46999 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2006-01-15 + + o Added missing parameters to set the ports of an expectation tuple + o Bumped version to 1.00beta2 + 2005-12-26 o add IPv6 support: main change diff --git a/configure.in b/configure.in index 5336a4d..2692b67 100644 --- a/configure.in +++ b/configure.in @@ -2,7 +2,7 @@ AC_INIT AC_CANONICAL_SYSTEM -AM_INIT_AUTOMAKE(conntrack, 1.00beta1) +AM_INIT_AUTOMAKE(conntrack, 1.00beta2) #AM_CONFIG_HEADER(config.h) AC_PROG_CC diff --git a/extensions/libct_proto_sctp.c b/extensions/libct_proto_sctp.c index 825cbd9..1c8f0d1 100644 --- a/extensions/libct_proto_sctp.c +++ b/extensions/libct_proto_sctp.c @@ -1,5 +1,6 @@ /* * (C) 2005 by Harald Welte + * 2006 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 @@ -21,7 +22,9 @@ static struct option opts[] = { {"orig-port-dst", 1, 0, '2'}, {"reply-port-src", 1, 0, '3'}, {"reply-port-dst", 1, 0, '4'}, - {"state", 1, 0, '7'}, + {"state", 1, 0, '5'}, + {"tuple-port-src", 1, 0, '6'}, + {"tuple-port-dst", 1, 0, '7'}, {0, 0, 0, 0} }; @@ -43,11 +46,14 @@ static void help() fprintf(stdout, "--reply-port-src reply source port\n"); fprintf(stdout, "--reply-port-dst reply destination port\n"); fprintf(stdout, "--state SCTP state, fe. ESTABLISHED\n"); + fprintf(stdout, "--tuple-port-src expectation tuple src port\n"); + fprintf(stdout, "--tuple-port-src expectation tuple dst port\n"); } static int parse_options(char c, char *argv[], struct nfct_tuple *orig, struct nfct_tuple *reply, + struct nfct_tuple *exptuple, struct nfct_tuple *mask, union nfct_protoinfo *proto, unsigned int *flags) @@ -95,6 +101,18 @@ static int parse_options(char c, char *argv[], *flags |= SCTP_STATE; } break; + case '6': + if (optarg) { + exptuple->l4src.sctp.port = htons(atoi(optarg)); + *flags |= SCTP_EXPTUPLE_SPORT; + } + break; + case '7': + if (optarg) { + exptuple->l4dst.sctp.port = htons(atoi(optarg)); + *flags |= SCTP_EXPTUPLE_DPORT; + } + } return 1; } diff --git a/extensions/libct_proto_tcp.c b/extensions/libct_proto_tcp.c index 35fa292..ee24206 100644 --- a/extensions/libct_proto_tcp.c +++ b/extensions/libct_proto_tcp.c @@ -25,6 +25,8 @@ static struct option opts[] = { {"mask-port-src", 1, 0, '5'}, {"mask-port-dst", 1, 0, '6'}, {"state", 1, 0, '7'}, + {"tuple-port-src", 1, 0, '8'}, + {"tuple-port-dst", 1, 0, '9'}, {0, 0, 0, 0} }; @@ -49,12 +51,15 @@ static void help() fprintf(stdout, "--reply-port-dst reply destination port\n"); fprintf(stdout, "--mask-port-src mask source port\n"); fprintf(stdout, "--mask-port-dst mask destination port\n"); + fprintf(stdout, "--tuple-port-src expectation tuple src port\n"); + fprintf(stdout, "--tuple-port-src expectation tuple dst port\n"); fprintf(stdout, "--state TCP state, fe. ESTABLISHED\n"); } static int parse_options(char c, char *argv[], struct nfct_tuple *orig, struct nfct_tuple *reply, + struct nfct_tuple *exptuple, struct nfct_tuple *mask, union nfct_protoinfo *proto, unsigned int *flags) @@ -112,6 +117,18 @@ static int parse_options(char c, char *argv[], *flags |= TCP_STATE; } break; + case '8': + if (optarg) { + exptuple->l4src.tcp.port = htons(atoi(optarg)); + *flags |= TCP_EXPTUPLE_SPORT; + } + break; + case '9': + if (optarg) { + exptuple->l4dst.tcp.port = htons(atoi(optarg)); + *flags |= TCP_EXPTUPLE_DPORT; + } + break; } return 1; } diff --git a/extensions/libct_proto_udp.c b/extensions/libct_proto_udp.c index 974e455..48079e0 100644 --- a/extensions/libct_proto_udp.c +++ b/extensions/libct_proto_udp.c @@ -22,6 +22,8 @@ static struct option opts[] = { {"reply-port-dst", 1, 0, '4'}, {"mask-port-src", 1, 0, '5'}, {"mask-port-dst", 1, 0, '6'}, + {"tuple-port-src", 1, 0, '7'}, + {"tuple-port-dst", 1, 0, '8'}, {0, 0, 0, 0} }; @@ -33,11 +35,14 @@ static void help() fprintf(stdout, "--reply-port-dst reply destination port\n"); fprintf(stdout, "--mask-port-src mask source port\n"); fprintf(stdout, "--mask-port-dst mask destination port\n"); + fprintf(stdout, "--tuple-port-src expectation tuple src port\n"); + fprintf(stdout, "--tuple-port-src expectation tuple dst port\n"); } static int parse_options(char c, char *argv[], struct nfct_tuple *orig, struct nfct_tuple *reply, + struct nfct_tuple *exptuple, struct nfct_tuple *mask, union nfct_protoinfo *proto, unsigned int *flags) @@ -79,6 +84,18 @@ static int parse_options(char c, char *argv[], *flags |= UDP_MASK_DPORT; } break; + case '7': + if (optarg) { + exptuple->l4src.udp.port = htons(atoi(optarg)); + *flags |= UDP_EXPTUPLE_SPORT; + } + break; + case '8': + if (optarg) { + exptuple->l4dst.udp.port = htons(atoi(optarg)); + *flags |= UDP_EXPTUPLE_DPORT; + } + } return 1; } diff --git a/include/conntrack.h b/include/conntrack.h index e9f1946..9f5768d 100644 --- a/include/conntrack.h +++ b/include/conntrack.h @@ -134,6 +134,7 @@ struct ctproto_handler { int (*parse_opts)(char c, char *argv[], struct nfct_tuple *orig, struct nfct_tuple *reply, + struct nfct_tuple *exptuple, struct nfct_tuple *mask, union nfct_protoinfo *proto, unsigned int *flags); diff --git a/src/conntrack.c b/src/conntrack.c index b27cf47..f904344 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -812,7 +812,7 @@ int main(int argc, char *argv[]) default: if (h && h->parse_opts &&!h->parse_opts(c - h->option_offset, argv, &orig, - &reply, &mask, &proto, + &reply, &exptuple, &mask, &proto, &l4flags)) exit_error(PARAMETER_PROBLEM, "parse error\n"); diff --git a/test.sh b/test.sh index b84fb13..4694236 100644 --- a/test.sh +++ b/test.sh @@ -78,7 +78,8 @@ case $1 in --tuple-src 4.4.4.4 --tuple-dst 5.5.5.5 \ --mask-src 255.255.255.0 --mask-dst 255.255.255.255 \ -p tcp --orig-port-src $SPORT --orig-port-dst $DPORT \ - -t 200 --mask-port-src 10 --mask-port-dst 300 + -t 200 --tuple-port-src 10 --tuple-port-dst 300 \ + --mask-port-src 10 --mask-port-dst 300 ;; get-expect) $CONNTRACK -G expect --orig-src 4.4.4.4 --orig-dst 5.5.5.5 \ -- cgit v1.2.3 From 69bdc92bf7b8ba3b8ea9341a75413817f8fb5e05 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, 15 Jan 2006 03:50:24 +0000 Subject: o Add support to filter dumped entries. ie: - display all the connections to IMAPS servers conntrack -L -p tcp --orig-port-dst 993 - display all the connection marked with 2 conntrack -L -m 2 --- ChangeLog | 5 +++++ src/conntrack.c | 67 ++++++++++++++++++++++++++++++++++++++------------------- 2 files changed, 50 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 7a46999..00a46b5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,11 @@ 2006-01-15 o Added missing parameters to set the ports of an expectation tuple + o Add support to filter dumped entries. + ie: conntrack -L -p tcp --orig-port-dst 993 + display all the connections to IMAPS servers + conntrack -L -m 2 + display all the connection marked with 2 o Bumped version to 1.00beta2 2005-12-26 diff --git a/src/conntrack.c b/src/conntrack.c index f904344..2105561 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -113,7 +113,7 @@ static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = /* Well, it's better than "Re: Linux vs FreeBSD" */ { /* s d r q p t u z e x y k l a m i f*/ -/*CT_LIST*/ {0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,2,2}, +/*CT_LIST*/ {2,2,2,2,2,0,0,2,0,0,0,0,0,0,2,2,2}, /*CT_CREATE*/ {2,2,2,2,1,1,1,0,0,0,0,0,0,2,2,0,0}, /*CT_UPDATE*/ {2,2,2,2,1,2,2,0,0,0,0,0,0,0,2,2,0}, /*CT_DELETE*/ {2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,2,0}, @@ -585,6 +585,8 @@ void usage(char *prog) { fprintf(stdout, "\n%s", usage_parameters); } +#define CT_COMPARISON (CT_OPT_PROTO | CT_OPT_ORIG | CT_OPT_REPL | CT_OPT_MARK) + static struct nfct_tuple orig, reply, mask; static struct nfct_tuple exptuple; static struct ctproto_handler *h; @@ -596,15 +598,17 @@ static unsigned long timeout; static unsigned int status; static unsigned int mark; static unsigned int id = NFCT_ANY_ID; +static struct nfct_conntrack_compare cmp; int main(int argc, char *argv[]) { char c; unsigned int command = 0, options = 0; unsigned int type = 0, event_mask = 0; - unsigned int l3flags = 0, l4flags = 0; + unsigned int l3flags = 0, l4flags = 0, metaflags = 0; int res = 0; int family = AF_UNSPEC; + struct nfct_conntrack_compare *pcmp; while ((c = getopt_long(argc, argv, "L::I::U::D::G::E::F::hVs:d:r:q:p:t:u:e:a:z[:]:{:}:m:i::f:", @@ -784,7 +788,9 @@ int main(int argc, char *argv[]) nat_parse(optarg, 1, &range); break; case 'm': + options |= CT_OPT_MARK; mark = atol(optarg); + metaflags |= NFCT_MARK; break; case 'i': { char *s = NULL; @@ -848,14 +854,33 @@ int main(int argc, char *argv[]) if (!cth) exit_error(OTHER_PROBLEM, "Can't open handler"); + if (options & CT_COMPARISON) { + + if (options & CT_OPT_ZERO) + exit_error(PARAMETER_PROBLEM, "Can't use -z " + "with filtering parameters"); + + ct = nfct_conntrack_alloc(&orig, &reply, timeout, + &proto, status, mark, id, + NULL); + if (!ct) + exit_error(OTHER_PROBLEM, "Not enough memory"); + + cmp.ct = ct; + cmp.flags = metaflags; + cmp.l3flags = l3flags; + cmp.l4flags = l4flags; + pcmp = &cmp; + } + if (options & CT_OPT_ID) nfct_register_callback(cth, nfct_default_conntrack_display_id, - NULL); + (void *) pcmp); else nfct_register_callback(cth, nfct_default_conntrack_display, - NULL); + (void *) pcmp); if (options & CT_OPT_ZERO) res = @@ -1036,11 +1061,6 @@ int main(int argc, char *argv[]) break; case CT_EVENT: - ct = nfct_conntrack_alloc(&orig, &reply, timeout, - &proto, status, mark, id, NULL); - if (!ct) - exit_error(OTHER_PROBLEM, "Not enough memory"); - if (options & CT_OPT_EVENT_MASK) cth = nfct_open(CONNTRACK, event_mask); else @@ -1050,20 +1070,23 @@ int main(int argc, char *argv[]) exit_error(OTHER_PROBLEM, "Can't open handler"); signal(SIGINT, event_sighandler); - if (options & (CT_OPT_PROTO | CT_OPT_ORIG | CT_OPT_REPL)) { - struct nfct_conntrack_compare cmp = { - .ct = ct, - .flags = 0, - .l3flags = l3flags, - .l4flags = l4flags - }; - nfct_register_callback(cth, - nfct_default_conntrack_event_display, - (void *)&cmp); - } else { - nfct_register_callback(cth, - nfct_default_conntrack_event_display, NULL); + if (options & CT_COMPARISON) { + ct = nfct_conntrack_alloc(&orig, &reply, timeout, + &proto, status, mark, id, + NULL); + if (!ct) + exit_error(OTHER_PROBLEM, "Not enough memory"); + + cmp.ct = ct; + cmp.flags = metaflags; + cmp.l3flags = l3flags; + cmp.l4flags = l4flags; + pcmp = &cmp; } + + nfct_register_callback(cth, + nfct_default_conntrack_event_display, + (void *) pcmp); res = nfct_event_conntrack(cth); nfct_close(cth); break; -- cgit v1.2.3 From 57c6018af541da18c8b750b4ceb2894a1dd37a2f Mon Sep 17 00:00:00 2001 From: "/C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=laforge/emailAddress=laforge@netfilter.org" Date: Mon, 22 May 2006 20:10:22 +0000 Subject: [PATCH] conntrack: Fix option parsing for ARM (Philip Craig ) The result of getopt_long() was assigned to a char, which defaults to unsigned --- src/conntrack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index 2105561..3e0643c 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -602,7 +602,7 @@ static struct nfct_conntrack_compare cmp; int main(int argc, char *argv[]) { - char c; + int c; unsigned int command = 0, options = 0; unsigned int type = 0, event_mask = 0; unsigned int l3flags = 0, l4flags = 0, metaflags = 0; -- cgit v1.2.3 From c27661b3dc89496052e4d9e5a0830f828475ac5a Mon Sep 17 00:00:00 2001 From: "/C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=kaber/emailAddress=kaber@netfilter.org" Date: Mon, 3 Jul 2006 18:34:50 +0000 Subject: [PATCH]: Userspace code related to fixed timeout patch (Eric Leblond ) --- src/conntrack.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index 3e0643c..9181410 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -335,13 +335,13 @@ err2str(int err, enum action command) #define PARSE_MAX 2 static struct parse_parameter { - char *parameter[5]; + char *parameter[6]; size_t size; - unsigned int value[5]; + unsigned int value[6]; } parse_array[PARSE_MAX] = { - { {"ASSURED", "SEEN_REPLY", "UNSET", "SRC_NAT", "DST_NAT"}, 5, + { {"ASSURED", "SEEN_REPLY", "UNSET", "SRC_NAT", "DST_NAT","FIXED_TIMEOUT"}, 6, { IPS_ASSURED, IPS_SEEN_REPLY, 0, - IPS_SRC_NAT_DONE, IPS_DST_NAT_DONE} }, + IPS_SRC_NAT_DONE, IPS_DST_NAT_DONE, IPS_FIXED_TIMEOUT} }, { {"ALL", "NEW", "UPDATES", "DESTROY"}, 4, {~0U, NF_NETLINK_CONNTRACK_NEW, NF_NETLINK_CONNTRACK_UPDATE, NF_NETLINK_CONNTRACK_DESTROY} }, -- cgit v1.2.3 From 42755eefea4ffcc2b160468f3a1a6fc575d5061a Mon Sep 17 00:00:00 2001 From: "/C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=kaber/emailAddress=kaber@netfilter.org" Date: Thu, 3 Aug 2006 10:37:00 +0000 Subject: [PATCH 5/6] conntrack pkt-config changes (KOVACS Krisztian ) --- configure.in | 37 +++++++++++-------------------------- src/Makefile.am | 4 ++-- 2 files changed, 13 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/configure.in b/configure.in index 2692b67..1b1b391 100644 --- a/configure.in +++ b/configure.in @@ -3,7 +3,6 @@ AC_INIT AC_CANONICAL_SYSTEM AM_INIT_AUTOMAKE(conntrack, 1.00beta2) -#AM_CONFIG_HEADER(config.h) AC_PROG_CC AM_PROG_LIBTOOL @@ -15,14 +14,14 @@ case $target in *) AC_MSG_ERROR([Linux only, dude!]);; esac -# Checks for libraries. -# FIXME: Replace `main' with a function in `-lc': -dnl AC_CHECK_LIB([c], [main]) -# FIXME: Replace `main' with a function in `-ldl': - -AC_CHECK_LIB([dl], [dlopen]) -AC_CHECK_LIB([netfilter_conntrack], [nfct_dump_conntrack_table] ,,,[-lnetfilter_conntrack]) +dnl Dependencies +LIBNFCONNTRACK_REQUIRED=0.0.31 + +AC_CHECK_LIB(dl, dlopen) +PKG_CHECK_MODULES(LIBNFCONNTRACK, libnetfilter_conntrack >= $LIBNFCONNTRACK_REQUIRED,, + AC_MSG_ERROR(Cannot find libnetfilter_conntrack >= $LIBNFCONNTRACK_REQUIRED)) + AC_CHECK_HEADERS(arpa/inet.h) dnl check for inet_pton AC_CHECK_FUNCS(inet_pton) @@ -56,19 +55,6 @@ int main() ], AC_MSG_RESULT(no), AC_MSG_RESULT(no)) fi -# Checks for header files. -dnl AC_HEADER_STDC -dnl AC_CHECK_HEADERS([netinet/in.h stdlib.h]) - -# Checks for typedefs, structures, and compiler characteristics. -dnl AC_C_CONST -dnl AC_C_INLINE - -# Checks for library functions. -dnl AC_FUNC_MALLOC -dnl AC_FUNC_VPRINTF -dnl AC_CHECK_FUNCS([memset]) - dnl-------------------------------- if test ! -z "$libdir"; then @@ -78,10 +64,9 @@ fi dnl-------------------------------- -dnl AC_CONFIG_FILES([Makefile -dnl debug/Makefile -dnl debug/src/Makefile -dnl extensions/Makefile -dnl src/Makefile]) +CFLAGS="$CFLAGS $LIBNFCONNTRACK_CFLAGS" +CONNTRACK_LIBS="$LIBNFCONNTRACK_LIBS" + +AC_SUBST(CONNTRACK_LIBS) AC_OUTPUT(Makefile src/Makefile extensions/Makefile include/Makefile) diff --git a/src/Makefile.am b/src/Makefile.am index 0dfd3b8..ebe370c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,7 +1,7 @@ include $(top_srcdir)/Make_global.am +LIBS = @CONNTRACK_LIBS@ sbin_PROGRAMS = conntrack conntrack_SOURCES = conntrack.c - -conntrack_LDFLAGS = $(all_libraries) -rdynamic -lnetfilter_conntrack +#conntrack_LDFLAGS = $(all_libraries) -rdynamic -- cgit v1.2.3 From 3ba870417a7bf07c87b496fc22459c3b2c986783 Mon Sep 17 00:00:00 2001 From: "/C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=kaber/emailAddress=kaber@netfilter.org" Date: Fri, 16 Mar 2007 15:07:53 +0000 Subject: [patch] conntrack compile fix (Thomas Jarosch ) --- src/conntrack.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index 9181410..30fbf69 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -48,6 +48,7 @@ #endif #include #include +#include #include #include "linux_list.h" #include "conntrack.h" -- cgit v1.2.3 From 13e6cab49dc2716c3e58eda12eed2fbab24be59b Mon Sep 17 00:00:00 2001 From: "/C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=kaber/emailAddress=kaber@netfilter.org" Date: Fri, 16 Mar 2007 17:53:26 +0000 Subject: [patch] conntrack tool: Fix loading of protocol helpers (Thomas Jarosch ) the pkgconfig changes from August 2006 broke the loading of the protocol helpers as dlopen() doesn't search for symbols in the main executable. As a result the protocol helpers can't find register_proto(). Attached patch fixes the problem. --- src/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index ebe370c..83cad99 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -3,5 +3,5 @@ LIBS = @CONNTRACK_LIBS@ sbin_PROGRAMS = conntrack conntrack_SOURCES = conntrack.c -#conntrack_LDFLAGS = $(all_libraries) -rdynamic +conntrack_LDFLAGS = -rdynamic -- cgit v1.2.3 From ad31f852c3454136bdbfeb7f222cb9c175f13c1c Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Mon, 16 Apr 2007 17:55:00 +0000 Subject: initial import of the conntrack daemon to Netfilter SVN --- AUTHORS | 2 - ChangeLog | 243 ----- INSTALL | 229 ---- Make_global.am | 1 - Makefile.am | 21 - README | 17 + autogen.sh | 18 - cli/AUTHORS | 2 + cli/ChangeLog | 243 +++++ cli/INSTALL | 229 ++++ cli/Make_global.am | 1 + cli/Makefile.am | 21 + cli/autogen.sh | 18 + cli/configure.in | 72 ++ cli/conntrack.8 | 142 +++ cli/extensions/Makefile.am | 16 + cli/extensions/libct_proto_icmp.c | 108 ++ cli/extensions/libct_proto_icmp.man | 10 + cli/extensions/libct_proto_sctp.c | 164 +++ cli/extensions/libct_proto_tcp.c | 180 ++++ cli/extensions/libct_proto_tcp.man | 16 + cli/extensions/libct_proto_udp.c | 141 +++ cli/extensions/libct_proto_udp.man | 13 + cli/include/Makefile.am | 2 + cli/include/conntrack.h | 160 +++ cli/include/linux_list.h | 725 +++++++++++++ cli/src/Makefile.am | 7 + cli/src/conntrack.c | 1131 ++++++++++++++++++++ cli/test.sh | 110 ++ configure.in | 72 -- conntrack.8 | 142 --- daemon/AUTHORS | 1 + daemon/CHANGELOG | 184 ++++ daemon/CONTRIBUTORS | 3 + daemon/INSTALL | 199 ++++ daemon/Make_global.am | 1 + daemon/Makefile.am | 21 + daemon/TODO | 18 + daemon/autogen.sh | 18 + daemon/configure.in | 106 ++ daemon/examples/Makefile.am | 1 + daemon/examples/debian.conntrackd.init.d | 48 + daemon/examples/stats/Makefile.am | 1 + daemon/examples/stats/conntrackd.conf | 69 ++ daemon/examples/sync/Makefile.am | 1 + daemon/examples/sync/nack/Makefile.am | 2 + daemon/examples/sync/nack/README | 1 + daemon/examples/sync/nack/node1/Makefile.am | 1 + daemon/examples/sync/nack/node1/conntrackd.conf | 125 +++ daemon/examples/sync/nack/node1/keepalived.conf | 38 + daemon/examples/sync/nack/node2/Makefile.am | 1 + daemon/examples/sync/nack/node2/conntrackd.conf | 124 +++ daemon/examples/sync/nack/node2/keepalived.conf | 38 + daemon/examples/sync/nack/script_backup.sh | 3 + daemon/examples/sync/nack/script_master.sh | 5 + daemon/examples/sync/persistent/Makefile.am | 2 + daemon/examples/sync/persistent/README | 1 + daemon/examples/sync/persistent/node1/Makefile.am | 1 + .../examples/sync/persistent/node1/conntrackd.conf | 130 +++ .../examples/sync/persistent/node1/keepalived.conf | 38 + daemon/examples/sync/persistent/node2/Makefile.am | 1 + .../examples/sync/persistent/node2/conntrackd.conf | 130 +++ .../examples/sync/persistent/node2/keepalived.conf | 38 + daemon/examples/sync/persistent/script_backup.sh | 3 + daemon/examples/sync/persistent/script_master.sh | 4 + daemon/include/Makefile.am | 5 + daemon/include/alarm.h | 13 + daemon/include/buffer.h | 32 + daemon/include/cache.h | 92 ++ daemon/include/conntrackd.h | 174 +++ daemon/include/debug.h | 53 + daemon/include/hash.h | 47 + daemon/include/ignore.h | 12 + daemon/include/jhash.h | 146 +++ daemon/include/linux_list.h | 725 +++++++++++++ daemon/include/local.h | 29 + daemon/include/log.h | 10 + daemon/include/mcast.h | 48 + daemon/include/network.h | 34 + daemon/include/slist.h | 41 + daemon/include/state_helper.h | 20 + daemon/include/sync.h | 23 + daemon/include/us-conntrack.h | 13 + daemon/src/Makefile.am | 22 + daemon/src/alarm.c | 141 +++ daemon/src/buffer.c | 136 +++ daemon/src/cache.c | 446 ++++++++ daemon/src/cache_iterators.c | 229 ++++ daemon/src/cache_lifetime.c | 65 ++ daemon/src/cache_timer.c | 72 ++ daemon/src/checksum.c | 32 + daemon/src/hash.c | 199 ++++ daemon/src/ignore_pool.c | 136 +++ daemon/src/local.c | 159 +++ daemon/src/lock.c | 32 + daemon/src/log.c | 57 + daemon/src/main.c | 302 ++++++ daemon/src/mcast.c | 287 +++++ daemon/src/netlink.c | 326 ++++++ daemon/src/network.c | 282 +++++ daemon/src/proxy.c | 124 +++ daemon/src/read_config_lex.l | 125 +++ daemon/src/read_config_yy.y | 550 ++++++++++ daemon/src/run.c | 227 ++++ daemon/src/state_helper.c | 44 + daemon/src/state_helper_tcp.c | 35 + daemon/src/stats-mode.c | 151 +++ daemon/src/sync-mode.c | 416 +++++++ daemon/src/sync-nack.c | 309 ++++++ daemon/src/sync-notrack.c | 127 +++ daemon/src/traffic_stats.c | 54 + extensions/Makefile.am | 16 - extensions/libct_proto_icmp.c | 108 -- extensions/libct_proto_icmp.man | 10 - extensions/libct_proto_sctp.c | 164 --- extensions/libct_proto_tcp.c | 180 ---- extensions/libct_proto_tcp.man | 16 - extensions/libct_proto_udp.c | 141 --- extensions/libct_proto_udp.man | 13 - include/Makefile.am | 2 - include/conntrack.h | 160 --- include/linux_list.h | 725 ------------- src/Makefile.am | 7 - src/conntrack.c | 1131 -------------------- test.sh | 110 -- 125 files changed, 11487 insertions(+), 3511 deletions(-) delete mode 100644 AUTHORS delete mode 100644 ChangeLog delete mode 100644 INSTALL delete mode 100644 Make_global.am delete mode 100644 Makefile.am create mode 100644 README delete mode 100755 autogen.sh create mode 100644 cli/AUTHORS create mode 100644 cli/ChangeLog create mode 100644 cli/INSTALL create mode 100644 cli/Make_global.am create mode 100644 cli/Makefile.am create mode 100755 cli/autogen.sh create mode 100644 cli/configure.in create mode 100644 cli/conntrack.8 create mode 100644 cli/extensions/Makefile.am create mode 100644 cli/extensions/libct_proto_icmp.c create mode 100644 cli/extensions/libct_proto_icmp.man create mode 100644 cli/extensions/libct_proto_sctp.c create mode 100644 cli/extensions/libct_proto_tcp.c create mode 100644 cli/extensions/libct_proto_tcp.man create mode 100644 cli/extensions/libct_proto_udp.c create mode 100644 cli/extensions/libct_proto_udp.man create mode 100644 cli/include/Makefile.am create mode 100644 cli/include/conntrack.h create mode 100644 cli/include/linux_list.h create mode 100644 cli/src/Makefile.am create mode 100644 cli/src/conntrack.c create mode 100644 cli/test.sh delete mode 100644 configure.in delete mode 100644 conntrack.8 create mode 100644 daemon/AUTHORS create mode 100644 daemon/CHANGELOG create mode 100644 daemon/CONTRIBUTORS create mode 100644 daemon/INSTALL create mode 100644 daemon/Make_global.am create mode 100644 daemon/Makefile.am create mode 100644 daemon/TODO create mode 100755 daemon/autogen.sh create mode 100644 daemon/configure.in create mode 100644 daemon/examples/Makefile.am create mode 100644 daemon/examples/debian.conntrackd.init.d create mode 100644 daemon/examples/stats/Makefile.am create mode 100644 daemon/examples/stats/conntrackd.conf create mode 100644 daemon/examples/sync/Makefile.am create mode 100644 daemon/examples/sync/nack/Makefile.am create mode 100644 daemon/examples/sync/nack/README create mode 100644 daemon/examples/sync/nack/node1/Makefile.am create mode 100644 daemon/examples/sync/nack/node1/conntrackd.conf create mode 100644 daemon/examples/sync/nack/node1/keepalived.conf create mode 100644 daemon/examples/sync/nack/node2/Makefile.am create mode 100644 daemon/examples/sync/nack/node2/conntrackd.conf create mode 100644 daemon/examples/sync/nack/node2/keepalived.conf create mode 100755 daemon/examples/sync/nack/script_backup.sh create mode 100755 daemon/examples/sync/nack/script_master.sh create mode 100644 daemon/examples/sync/persistent/Makefile.am create mode 100644 daemon/examples/sync/persistent/README create mode 100644 daemon/examples/sync/persistent/node1/Makefile.am create mode 100644 daemon/examples/sync/persistent/node1/conntrackd.conf create mode 100644 daemon/examples/sync/persistent/node1/keepalived.conf create mode 100644 daemon/examples/sync/persistent/node2/Makefile.am create mode 100644 daemon/examples/sync/persistent/node2/conntrackd.conf create mode 100644 daemon/examples/sync/persistent/node2/keepalived.conf create mode 100755 daemon/examples/sync/persistent/script_backup.sh create mode 100755 daemon/examples/sync/persistent/script_master.sh create mode 100644 daemon/include/Makefile.am create mode 100644 daemon/include/alarm.h create mode 100644 daemon/include/buffer.h create mode 100644 daemon/include/cache.h create mode 100644 daemon/include/conntrackd.h create mode 100644 daemon/include/debug.h create mode 100644 daemon/include/hash.h create mode 100644 daemon/include/ignore.h create mode 100644 daemon/include/jhash.h create mode 100644 daemon/include/linux_list.h create mode 100644 daemon/include/local.h create mode 100644 daemon/include/log.h create mode 100644 daemon/include/mcast.h create mode 100644 daemon/include/network.h create mode 100644 daemon/include/slist.h create mode 100644 daemon/include/state_helper.h create mode 100644 daemon/include/sync.h create mode 100644 daemon/include/us-conntrack.h create mode 100644 daemon/src/Makefile.am create mode 100644 daemon/src/alarm.c create mode 100644 daemon/src/buffer.c create mode 100644 daemon/src/cache.c create mode 100644 daemon/src/cache_iterators.c create mode 100644 daemon/src/cache_lifetime.c create mode 100644 daemon/src/cache_timer.c create mode 100644 daemon/src/checksum.c create mode 100644 daemon/src/hash.c create mode 100644 daemon/src/ignore_pool.c create mode 100644 daemon/src/local.c create mode 100644 daemon/src/lock.c create mode 100644 daemon/src/log.c create mode 100644 daemon/src/main.c create mode 100644 daemon/src/mcast.c create mode 100644 daemon/src/netlink.c create mode 100644 daemon/src/network.c create mode 100644 daemon/src/proxy.c create mode 100644 daemon/src/read_config_lex.l create mode 100644 daemon/src/read_config_yy.y create mode 100644 daemon/src/run.c create mode 100644 daemon/src/state_helper.c create mode 100644 daemon/src/state_helper_tcp.c create mode 100644 daemon/src/stats-mode.c create mode 100644 daemon/src/sync-mode.c create mode 100644 daemon/src/sync-nack.c create mode 100644 daemon/src/sync-notrack.c create mode 100644 daemon/src/traffic_stats.c delete mode 100644 extensions/Makefile.am delete mode 100644 extensions/libct_proto_icmp.c delete mode 100644 extensions/libct_proto_icmp.man delete mode 100644 extensions/libct_proto_sctp.c delete mode 100644 extensions/libct_proto_tcp.c delete mode 100644 extensions/libct_proto_tcp.man delete mode 100644 extensions/libct_proto_udp.c delete mode 100644 extensions/libct_proto_udp.man delete mode 100644 include/Makefile.am delete mode 100644 include/conntrack.h delete mode 100644 include/linux_list.h delete mode 100644 src/Makefile.am delete mode 100644 src/conntrack.c delete mode 100644 test.sh (limited to 'src') diff --git a/AUTHORS b/AUTHORS deleted file mode 100644 index d1cb6fa..0000000 --- a/AUTHORS +++ /dev/null @@ -1,2 +0,0 @@ -Pablo Neira Ayuso -Harald Welte diff --git a/ChangeLog b/ChangeLog deleted file mode 100644 index 1524ef6..0000000 --- a/ChangeLog +++ /dev/null @@ -1,243 +0,0 @@ -2006-03-20 - - o fix ICMP protocol extension parse callback - -2006-01-15 - - o Added missing parameters to set the ports of an expectation tuple - o Add support to filter dumped entries. - ie: conntrack -L -p tcp --orig-port-dst 993 - display all the connections to IMAPS servers - conntrack -L -m 2 - display all the connection marked with 2 - o Bumped version to 1.00beta2 - -2005-12-26 - - o add IPv6 support: main change - o removed dead code: iptables_insmod and get_modprobe - o compact the commands vs. options table - o move working vars from the stack to the BSS section - o update manpage - o Bumped version to 1.0beta1 - - o check address family mismatch - o fix incomplete copying IPv6 addresses - -2005-12-19 - - o We only support ipv4 at the moment: set l3protonum to AF_INET - o Minor changes to prepare upcoming ipv6 support - -2005-12-03 - - o Add support to filter events. ie: -p tcp --orig-port-dst 80 in - conjuction with -E to get all the requests to HTTP servers - o Update manpage - o Missing static function declaration in the protocol handlers - o Use protocol flags defined in libnetfilter_conntrack - o Bumped version to 0.991 - -2005-11-22 - - o Fix oversized number of options - -2005-11-11 - - o don't check for kernel header path in configure, since we don't use - kernel headers - o don't check for libnfnetlink, we don't use it directly - o move plugins into pkglibdir - o remove 'lib' prefix of plugins, they're not really libraries - o remove version information from plugin filenames - o Bumped version to 0.99 -2005-11-09 - - o set status to zero, libnetfilter_conntrack now activate - IPS_CONFIRMED since all conntrack in hash must be confirmed. - o Bumped version to 0.98 - -2005-11-08 - - o Fix warnings generated by gcc -Wall - o Fix conntrack exit value at error - o Replace obsolete inet_addr by inet_aton - -2005-11-05 - - o Improved conntrack -h output - o add htons for icmp id. - - o -t and -u are optional at update. - o Fixed versioning :( - o Bumped version to 0.97 - -2005-11-03 - - o Use extra 'data' argument of nfct_register_callback() function that - I've introduced in libetfilter_conntrack. - - o moves conntrack tool from bin to sbin directory since this - application is an administration utility and it requires uid==0 or - CAP_NET_ADMIN - - o check if --state missing when -p is passed - o command type is passed to final_check: checkings based on the - command can be done now. - o kill duplicated definition of IPS_* bits: Already present in - libnetfilter_conntrack. - o Move action and command enum to conntrack.h - o kill NIPQUAD macro - o make conntrack handler cth static. - o Bumped version to 0.96 - -2005-11-01 - - o Fix error message describing illegal option -E -i - o -D -i ID requires tuple information: Display an error message - o Use NFCT_ALL_CT_GROUPS flag instead of NFCT_ALL_GROUPS - o Event mask doesn't make sense for expectations, kill dead code - o Bumped version to 0.95 - - o Fix wrong formating in conntrack -h - -2005-10-30 - - Special thanks to Deti Fiegl from the Leibniz Supercomputing Centre in - Munich, Germany for providing the "fast" hardware to reproduce - spurious bugs ;) - - o Replace misleading message "Not enough memory" by "Can't open handler" - o New option -i for expectation dumping: conntrack -L expect [-i] - o sed 's/VERSION/CONNTRACK_VERSION/g' - o Fix nfct_open flags, now uses NFCT_ALL_GROUPS when needed - o Bumped version to 0.94 - -2005-10-28 - - o New option -i for dumping: conntrack -L [-i] - o Fixed warning in findproto due to a stupid wrong type definition - o sed 's/nfct_set_callback/nfct_register_callback/g' - o killed the 'retry' logic, *sigh* it is broken in some cases - o killed broken and unneeded protocol handler destructors (fini) - o killed unregister_proto - o Fixed code indentation in the command selector - o Bumped version to 0.93 - -2005-10-27 - - o Use conntrack VERSION instead of the old LIBCT_VERSION - o proto_list and lib_dir are now static - o kill dead code: function dump_tuple - o Bumped version to 0.92 - -2005-10-25 - - o Add missing autogen.sh file - -2005-10-24 - - o use NFCT_ANY_GROUP flag in nfct_open() - -2005-10-21 - - o Bumped version to 0.90 - o Add support for id and marks - -2005-10-20 - - o Kill some more files that generated by the autocrap - o Resync with the lastest libnetfilter_conntrack API changes - -2005-10-16 - - o Rename libct_proto.h to conntrack.h - o Remove config.h.in from svn, it's autogenerated by the autocrap :) - o Remove dead functions in the SCTP protocol helper - -2005-10-14 - - o Kill config.h.in, it's generated by the autocrap - o The conntrack tool now uses libnetfilter_conntrack :) - o libct.c has been killed, now it's in libnetfilter_conntrack - o Check if you're root or CAP_NET_ADMIN - o Bumped version number to 0.86 - -2005-10-07 - - o Fixed ICMP options - - o Multiple fixes for the ICMP protocol handler - o Fix ICMP output: wrong output. type and code were set to zero. - -2005-10-05 - - o Fix up counters - o Fix up compilation (IPS_* stuff missing), still need a proper fix - o Bumped version number to 0.82 - -2005-09-24 - - o Get rid of C++ style comments - o Remove remaining bits of "-A --action", group-mask and dump-mask - o Clean up #include's - o Fix double-free when exiting via signal handler (Ctrl+C) - o Add "version" member to plugins - o Fix some Endianness issues when printing CTA_STATUS - -2005-08-31 - - o Fix packet and bytes counters (use __be64_to_cpu) - o Fix ip_conntrack_netlink load-on-demand - -2005-07-12 - - o Use conntrack netlink attributes: Major change - o Kill action setting: Mask based dumping - o Fix ChangeLog - -2005-05-23 - - o Fixed syntax error (tab/space issue) in help message - o Fixed getopt handling on big endian machines - o Fixed possible future read-over-end-of-array in TCP extension - o Add manpage - o Add missing space at output of libct_proto_icmp.c - o Add status bits that were introduced in 2.6.11 - o Add SCTP extension - o Add support for expect creation - o Bump version number to 0.63 - -2005-05-17 - - o Added descriptive error messages. - o Fix wrong flags check in [tcp|udp] proto helpers. - -2005-05-16 - - o Implemented ICMP proto helper - o Added help() and final_check() functions for proto helpers. - -2005-05-01 - - o Created changelog file - o Deleted libctnetlink.h and libnfnetlink.h from the include/ dir. - o Added support for version (-V) and help (-h) - o Added event mask based support - o Added GPLv2 headers - o Use fprintf instead of printf - o Defined print_tuple and print_proto output interfaces - o ctnl_[get|del]_conntrack handles return value from kernel via msgerr - o Added support for conntrack table flushing - o Added test case file (test.sh) - o Improve dump output - - - o Autoconf stuff for conntrack + some pablo's modifications. - o Fixed packet counters formatting (use %llu instead of %lu) - -2005-04-25 - - o Added support for mask based event dumping - o Added support for mask based event notification - o On-demand autoload of ip_conntrack_netlink diff --git a/INSTALL b/INSTALL deleted file mode 100644 index 54caf7c..0000000 --- a/INSTALL +++ /dev/null @@ -1,229 +0,0 @@ -Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software -Foundation, Inc. - - This file is free documentation; the Free Software Foundation gives -unlimited permission to copy, distribute and modify it. - -Basic Installation -================== - - These are generic installation instructions. - - The `configure' shell script attempts to guess correct values for -various system-dependent variables used during compilation. It uses -those values to create a `Makefile' in each directory of the package. -It may also create one or more `.h' files containing system-dependent -definitions. Finally, it creates a shell script `config.status' that -you can run in the future to recreate the current configuration, and a -file `config.log' containing compiler output (useful mainly for -debugging `configure'). - - It can also use an optional file (typically called `config.cache' -and enabled with `--cache-file=config.cache' or simply `-C') that saves -the results of its tests to speed up reconfiguring. (Caching is -disabled by default to prevent problems with accidental use of stale -cache files.) - - If you need to do unusual things to compile the package, please try -to figure out how `configure' could check whether to do them, and mail -diffs or instructions to the address given in the `README' so they can -be considered for the next release. If you are using the cache, and at -some point `config.cache' contains results you don't want to keep, you -may remove or edit it. - - The file `configure.ac' (or `configure.in') is used to create -`configure' by a program called `autoconf'. You only need -`configure.ac' if you want to change it or regenerate `configure' using -a newer version of `autoconf'. - -The simplest way to compile this package is: - - 1. `cd' to the directory containing the package's source code and type - `./configure' to configure the package for your system. If you're - using `csh' on an old version of System V, you might need to type - `sh ./configure' instead to prevent `csh' from trying to execute - `configure' itself. - - Running `configure' takes awhile. While running, it prints some - messages telling which features it is checking for. - - 2. Type `make' to compile the package. - - 3. Optionally, type `make check' to run any self-tests that come with - the package. - - 4. Type `make install' to install the programs and any data files and - documentation. - - 5. You can remove the program binaries and object files from the - source code directory by typing `make clean'. To also remove the - files that `configure' created (so you can compile the package for - a different kind of computer), type `make distclean'. There is - also a `make maintainer-clean' target, but that is intended mainly - for the package's developers. If you use it, you may have to get - all sorts of other programs in order to regenerate files that came - with the distribution. - -Compilers and Options -===================== - - Some systems require unusual options for compilation or linking that -the `configure' script does not know about. Run `./configure --help' -for details on some of the pertinent environment variables. - - You can give `configure' initial values for configuration parameters -by setting variables in the command line or in the environment. Here -is an example: - - ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix - - *Note Defining Variables::, for more details. - -Compiling For Multiple Architectures -==================================== - - You can compile the package for more than one kind of computer at the -same time, by placing the object files for each architecture in their -own directory. To do this, you must use a version of `make' that -supports the `VPATH' variable, such as GNU `make'. `cd' to the -directory where you want the object files and executables to go and run -the `configure' script. `configure' automatically checks for the -source code in the directory that `configure' is in and in `..'. - - If you have to use a `make' that does not support the `VPATH' -variable, you have to compile the package for one architecture at a -time in the source code directory. After you have installed the -package for one architecture, use `make distclean' before reconfiguring -for another architecture. - -Installation Names -================== - - By default, `make install' will install the package's files in -`/usr/local/bin', `/usr/local/man', etc. You can specify an -installation prefix other than `/usr/local' by giving `configure' the -option `--prefix=PATH'. - - You can specify separate installation prefixes for -architecture-specific files and architecture-independent files. If you -give `configure' the option `--exec-prefix=PATH', the package will use -PATH as the prefix for installing programs and libraries. -Documentation and other data files will still use the regular prefix. - - In addition, if you use an unusual directory layout you can give -options like `--bindir=PATH' to specify different values for particular -kinds of files. Run `configure --help' for a list of the directories -you can set and what kinds of files go in them. - - If the package supports it, you can cause programs to be installed -with an extra prefix or suffix on their names by giving `configure' the -option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. - -Optional Features -================= - - Some packages pay attention to `--enable-FEATURE' options to -`configure', where FEATURE indicates an optional part of the package. -They may also pay attention to `--with-PACKAGE' options, where PACKAGE -is something like `gnu-as' or `x' (for the X Window System). The -`README' should mention any `--enable-' and `--with-' options that the -package recognizes. - - For packages that use the X Window System, `configure' can usually -find the X include and library files automatically, but if it doesn't, -you can use the `configure' options `--x-includes=DIR' and -`--x-libraries=DIR' to specify their locations. - -Specifying the System Type -========================== - - There may be some features `configure' cannot figure out -automatically, but needs to determine by the type of machine the package -will run on. Usually, assuming the package is built to be run on the -_same_ architectures, `configure' can figure that out, but if it prints -a message saying it cannot guess the machine type, give it the -`--build=TYPE' option. TYPE can either be a short name for the system -type, such as `sun4', or a canonical name which has the form: - - CPU-COMPANY-SYSTEM - -where SYSTEM can have one of these forms: - - OS KERNEL-OS - - See the file `config.sub' for the possible values of each field. If -`config.sub' isn't included in this package, then this package doesn't -need to know the machine type. - - If you are _building_ compiler tools for cross-compiling, you should -use the `--target=TYPE' option to select the type of system they will -produce code for. - - If you want to _use_ a cross compiler, that generates code for a -platform different from the build platform, you should specify the -"host" platform (i.e., that on which the generated programs will -eventually be run) with `--host=TYPE'. - -Sharing Defaults -================ - - If you want to set default values for `configure' scripts to share, -you can create a site shell script called `config.site' that gives -default values for variables like `CC', `cache_file', and `prefix'. -`configure' looks for `PREFIX/share/config.site' if it exists, then -`PREFIX/etc/config.site' if it exists. Or, you can set the -`CONFIG_SITE' environment variable to the location of the site script. -A warning: not all `configure' scripts look for a site script. - -Defining Variables -================== - - Variables not defined in a site shell script can be set in the -environment passed to `configure'. However, some packages may run -configure again during the build, and the customized values of these -variables may be lost. In order to avoid this problem, you should set -them in the `configure' command line, using `VAR=value'. For example: - - ./configure CC=/usr/local2/bin/gcc - -will cause the specified gcc to be used as the C compiler (unless it is -overridden in the site shell script). - -`configure' Invocation -====================== - - `configure' recognizes the following options to control how it -operates. - -`--help' -`-h' - Print a summary of the options to `configure', and exit. - -`--version' -`-V' - Print the version of Autoconf used to generate the `configure' - script, and exit. - -`--cache-file=FILE' - Enable the cache: use and save the results of the tests in FILE, - traditionally `config.cache'. FILE defaults to `/dev/null' to - disable caching. - -`--config-cache' -`-C' - Alias for `--cache-file=config.cache'. - -`--quiet' -`--silent' -`-q' - Do not print messages saying which checks are being made. To - suppress all normal output, redirect it to `/dev/null' (any error - messages will still be shown). - -`--srcdir=DIR' - Look for the package's source code in directory DIR. Usually - `configure' can determine that directory automatically. - -`configure' also accepts some other, not widely useful, options. Run -`configure --help' for more details. - diff --git a/Make_global.am b/Make_global.am deleted file mode 100644 index 685add7..0000000 --- a/Make_global.am +++ /dev/null @@ -1 +0,0 @@ -INCLUDES=$(all_includes) -I$(top_srcdir)/include diff --git a/Makefile.am b/Makefile.am deleted file mode 100644 index d3b4ceb..0000000 --- a/Makefile.am +++ /dev/null @@ -1,21 +0,0 @@ -include Make_global.am - -# not a GNU package. You can remove this line, if -# have all needed files, that a GNU package needs -AUTOMAKE_OPTIONS = foreign dist-bzip2 1.6 - -man_MANS = conntrack.8 - -EXTRA_DIST = $(man_MANS) Make_global.am debian - -SUBDIRS = src extensions -DIST_SUBDIRS = include src extensions -LINKOPTS = -ldl -lnetfilter_conntrack -AM_CFLAGS = -g - -$(OBJECTS): libtool -libtool: $(LIBTOOL_DEPS) - $(SHELL) ./config.status --recheck - -dist-hook: - rm -rf `find $(distdir)/debian -name .svn` diff --git a/README b/README new file mode 100644 index 0000000..314a2e4 --- /dev/null +++ b/README @@ -0,0 +1,17 @@ +This package contains two subdirectories: + +cli (command line interface) +============================ +This subdirectory contains the command line tool `conntrack' that provides an +userspace interface to the connection tracking system. This tool let system +administrators perform different actions against the connection tracking +table. For more information see the manpage conntrack(8). + +daemon +====== +This subdirectory contains the userspace connection tracking daemon so-called +'conntrackd`. This daemon maintains a copy of the connection tracking table +in userspace. It is highly configurable and easily extensible. Currently it +covers the specific aspects of stateful GNU/Linux firewalls to enable high +availability solutions and can be used as statistics collector of the firewall +use. diff --git a/autogen.sh b/autogen.sh deleted file mode 100755 index e76d3ef..0000000 --- a/autogen.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/sh - -run () -{ - echo "running: $*" - eval $* - - if test $? != 0 ; then - echo "error: while running '$*'" - exit 1 - fi -} - -run aclocal -run libtoolize -f -#run autoheader -run automake -a -run autoconf diff --git a/cli/AUTHORS b/cli/AUTHORS new file mode 100644 index 0000000..d1cb6fa --- /dev/null +++ b/cli/AUTHORS @@ -0,0 +1,2 @@ +Pablo Neira Ayuso +Harald Welte diff --git a/cli/ChangeLog b/cli/ChangeLog new file mode 100644 index 0000000..1524ef6 --- /dev/null +++ b/cli/ChangeLog @@ -0,0 +1,243 @@ +2006-03-20 + + o fix ICMP protocol extension parse callback + +2006-01-15 + + o Added missing parameters to set the ports of an expectation tuple + o Add support to filter dumped entries. + ie: conntrack -L -p tcp --orig-port-dst 993 + display all the connections to IMAPS servers + conntrack -L -m 2 + display all the connection marked with 2 + o Bumped version to 1.00beta2 + +2005-12-26 + + o add IPv6 support: main change + o removed dead code: iptables_insmod and get_modprobe + o compact the commands vs. options table + o move working vars from the stack to the BSS section + o update manpage + o Bumped version to 1.0beta1 + + o check address family mismatch + o fix incomplete copying IPv6 addresses + +2005-12-19 + + o We only support ipv4 at the moment: set l3protonum to AF_INET + o Minor changes to prepare upcoming ipv6 support + +2005-12-03 + + o Add support to filter events. ie: -p tcp --orig-port-dst 80 in + conjuction with -E to get all the requests to HTTP servers + o Update manpage + o Missing static function declaration in the protocol handlers + o Use protocol flags defined in libnetfilter_conntrack + o Bumped version to 0.991 + +2005-11-22 + + o Fix oversized number of options + +2005-11-11 + + o don't check for kernel header path in configure, since we don't use + kernel headers + o don't check for libnfnetlink, we don't use it directly + o move plugins into pkglibdir + o remove 'lib' prefix of plugins, they're not really libraries + o remove version information from plugin filenames + o Bumped version to 0.99 +2005-11-09 + + o set status to zero, libnetfilter_conntrack now activate + IPS_CONFIRMED since all conntrack in hash must be confirmed. + o Bumped version to 0.98 + +2005-11-08 + + o Fix warnings generated by gcc -Wall + o Fix conntrack exit value at error + o Replace obsolete inet_addr by inet_aton + +2005-11-05 + + o Improved conntrack -h output + o add htons for icmp id. + + o -t and -u are optional at update. + o Fixed versioning :( + o Bumped version to 0.97 + +2005-11-03 + + o Use extra 'data' argument of nfct_register_callback() function that + I've introduced in libetfilter_conntrack. + + o moves conntrack tool from bin to sbin directory since this + application is an administration utility and it requires uid==0 or + CAP_NET_ADMIN + + o check if --state missing when -p is passed + o command type is passed to final_check: checkings based on the + command can be done now. + o kill duplicated definition of IPS_* bits: Already present in + libnetfilter_conntrack. + o Move action and command enum to conntrack.h + o kill NIPQUAD macro + o make conntrack handler cth static. + o Bumped version to 0.96 + +2005-11-01 + + o Fix error message describing illegal option -E -i + o -D -i ID requires tuple information: Display an error message + o Use NFCT_ALL_CT_GROUPS flag instead of NFCT_ALL_GROUPS + o Event mask doesn't make sense for expectations, kill dead code + o Bumped version to 0.95 + + o Fix wrong formating in conntrack -h + +2005-10-30 + + Special thanks to Deti Fiegl from the Leibniz Supercomputing Centre in + Munich, Germany for providing the "fast" hardware to reproduce + spurious bugs ;) + + o Replace misleading message "Not enough memory" by "Can't open handler" + o New option -i for expectation dumping: conntrack -L expect [-i] + o sed 's/VERSION/CONNTRACK_VERSION/g' + o Fix nfct_open flags, now uses NFCT_ALL_GROUPS when needed + o Bumped version to 0.94 + +2005-10-28 + + o New option -i for dumping: conntrack -L [-i] + o Fixed warning in findproto due to a stupid wrong type definition + o sed 's/nfct_set_callback/nfct_register_callback/g' + o killed the 'retry' logic, *sigh* it is broken in some cases + o killed broken and unneeded protocol handler destructors (fini) + o killed unregister_proto + o Fixed code indentation in the command selector + o Bumped version to 0.93 + +2005-10-27 + + o Use conntrack VERSION instead of the old LIBCT_VERSION + o proto_list and lib_dir are now static + o kill dead code: function dump_tuple + o Bumped version to 0.92 + +2005-10-25 + + o Add missing autogen.sh file + +2005-10-24 + + o use NFCT_ANY_GROUP flag in nfct_open() + +2005-10-21 + + o Bumped version to 0.90 + o Add support for id and marks + +2005-10-20 + + o Kill some more files that generated by the autocrap + o Resync with the lastest libnetfilter_conntrack API changes + +2005-10-16 + + o Rename libct_proto.h to conntrack.h + o Remove config.h.in from svn, it's autogenerated by the autocrap :) + o Remove dead functions in the SCTP protocol helper + +2005-10-14 + + o Kill config.h.in, it's generated by the autocrap + o The conntrack tool now uses libnetfilter_conntrack :) + o libct.c has been killed, now it's in libnetfilter_conntrack + o Check if you're root or CAP_NET_ADMIN + o Bumped version number to 0.86 + +2005-10-07 + + o Fixed ICMP options + + o Multiple fixes for the ICMP protocol handler + o Fix ICMP output: wrong output. type and code were set to zero. + +2005-10-05 + + o Fix up counters + o Fix up compilation (IPS_* stuff missing), still need a proper fix + o Bumped version number to 0.82 + +2005-09-24 + + o Get rid of C++ style comments + o Remove remaining bits of "-A --action", group-mask and dump-mask + o Clean up #include's + o Fix double-free when exiting via signal handler (Ctrl+C) + o Add "version" member to plugins + o Fix some Endianness issues when printing CTA_STATUS + +2005-08-31 + + o Fix packet and bytes counters (use __be64_to_cpu) + o Fix ip_conntrack_netlink load-on-demand + +2005-07-12 + + o Use conntrack netlink attributes: Major change + o Kill action setting: Mask based dumping + o Fix ChangeLog + +2005-05-23 + + o Fixed syntax error (tab/space issue) in help message + o Fixed getopt handling on big endian machines + o Fixed possible future read-over-end-of-array in TCP extension + o Add manpage + o Add missing space at output of libct_proto_icmp.c + o Add status bits that were introduced in 2.6.11 + o Add SCTP extension + o Add support for expect creation + o Bump version number to 0.63 + +2005-05-17 + + o Added descriptive error messages. + o Fix wrong flags check in [tcp|udp] proto helpers. + +2005-05-16 + + o Implemented ICMP proto helper + o Added help() and final_check() functions for proto helpers. + +2005-05-01 + + o Created changelog file + o Deleted libctnetlink.h and libnfnetlink.h from the include/ dir. + o Added support for version (-V) and help (-h) + o Added event mask based support + o Added GPLv2 headers + o Use fprintf instead of printf + o Defined print_tuple and print_proto output interfaces + o ctnl_[get|del]_conntrack handles return value from kernel via msgerr + o Added support for conntrack table flushing + o Added test case file (test.sh) + o Improve dump output + + + o Autoconf stuff for conntrack + some pablo's modifications. + o Fixed packet counters formatting (use %llu instead of %lu) + +2005-04-25 + + o Added support for mask based event dumping + o Added support for mask based event notification + o On-demand autoload of ip_conntrack_netlink diff --git a/cli/INSTALL b/cli/INSTALL new file mode 100644 index 0000000..54caf7c --- /dev/null +++ b/cli/INSTALL @@ -0,0 +1,229 @@ +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software +Foundation, Inc. + + This file is free documentation; the Free Software Foundation gives +unlimited permission to copy, distribute and modify it. + +Basic Installation +================== + + These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. (Caching is +disabled by default to prevent problems with accidental use of stale +cache files.) + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You only need +`configure.ac' if you want to change it or regenerate `configure' using +a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. Run `./configure --help' +for details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not support the `VPATH' +variable, you have to compile the package for one architecture at a +time in the source code directory. After you have installed the +package for one architecture, use `make distclean' before reconfiguring +for another architecture. + +Installation Names +================== + + By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/man', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PATH'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PATH', the package will use +PATH as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=PATH' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + + There may be some features `configure' cannot figure out +automatically, but needs to determine by the type of machine the package +will run on. Usually, assuming the package is built to be run on the +_same_ architectures, `configure' can figure that out, but if it prints +a message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the `--target=TYPE' option to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + + Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +will cause the specified gcc to be used as the C compiler (unless it is +overridden in the site shell script). + +`configure' Invocation +====================== + + `configure' recognizes the following options to control how it +operates. + +`--help' +`-h' + Print a summary of the options to `configure', and exit. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. + diff --git a/cli/Make_global.am b/cli/Make_global.am new file mode 100644 index 0000000..685add7 --- /dev/null +++ b/cli/Make_global.am @@ -0,0 +1 @@ +INCLUDES=$(all_includes) -I$(top_srcdir)/include diff --git a/cli/Makefile.am b/cli/Makefile.am new file mode 100644 index 0000000..d3b4ceb --- /dev/null +++ b/cli/Makefile.am @@ -0,0 +1,21 @@ +include Make_global.am + +# not a GNU package. You can remove this line, if +# have all needed files, that a GNU package needs +AUTOMAKE_OPTIONS = foreign dist-bzip2 1.6 + +man_MANS = conntrack.8 + +EXTRA_DIST = $(man_MANS) Make_global.am debian + +SUBDIRS = src extensions +DIST_SUBDIRS = include src extensions +LINKOPTS = -ldl -lnetfilter_conntrack +AM_CFLAGS = -g + +$(OBJECTS): libtool +libtool: $(LIBTOOL_DEPS) + $(SHELL) ./config.status --recheck + +dist-hook: + rm -rf `find $(distdir)/debian -name .svn` diff --git a/cli/autogen.sh b/cli/autogen.sh new file mode 100755 index 0000000..e76d3ef --- /dev/null +++ b/cli/autogen.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +run () +{ + echo "running: $*" + eval $* + + if test $? != 0 ; then + echo "error: while running '$*'" + exit 1 + fi +} + +run aclocal +run libtoolize -f +#run autoheader +run automake -a +run autoconf diff --git a/cli/configure.in b/cli/configure.in new file mode 100644 index 0000000..1b1b391 --- /dev/null +++ b/cli/configure.in @@ -0,0 +1,72 @@ +AC_INIT + +AC_CANONICAL_SYSTEM + +AM_INIT_AUTOMAKE(conntrack, 1.00beta2) + +AC_PROG_CC +AM_PROG_LIBTOOL +AC_PROG_INSTALL +AC_PROG_LN_S + +case $target in +*-*-linux*) ;; +*) AC_MSG_ERROR([Linux only, dude!]);; +esac + +dnl Dependencies +LIBNFCONNTRACK_REQUIRED=0.0.31 + +AC_CHECK_LIB(dl, dlopen) + +PKG_CHECK_MODULES(LIBNFCONNTRACK, libnetfilter_conntrack >= $LIBNFCONNTRACK_REQUIRED,, + AC_MSG_ERROR(Cannot find libnetfilter_conntrack >= $LIBNFCONNTRACK_REQUIRED)) + +AC_CHECK_HEADERS(arpa/inet.h) +dnl check for inet_pton +AC_CHECK_FUNCS(inet_pton) +dnl Some systems have it, but not IPv6 +if test "$ac_cv_func_inet_pton" = "yes" ; then +AC_MSG_CHECKING(if inet_pton supports IPv6) +AC_TRY_RUN( + [ +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +int main() + { + struct in6_addr addr6; + if (inet_pton(AF_INET6, "::1", &addr6) < 1) + exit(1); + else + exit(0); + } + ], [ AC_MSG_RESULT(yes) + AC_DEFINE_UNQUOTED(HAVE_INET_PTON_IPV6, 1, [Define to 1 if inet_pton supports IPv6.]) + ], AC_MSG_RESULT(no), AC_MSG_RESULT(no)) +fi + +dnl-------------------------------- + +if test ! -z "$libdir"; then + MODULE_DIR="\\\"$libdir/conntrack/\\\"" + CFLAGS="$CFLAGS -DCONNTRACK_LIB_DIR=$MODULE_DIR" +fi + +dnl-------------------------------- + +CFLAGS="$CFLAGS $LIBNFCONNTRACK_CFLAGS" +CONNTRACK_LIBS="$LIBNFCONNTRACK_LIBS" + +AC_SUBST(CONNTRACK_LIBS) + +AC_OUTPUT(Makefile src/Makefile extensions/Makefile include/Makefile) diff --git a/cli/conntrack.8 b/cli/conntrack.8 new file mode 100644 index 0000000..307180b --- /dev/null +++ b/cli/conntrack.8 @@ -0,0 +1,142 @@ +.TH CONNTRACK 8 "Jun 23, 2005" "" "" + +.\" Man page written by Harald Welte . diff --git a/cli/extensions/Makefile.am b/cli/extensions/Makefile.am new file mode 100644 index 0000000..5366ee3 --- /dev/null +++ b/cli/extensions/Makefile.am @@ -0,0 +1,16 @@ +include $(top_srcdir)/Make_global.am + +AM_CFLAGS=-fPIC -Wall +LIBS= + +pkglib_LTLIBRARIES = ct_proto_tcp.la ct_proto_udp.la \ + ct_proto_icmp.la ct_proto_sctp.la + +ct_proto_tcp_la_SOURCES = libct_proto_tcp.c +ct_proto_tcp_la_LDFLAGS = -module -avoid-version +ct_proto_udp_la_SOURCES = libct_proto_udp.c +ct_proto_udp_la_LDFLAGS = -module -avoid-version +ct_proto_icmp_la_SOURCES = libct_proto_icmp.c +ct_proto_icmp_la_LDFLAGS = -module -avoid-version +ct_proto_sctp_la_SOURCES = libct_proto_sctp.c +ct_proto_sctp_la_LDFLAGS = -module -avoid-version diff --git a/cli/extensions/libct_proto_icmp.c b/cli/extensions/libct_proto_icmp.c new file mode 100644 index 0000000..e7cb04d --- /dev/null +++ b/cli/extensions/libct_proto_icmp.c @@ -0,0 +1,108 @@ +/* + * (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 /* For htons */ +#include +#include +#include +#include "conntrack.h" + +static struct option opts[] = { + {"icmp-type", 1, 0, '1'}, + {"icmp-code", 1, 0, '2'}, + {"icmp-id", 1, 0, '3'}, + {0, 0, 0, 0} +}; + +static void help() +{ + fprintf(stdout, "--icmp-type icmp type\n"); + fprintf(stdout, "--icmp-code icmp code\n"); + fprintf(stdout, "--icmp-id icmp id\n"); +} + +/* Add 1; spaces filled with 0. */ +static u_int8_t invmap[] + = { [ICMP_ECHO] = ICMP_ECHOREPLY + 1, + [ICMP_ECHOREPLY] = ICMP_ECHO + 1, + [ICMP_TIMESTAMP] = ICMP_TIMESTAMPREPLY + 1, + [ICMP_TIMESTAMPREPLY] = ICMP_TIMESTAMP + 1, + [ICMP_INFO_REQUEST] = ICMP_INFO_REPLY + 1, + [ICMP_INFO_REPLY] = ICMP_INFO_REQUEST + 1, + [ICMP_ADDRESS] = ICMP_ADDRESSREPLY + 1, + [ICMP_ADDRESSREPLY] = ICMP_ADDRESS + 1}; + +static int parse(char c, char *argv[], + struct nfct_tuple *orig, + struct nfct_tuple *reply, + struct nfct_tuple *exptuple, + struct nfct_tuple *mask, + union nfct_protoinfo *proto, + unsigned int *flags) +{ + switch(c) { + case '1': + if (optarg) { + orig->l4dst.icmp.type = atoi(optarg); + reply->l4dst.icmp.type = + invmap[orig->l4dst.icmp.type] - 1; + *flags |= ICMP_TYPE; + } + break; + case '2': + if (optarg) { + orig->l4dst.icmp.code = atoi(optarg); + reply->l4dst.icmp.code = 0; + *flags |= ICMP_CODE; + } + break; + case '3': + if (optarg) { + orig->l4src.icmp.id = htons(atoi(optarg)); + reply->l4dst.icmp.id = 0; + *flags |= ICMP_ID; + } + break; + } + return 1; +} + +static int final_check(unsigned int flags, + unsigned int command, + struct nfct_tuple *orig, + struct nfct_tuple *reply) +{ + if (!(flags & ICMP_TYPE)) + return 0; + else if (!(flags & ICMP_CODE)) + return 0; + + return 1; +} + +static struct ctproto_handler icmp = { + .name = "icmp", + .protonum = IPPROTO_ICMP, + .parse_opts = parse, + .final_check = final_check, + .help = help, + .opts = opts, + .version = VERSION, +}; + +static void __attribute__ ((constructor)) init(void); + +static void init(void) +{ + register_proto(&icmp); +} diff --git a/cli/extensions/libct_proto_icmp.man b/cli/extensions/libct_proto_icmp.man new file mode 100644 index 0000000..3b860d0 --- /dev/null +++ b/cli/extensions/libct_proto_icmp.man @@ -0,0 +1,10 @@ +This module matches on ICMP-specific fields. +.TP +.BI "--icmp-type " "TYPE" +ICMP Type. Has to be specified numerically. +.TP +.BI "--icmp-code " "CODE" +ICMP Code. Has to be specified numerically. +.TP +.BI "--icmp-id " "ID" +ICMP Id. Has to be specified numerically. diff --git a/cli/extensions/libct_proto_sctp.c b/cli/extensions/libct_proto_sctp.c new file mode 100644 index 0000000..1c8f0d1 --- /dev/null +++ b/cli/extensions/libct_proto_sctp.c @@ -0,0 +1,164 @@ +/* + * (C) 2005 by Harald Welte + * 2006 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 +#include +#include +#include +#include /* For htons */ +#include "conntrack.h" +#include +#include + +static struct option opts[] = { + {"orig-port-src", 1, 0, '1'}, + {"orig-port-dst", 1, 0, '2'}, + {"reply-port-src", 1, 0, '3'}, + {"reply-port-dst", 1, 0, '4'}, + {"state", 1, 0, '5'}, + {"tuple-port-src", 1, 0, '6'}, + {"tuple-port-dst", 1, 0, '7'}, + {0, 0, 0, 0} +}; + +static const char *states[] = { + "NONE", + "CLOSED", + "COOKIE_WAIT", + "COOKIE_ECHOED", + "ESTABLISHED", + "SHUTDOWN_SENT", + "SHUTDOWN_RECV", + "SHUTDOWN_ACK_SENT", +}; + +static void help() +{ + fprintf(stdout, "--orig-port-src original source port\n"); + fprintf(stdout, "--orig-port-dst original destination port\n"); + fprintf(stdout, "--reply-port-src reply source port\n"); + fprintf(stdout, "--reply-port-dst reply destination port\n"); + fprintf(stdout, "--state SCTP state, fe. ESTABLISHED\n"); + fprintf(stdout, "--tuple-port-src expectation tuple src port\n"); + fprintf(stdout, "--tuple-port-src expectation tuple dst port\n"); +} + +static int parse_options(char c, char *argv[], + struct nfct_tuple *orig, + struct nfct_tuple *reply, + struct nfct_tuple *exptuple, + struct nfct_tuple *mask, + union nfct_protoinfo *proto, + unsigned int *flags) +{ + switch(c) { + case '1': + if (optarg) { + orig->l4src.sctp.port = htons(atoi(optarg)); + *flags |= SCTP_ORIG_SPORT; + } + break; + case '2': + if (optarg) { + orig->l4dst.sctp.port = htons(atoi(optarg)); + *flags |= SCTP_ORIG_DPORT; + } + break; + case '3': + if (optarg) { + reply->l4src.sctp.port = htons(atoi(optarg)); + *flags |= SCTP_REPL_SPORT; + } + break; + case '4': + if (optarg) { + reply->l4dst.sctp.port = htons(atoi(optarg)); + *flags |= SCTP_REPL_DPORT; + } + break; + case '5': + if (optarg) { + int i; + for (i=0; i<10; i++) { + if (strcmp(optarg, states[i]) == 0) { + /* FIXME: Add state to + * nfct_protoinfo + proto->sctp.state = i; */ + break; + } + } + if (i == 10) { + printf("doh?\n"); + return 0; + } + *flags |= SCTP_STATE; + } + break; + case '6': + if (optarg) { + exptuple->l4src.sctp.port = htons(atoi(optarg)); + *flags |= SCTP_EXPTUPLE_SPORT; + } + break; + case '7': + if (optarg) { + exptuple->l4dst.sctp.port = htons(atoi(optarg)); + *flags |= SCTP_EXPTUPLE_DPORT; + } + + } + return 1; +} + +static int final_check(unsigned int flags, + unsigned int command, + struct nfct_tuple *orig, + struct nfct_tuple *reply) +{ + int ret = 0; + + if ((flags & (SCTP_ORIG_SPORT|SCTP_ORIG_DPORT)) + && !(flags & (SCTP_REPL_SPORT|SCTP_REPL_DPORT))) { + reply->l4src.sctp.port = orig->l4dst.sctp.port; + reply->l4dst.sctp.port = orig->l4src.sctp.port; + ret = 1; + } else if (!(flags & (SCTP_ORIG_SPORT|SCTP_ORIG_DPORT)) + && (flags & (SCTP_REPL_SPORT|SCTP_REPL_DPORT))) { + orig->l4src.sctp.port = reply->l4dst.sctp.port; + orig->l4dst.sctp.port = reply->l4src.sctp.port; + ret = 1; + } + if ((flags & (SCTP_ORIG_SPORT|SCTP_ORIG_DPORT)) + && ((flags & (SCTP_REPL_SPORT|SCTP_REPL_DPORT)))) + ret = 1; + + /* --state is missing and we are trying to create a conntrack */ + if (ret && (command & CT_CREATE) && (!(flags & SCTP_STATE))) + ret = 0; + + return ret; +} + +static struct ctproto_handler sctp = { + .name = "sctp", + .protonum = IPPROTO_SCTP, + .parse_opts = parse_options, + .final_check = final_check, + .help = help, + .opts = opts, + .version = VERSION, +}; + +static void __attribute__ ((constructor)) init(void); + +static void init(void) +{ + register_proto(&sctp); +} diff --git a/cli/extensions/libct_proto_tcp.c b/cli/extensions/libct_proto_tcp.c new file mode 100644 index 0000000..ee24206 --- /dev/null +++ b/cli/extensions/libct_proto_tcp.c @@ -0,0 +1,180 @@ +/* + * (C) 2005 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 +#include +#include +#include +#include /* For htons */ +#include +#include + +#include "conntrack.h" + +static struct option opts[] = { + {"orig-port-src", 1, 0, '1'}, + {"orig-port-dst", 1, 0, '2'}, + {"reply-port-src", 1, 0, '3'}, + {"reply-port-dst", 1, 0, '4'}, + {"mask-port-src", 1, 0, '5'}, + {"mask-port-dst", 1, 0, '6'}, + {"state", 1, 0, '7'}, + {"tuple-port-src", 1, 0, '8'}, + {"tuple-port-dst", 1, 0, '9'}, + {0, 0, 0, 0} +}; + +static const char *states[] = { + "NONE", + "SYN_SENT", + "SYN_RECV", + "ESTABLISHED", + "FIN_WAIT", + "CLOSE_WAIT", + "LAST_ACK", + "TIME_WAIT", + "CLOSE", + "LISTEN" +}; + +static void help() +{ + fprintf(stdout, "--orig-port-src original source port\n"); + fprintf(stdout, "--orig-port-dst original destination port\n"); + fprintf(stdout, "--reply-port-src reply source port\n"); + fprintf(stdout, "--reply-port-dst reply destination port\n"); + fprintf(stdout, "--mask-port-src mask source port\n"); + fprintf(stdout, "--mask-port-dst mask destination port\n"); + fprintf(stdout, "--tuple-port-src expectation tuple src port\n"); + fprintf(stdout, "--tuple-port-src expectation tuple dst port\n"); + fprintf(stdout, "--state TCP state, fe. ESTABLISHED\n"); +} + +static int parse_options(char c, char *argv[], + struct nfct_tuple *orig, + struct nfct_tuple *reply, + struct nfct_tuple *exptuple, + struct nfct_tuple *mask, + union nfct_protoinfo *proto, + unsigned int *flags) +{ + switch(c) { + case '1': + if (optarg) { + orig->l4src.tcp.port = htons(atoi(optarg)); + *flags |= TCP_ORIG_SPORT; + } + break; + case '2': + if (optarg) { + orig->l4dst.tcp.port = htons(atoi(optarg)); + *flags |= TCP_ORIG_DPORT; + } + break; + case '3': + if (optarg) { + reply->l4src.tcp.port = htons(atoi(optarg)); + *flags |= TCP_REPL_SPORT; + } + break; + case '4': + if (optarg) { + reply->l4dst.tcp.port = htons(atoi(optarg)); + *flags |= TCP_REPL_DPORT; + } + break; + case '5': + if (optarg) { + mask->l4src.tcp.port = htons(atoi(optarg)); + *flags |= TCP_MASK_SPORT; + } + break; + case '6': + if (optarg) { + mask->l4dst.tcp.port = htons(atoi(optarg)); + *flags |= TCP_MASK_DPORT; + } + break; + case '7': + if (optarg) { + int i; + for (i=0; i<10; i++) { + if (strcmp(optarg, states[i]) == 0) { + proto->tcp.state = i; + break; + } + } + if (i == 10) { + printf("doh?\n"); + return 0; + } + *flags |= TCP_STATE; + } + break; + case '8': + if (optarg) { + exptuple->l4src.tcp.port = htons(atoi(optarg)); + *flags |= TCP_EXPTUPLE_SPORT; + } + break; + case '9': + if (optarg) { + exptuple->l4dst.tcp.port = htons(atoi(optarg)); + *flags |= TCP_EXPTUPLE_DPORT; + } + break; + } + return 1; +} + +static int final_check(unsigned int flags, + unsigned int command, + struct nfct_tuple *orig, + struct nfct_tuple *reply) +{ + int ret = 0; + + if ((flags & (TCP_ORIG_SPORT|TCP_ORIG_DPORT)) + && !(flags & (TCP_REPL_SPORT|TCP_REPL_DPORT))) { + reply->l4src.tcp.port = orig->l4dst.tcp.port; + reply->l4dst.tcp.port = orig->l4src.tcp.port; + ret = 1; + } else if (!(flags & (TCP_ORIG_SPORT|TCP_ORIG_DPORT)) + && (flags & (TCP_REPL_SPORT|TCP_REPL_DPORT))) { + orig->l4src.tcp.port = reply->l4dst.tcp.port; + orig->l4dst.tcp.port = reply->l4src.tcp.port; + ret = 1; + } + if ((flags & (TCP_ORIG_SPORT|TCP_ORIG_DPORT)) + && ((flags & (TCP_REPL_SPORT|TCP_REPL_DPORT)))) + ret = 1; + + /* --state is missing and we are trying to create a conntrack */ + if (ret && (command & CT_CREATE) && (!(flags & TCP_STATE))) + ret = 0; + + return ret; +} + +static struct ctproto_handler tcp = { + .name = "tcp", + .protonum = IPPROTO_TCP, + .parse_opts = parse_options, + .final_check = final_check, + .help = help, + .opts = opts, + .version = VERSION, +}; + +static void __attribute__ ((constructor)) init(void); + +static void init(void) +{ + register_proto(&tcp); +} diff --git a/cli/extensions/libct_proto_tcp.man b/cli/extensions/libct_proto_tcp.man new file mode 100644 index 0000000..41783f8 --- /dev/null +++ b/cli/extensions/libct_proto_tcp.man @@ -0,0 +1,16 @@ +This module matches on TCP-specific fields. +.TP +.BI "--orig-port-src " "PORT" +Source port in original direction +.TP +.BI "--orig-port-dst " "PORT" +Destination port in original direction +.TP +.BI "--reply-port-src " "PORT" +Source port in reply direction +.TP +.BI "--reply-port-dst " "PORT" +Destination port in reply direction +.TP +.BI "--state " "[NONE|SYN_SENT|SYN_RECV|ESTABLISHED|FIN_WAIT|CLOSE_WAIT|LAST_ACK|TIME_WAIT|CLOSE|LISTEN]" +TCP state diff --git a/cli/extensions/libct_proto_udp.c b/cli/extensions/libct_proto_udp.c new file mode 100644 index 0000000..48079e0 --- /dev/null +++ b/cli/extensions/libct_proto_udp.c @@ -0,0 +1,141 @@ +/* + * (C) 2005 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 +#include +#include +#include /* For htons */ +#include "conntrack.h" +#include +#include + +static struct option opts[] = { + {"orig-port-src", 1, 0, '1'}, + {"orig-port-dst", 1, 0, '2'}, + {"reply-port-src", 1, 0, '3'}, + {"reply-port-dst", 1, 0, '4'}, + {"mask-port-src", 1, 0, '5'}, + {"mask-port-dst", 1, 0, '6'}, + {"tuple-port-src", 1, 0, '7'}, + {"tuple-port-dst", 1, 0, '8'}, + {0, 0, 0, 0} +}; + +static void help() +{ + fprintf(stdout, "--orig-port-src original source port\n"); + fprintf(stdout, "--orig-port-dst original destination port\n"); + fprintf(stdout, "--reply-port-src reply source port\n"); + fprintf(stdout, "--reply-port-dst reply destination port\n"); + fprintf(stdout, "--mask-port-src mask source port\n"); + fprintf(stdout, "--mask-port-dst mask destination port\n"); + fprintf(stdout, "--tuple-port-src expectation tuple src port\n"); + fprintf(stdout, "--tuple-port-src expectation tuple dst port\n"); +} + +static int parse_options(char c, char *argv[], + struct nfct_tuple *orig, + struct nfct_tuple *reply, + struct nfct_tuple *exptuple, + struct nfct_tuple *mask, + union nfct_protoinfo *proto, + unsigned int *flags) +{ + switch(c) { + case '1': + if (optarg) { + orig->l4src.udp.port = htons(atoi(optarg)); + *flags |= UDP_ORIG_SPORT; + } + break; + case '2': + if (optarg) { + orig->l4dst.udp.port = htons(atoi(optarg)); + *flags |= UDP_ORIG_DPORT; + } + break; + case '3': + if (optarg) { + reply->l4src.udp.port = htons(atoi(optarg)); + *flags |= UDP_REPL_SPORT; + } + break; + case '4': + if (optarg) { + reply->l4dst.udp.port = htons(atoi(optarg)); + *flags |= UDP_REPL_DPORT; + } + break; + case '5': + if (optarg) { + mask->l4src.udp.port = htons(atoi(optarg)); + *flags |= UDP_MASK_SPORT; + } + break; + case '6': + if (optarg) { + mask->l4dst.udp.port = htons(atoi(optarg)); + *flags |= UDP_MASK_DPORT; + } + break; + case '7': + if (optarg) { + exptuple->l4src.udp.port = htons(atoi(optarg)); + *flags |= UDP_EXPTUPLE_SPORT; + } + break; + case '8': + if (optarg) { + exptuple->l4dst.udp.port = htons(atoi(optarg)); + *flags |= UDP_EXPTUPLE_DPORT; + } + + } + return 1; +} + +static int final_check(unsigned int flags, + unsigned int command, + struct nfct_tuple *orig, + struct nfct_tuple *reply) +{ + if ((flags & (UDP_ORIG_SPORT|UDP_ORIG_DPORT)) + && !(flags & (UDP_REPL_SPORT|UDP_REPL_DPORT))) { + reply->l4src.udp.port = orig->l4dst.udp.port; + reply->l4dst.udp.port = orig->l4src.udp.port; + return 1; + } else if (!(flags & (UDP_ORIG_SPORT|UDP_ORIG_DPORT)) + && (flags & (UDP_REPL_SPORT|UDP_REPL_DPORT))) { + orig->l4src.udp.port = reply->l4dst.udp.port; + orig->l4dst.udp.port = reply->l4src.udp.port; + return 1; + } + if ((flags & (UDP_ORIG_SPORT|UDP_ORIG_DPORT)) + && ((flags & (UDP_REPL_SPORT|UDP_REPL_DPORT)))) + return 1; + + return 0; +} + +static struct ctproto_handler udp = { + .name = "udp", + .protonum = IPPROTO_UDP, + .parse_opts = parse_options, + .final_check = final_check, + .help = help, + .opts = opts, + .version = VERSION, +}; + +static void __attribute__ ((constructor)) init(void); + +static void init(void) +{ + register_proto(&udp); +} diff --git a/cli/extensions/libct_proto_udp.man b/cli/extensions/libct_proto_udp.man new file mode 100644 index 0000000..c67fedf --- /dev/null +++ b/cli/extensions/libct_proto_udp.man @@ -0,0 +1,13 @@ +This module matches on UDP-specific fields. +.TP +.BI "--orig-port-src " "PORT" +Source port in original direction +.TP +.BI "--orig-port-dst " "PORT" +Destination port in original direction +.TP +.BI "--reply-port-src " "PORT" +Source port in reply direction +.TP +.BI "--reply-port-dst " "PORT" +Destination port in reply direction diff --git a/cli/include/Makefile.am b/cli/include/Makefile.am new file mode 100644 index 0000000..ef7ce45 --- /dev/null +++ b/cli/include/Makefile.am @@ -0,0 +1,2 @@ + +noinst_HEADERS = conntrack.h linux_list.h diff --git a/cli/include/conntrack.h b/cli/include/conntrack.h new file mode 100644 index 0000000..fb3b9b6 --- /dev/null +++ b/cli/include/conntrack.h @@ -0,0 +1,160 @@ +#ifndef _CONNTRACK_H +#define _CONNTRACK_H + +#ifdef HAVE_CONFIG_H +#include "../config.h" +#endif + +#include "linux_list.h" +#include +#include + +#define PROGNAME "conntrack" + +#include +#ifndef IPPROTO_SCTP +#define IPPROTO_SCTP 132 +#endif + +enum action { + CT_NONE = 0, + + CT_LIST_BIT = 0, + CT_LIST = (1 << CT_LIST_BIT), + + CT_CREATE_BIT = 1, + CT_CREATE = (1 << CT_CREATE_BIT), + + CT_UPDATE_BIT = 2, + CT_UPDATE = (1 << CT_UPDATE_BIT), + + CT_DELETE_BIT = 3, + CT_DELETE = (1 << CT_DELETE_BIT), + + CT_GET_BIT = 4, + CT_GET = (1 << CT_GET_BIT), + + CT_FLUSH_BIT = 5, + CT_FLUSH = (1 << CT_FLUSH_BIT), + + CT_EVENT_BIT = 6, + CT_EVENT = (1 << CT_EVENT_BIT), + + CT_VERSION_BIT = 7, + CT_VERSION = (1 << CT_VERSION_BIT), + + CT_HELP_BIT = 8, + CT_HELP = (1 << CT_HELP_BIT), + + EXP_LIST_BIT = 9, + EXP_LIST = (1 << EXP_LIST_BIT), + + EXP_CREATE_BIT = 10, + EXP_CREATE = (1 << EXP_CREATE_BIT), + + EXP_DELETE_BIT = 11, + EXP_DELETE = (1 << EXP_DELETE_BIT), + + EXP_GET_BIT = 12, + EXP_GET = (1 << EXP_GET_BIT), + + EXP_FLUSH_BIT = 13, + EXP_FLUSH = (1 << EXP_FLUSH_BIT), + + EXP_EVENT_BIT = 14, + EXP_EVENT = (1 << EXP_EVENT_BIT), +}; +#define NUMBER_OF_CMD 15 + +enum options { + CT_OPT_ORIG_SRC_BIT = 0, + CT_OPT_ORIG_SRC = (1 << CT_OPT_ORIG_SRC_BIT), + + CT_OPT_ORIG_DST_BIT = 1, + CT_OPT_ORIG_DST = (1 << CT_OPT_ORIG_DST_BIT), + + CT_OPT_ORIG = (CT_OPT_ORIG_SRC | CT_OPT_ORIG_DST), + + CT_OPT_REPL_SRC_BIT = 2, + CT_OPT_REPL_SRC = (1 << CT_OPT_REPL_SRC_BIT), + + CT_OPT_REPL_DST_BIT = 3, + CT_OPT_REPL_DST = (1 << CT_OPT_REPL_DST_BIT), + + CT_OPT_REPL = (CT_OPT_REPL_SRC | CT_OPT_REPL_DST), + + CT_OPT_PROTO_BIT = 4, + CT_OPT_PROTO = (1 << CT_OPT_PROTO_BIT), + + CT_OPT_TIMEOUT_BIT = 5, + CT_OPT_TIMEOUT = (1 << CT_OPT_TIMEOUT_BIT), + + CT_OPT_STATUS_BIT = 6, + CT_OPT_STATUS = (1 << CT_OPT_STATUS_BIT), + + CT_OPT_ZERO_BIT = 7, + CT_OPT_ZERO = (1 << CT_OPT_ZERO_BIT), + + CT_OPT_EVENT_MASK_BIT = 8, + CT_OPT_EVENT_MASK = (1 << CT_OPT_EVENT_MASK_BIT), + + CT_OPT_EXP_SRC_BIT = 9, + CT_OPT_EXP_SRC = (1 << CT_OPT_EXP_SRC_BIT), + + CT_OPT_EXP_DST_BIT = 10, + CT_OPT_EXP_DST = (1 << CT_OPT_EXP_DST_BIT), + + CT_OPT_MASK_SRC_BIT = 11, + CT_OPT_MASK_SRC = (1 << CT_OPT_MASK_SRC_BIT), + + CT_OPT_MASK_DST_BIT = 12, + CT_OPT_MASK_DST = (1 << CT_OPT_MASK_DST_BIT), + + CT_OPT_NATRANGE_BIT = 13, + CT_OPT_NATRANGE = (1 << CT_OPT_NATRANGE_BIT), + + CT_OPT_MARK_BIT = 14, + CT_OPT_MARK = (1 << CT_OPT_MARK_BIT), + + CT_OPT_ID_BIT = 15, + CT_OPT_ID = (1 << CT_OPT_ID_BIT), + + CT_OPT_FAMILY_BIT = 16, + CT_OPT_FAMILY = (1 << CT_OPT_FAMILY_BIT), + + CT_OPT_MAX_BIT = CT_OPT_FAMILY_BIT +}; +#define NUMBER_OF_OPT CT_OPT_MAX_BIT+1 + +struct ctproto_handler { + struct list_head head; + + char *name; + u_int16_t protonum; + char *version; + + enum ctattr_protoinfo protoinfo_attr; + + int (*parse_opts)(char c, char *argv[], + struct nfct_tuple *orig, + struct nfct_tuple *reply, + struct nfct_tuple *exptuple, + struct nfct_tuple *mask, + union nfct_protoinfo *proto, + unsigned int *flags); + + int (*final_check)(unsigned int flags, + unsigned int command, + struct nfct_tuple *orig, + struct nfct_tuple *reply); + + void (*help)(); + + struct option *opts; + + unsigned int option_offset; +}; + +extern void register_proto(struct ctproto_handler *h); + +#endif diff --git a/cli/include/linux_list.h b/cli/include/linux_list.h new file mode 100644 index 0000000..57b56d7 --- /dev/null +++ b/cli/include/linux_list.h @@ -0,0 +1,725 @@ +#ifndef _LINUX_LIST_H +#define _LINUX_LIST_H + +#undef offsetof +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) + +/** + * container_of - cast a member of a structure out to the containing structure + * + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + * + */ +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +/* + * Check at compile time that something is of a particular type. + * Always evaluates to 1 so you may use it easily in comparisons. + */ +#define typecheck(type,x) \ +({ type __dummy; \ + typeof(x) __dummy2; \ + (void)(&__dummy == &__dummy2); \ + 1; \ +}) + +#define prefetch(x) 1 + +/* empty define to make this work in userspace -HW */ +#ifndef smp_wmb +#define smp_wmb() +#endif + +/* + * These are non-NULL pointers that will result in page faults + * under normal circumstances, used to verify that nobody uses + * non-initialized list entries. + */ +#define LIST_POISON1 ((void *) 0x00100100) +#define LIST_POISON2 ((void *) 0x00200200) + +/* + * Simple doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +struct list_head { + struct list_head *next, *prev; +}; + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +#define INIT_LIST_HEAD(ptr) do { \ + (ptr)->next = (ptr); (ptr)->prev = (ptr); \ +} while (0) + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +/** + * list_add - add a new entry + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} + +/** + * list_add_tail - add a new entry + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static inline void list_add_tail(struct list_head *new, struct list_head *head) +{ + __list_add(new, head->prev, head); +} + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_add_rcu(struct list_head * new, + struct list_head * prev, struct list_head * next) +{ + new->next = next; + new->prev = prev; + smp_wmb(); + next->prev = new; + prev->next = new; +} + +/** + * list_add_rcu - add a new entry to rcu-protected list + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + * + * The caller must take whatever precautions are necessary + * (such as holding appropriate locks) to avoid racing + * with another list-mutation primitive, such as list_add_rcu() + * or list_del_rcu(), running on this same list. + * However, it is perfectly legal to run concurrently with + * the _rcu list-traversal primitives, such as + * list_for_each_entry_rcu(). + */ +static inline void list_add_rcu(struct list_head *new, struct list_head *head) +{ + __list_add_rcu(new, head, head->next); +} + +/** + * list_add_tail_rcu - add a new entry to rcu-protected list + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + * + * The caller must take whatever precautions are necessary + * (such as holding appropriate locks) to avoid racing + * with another list-mutation primitive, such as list_add_tail_rcu() + * or list_del_rcu(), running on this same list. + * However, it is perfectly legal to run concurrently with + * the _rcu list-traversal primitives, such as + * list_for_each_entry_rcu(). + */ +static inline void list_add_tail_rcu(struct list_head *new, + struct list_head *head) +{ + __list_add_rcu(new, head->prev, head); +} + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head * prev, struct list_head * next) +{ + next->prev = prev; + prev->next = next; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty on entry does not return true after this, the entry is + * in an undefined state. + */ +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->next = LIST_POISON1; + entry->prev = LIST_POISON2; +} + +/** + * list_del_rcu - deletes entry from list without re-initialization + * @entry: the element to delete from the list. + * + * Note: list_empty on entry does not return true after this, + * the entry is in an undefined state. It is useful for RCU based + * lockfree traversal. + * + * In particular, it means that we can not poison the forward + * pointers that may still be used for walking the list. + * + * The caller must take whatever precautions are necessary + * (such as holding appropriate locks) to avoid racing + * with another list-mutation primitive, such as list_del_rcu() + * or list_add_rcu(), running on this same list. + * However, it is perfectly legal to run concurrently with + * the _rcu list-traversal primitives, such as + * list_for_each_entry_rcu(). + * + * Note that the caller is not permitted to immediately free + * the newly deleted entry. Instead, either synchronize_kernel() + * or call_rcu() must be used to defer freeing until an RCU + * grace period has elapsed. + */ +static inline void list_del_rcu(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->prev = LIST_POISON2; +} + +/** + * list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list. + */ +static inline void list_del_init(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + INIT_LIST_HEAD(entry); +} + +/** + * list_move - delete from one list and add as another's head + * @list: the entry to move + * @head: the head that will precede our entry + */ +static inline void list_move(struct list_head *list, struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add(list, head); +} + +/** + * list_move_tail - delete from one list and add as another's tail + * @list: the entry to move + * @head: the head that will follow our entry + */ +static inline void list_move_tail(struct list_head *list, + struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add_tail(list, head); +} + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static inline int list_empty(const struct list_head *head) +{ + return head->next == head; +} + +/** + * list_empty_careful - tests whether a list is + * empty _and_ checks that no other CPU might be + * in the process of still modifying either member + * + * NOTE: using list_empty_careful() without synchronization + * can only be safe if the only activity that can happen + * to the list entry is list_del_init(). Eg. it cannot be used + * if another CPU could re-list_add() it. + * + * @head: the list to test. + */ +static inline int list_empty_careful(const struct list_head *head) +{ + struct list_head *next = head->next; + return (next == head) && (next == head->prev); +} + +static inline void __list_splice(struct list_head *list, + struct list_head *head) +{ + struct list_head *first = list->next; + struct list_head *last = list->prev; + struct list_head *at = head->next; + + first->prev = head; + head->next = first; + + last->next = at; + at->prev = last; +} + +/** + * list_splice - join two lists + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static inline void list_splice(struct list_head *list, struct list_head *head) +{ + if (!list_empty(list)) + __list_splice(list, head); +} + +/** + * list_splice_init - join two lists and reinitialise the emptied list. + * @list: the new list to add. + * @head: the place to add it in the first list. + * + * The list at @list is reinitialised + */ +static inline void list_splice_init(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) { + __list_splice(list, head); + INIT_LIST_HEAD(list); + } +} + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +/** + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next, prefetch(pos->next); pos != (head); \ + pos = pos->next, prefetch(pos->next)) + +/** + * __list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + * + * This variant differs from list_for_each() in that it's the + * simplest possible list iteration code, no prefetching is done. + * Use this for code that knows the list to be very short (empty + * or 1 entry) most of the time. + */ +#define __list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_for_each_prev - iterate over a list backwards + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + */ +#define list_for_each_prev(pos, head) \ + for (pos = (head)->prev, prefetch(pos->prev); pos != (head); \ + pos = pos->prev, prefetch(pos->prev)) + +/** + * list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the &struct list_head to use as a loop counter. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + prefetch(pos->member.next); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member), \ + prefetch(pos->member.next)) + +/** + * list_for_each_entry_reverse - iterate backwards over list of given type. + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_reverse(pos, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member), \ + prefetch(pos->member.prev); \ + &pos->member != (head); \ + pos = list_entry(pos->member.prev, typeof(*pos), member), \ + prefetch(pos->member.prev)) + +/** + * list_prepare_entry - prepare a pos entry for use as a start point in + * list_for_each_entry_continue + * @pos: the type * to use as a start point + * @head: the head of the list + * @member: the name of the list_struct within the struct. + */ +#define list_prepare_entry(pos, head, member) \ + ((pos) ? : list_entry(head, typeof(*pos), member)) + +/** + * list_for_each_entry_continue - iterate over list of given type + * continuing after existing point + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_continue(pos, head, member) \ + for (pos = list_entry(pos->member.next, typeof(*pos), member), \ + prefetch(pos->member.next); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member), \ + prefetch(pos->member.next)) + +/** + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos: the type * to use as a loop counter. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_rcu - iterate over an rcu-protected list + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + * + * This list-traversal primitive may safely run concurrently with + * the _rcu list-mutation primitives such as list_add_rcu() + * as long as the traversal is guarded by rcu_read_lock(). + */ +#define list_for_each_rcu(pos, head) \ + for (pos = (head)->next, prefetch(pos->next); pos != (head); \ + pos = pos->next, ({ smp_read_barrier_depends(); 0;}), prefetch(pos->next)) + +#define __list_for_each_rcu(pos, head) \ + for (pos = (head)->next; pos != (head); \ + pos = pos->next, ({ smp_read_barrier_depends(); 0;})) + +/** + * list_for_each_safe_rcu - iterate over an rcu-protected list safe + * against removal of list entry + * @pos: the &struct list_head to use as a loop counter. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + * + * This list-traversal primitive may safely run concurrently with + * the _rcu list-mutation primitives such as list_add_rcu() + * as long as the traversal is guarded by rcu_read_lock(). + */ +#define list_for_each_safe_rcu(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, ({ smp_read_barrier_depends(); 0;}), n = pos->next) + +/** + * list_for_each_entry_rcu - iterate over rcu list of given type + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * This list-traversal primitive may safely run concurrently with + * the _rcu list-mutation primitives such as list_add_rcu() + * as long as the traversal is guarded by rcu_read_lock(). + */ +#define list_for_each_entry_rcu(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + prefetch(pos->member.next); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member), \ + ({ smp_read_barrier_depends(); 0;}), \ + prefetch(pos->member.next)) + + +/** + * list_for_each_continue_rcu - iterate over an rcu-protected list + * continuing after existing point. + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + * + * This list-traversal primitive may safely run concurrently with + * the _rcu list-mutation primitives such as list_add_rcu() + * as long as the traversal is guarded by rcu_read_lock(). + */ +#define list_for_each_continue_rcu(pos, head) \ + for ((pos) = (pos)->next, prefetch((pos)->next); (pos) != (head); \ + (pos) = (pos)->next, ({ smp_read_barrier_depends(); 0;}), prefetch((pos)->next)) + +/* + * Double linked lists with a single pointer list head. + * Mostly useful for hash tables where the two pointer list head is + * too wasteful. + * You lose the ability to access the tail in O(1). + */ + +struct hlist_head { + struct hlist_node *first; +}; + +struct hlist_node { + struct hlist_node *next, **pprev; +}; + +#define HLIST_HEAD_INIT { .first = NULL } +#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL } +#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) +#define INIT_HLIST_NODE(ptr) ((ptr)->next = NULL, (ptr)->pprev = NULL) + +static inline int hlist_unhashed(const struct hlist_node *h) +{ + return !h->pprev; +} + +static inline int hlist_empty(const struct hlist_head *h) +{ + return !h->first; +} + +static inline void __hlist_del(struct hlist_node *n) +{ + struct hlist_node *next = n->next; + struct hlist_node **pprev = n->pprev; + *pprev = next; + if (next) + next->pprev = pprev; +} + +static inline void hlist_del(struct hlist_node *n) +{ + __hlist_del(n); + n->next = LIST_POISON1; + n->pprev = LIST_POISON2; +} + +/** + * hlist_del_rcu - deletes entry from hash list without re-initialization + * @n: the element to delete from the hash list. + * + * Note: list_unhashed() on entry does not return true after this, + * the entry is in an undefined state. It is useful for RCU based + * lockfree traversal. + * + * In particular, it means that we can not poison the forward + * pointers that may still be used for walking the hash list. + * + * The caller must take whatever precautions are necessary + * (such as holding appropriate locks) to avoid racing + * with another list-mutation primitive, such as hlist_add_head_rcu() + * or hlist_del_rcu(), running on this same list. + * However, it is perfectly legal to run concurrently with + * the _rcu list-traversal primitives, such as + * hlist_for_each_entry(). + */ +static inline void hlist_del_rcu(struct hlist_node *n) +{ + __hlist_del(n); + n->pprev = LIST_POISON2; +} + +static inline void hlist_del_init(struct hlist_node *n) +{ + if (n->pprev) { + __hlist_del(n); + INIT_HLIST_NODE(n); + } +} + +#define hlist_del_rcu_init hlist_del_init + +static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) +{ + struct hlist_node *first = h->first; + n->next = first; + if (first) + first->pprev = &n->next; + h->first = n; + n->pprev = &h->first; +} + + +/** + * hlist_add_head_rcu - adds the specified element to the specified hlist, + * while permitting racing traversals. + * @n: the element to add to the hash list. + * @h: the list to add to. + * + * The caller must take whatever precautions are necessary + * (such as holding appropriate locks) to avoid racing + * with another list-mutation primitive, such as hlist_add_head_rcu() + * or hlist_del_rcu(), running on this same list. + * However, it is perfectly legal to run concurrently with + * the _rcu list-traversal primitives, such as + * hlist_for_each_entry(), but only if smp_read_barrier_depends() + * is used to prevent memory-consistency problems on Alpha CPUs. + * Regardless of the type of CPU, the list-traversal primitive + * must be guarded by rcu_read_lock(). + * + * OK, so why don't we have an hlist_for_each_entry_rcu()??? + */ +static inline void hlist_add_head_rcu(struct hlist_node *n, + struct hlist_head *h) +{ + struct hlist_node *first = h->first; + n->next = first; + n->pprev = &h->first; + smp_wmb(); + if (first) + first->pprev = &n->next; + h->first = n; +} + +/* next must be != NULL */ +static inline void hlist_add_before(struct hlist_node *n, + struct hlist_node *next) +{ + n->pprev = next->pprev; + n->next = next; + next->pprev = &n->next; + *(n->pprev) = n; +} + +static inline void hlist_add_after(struct hlist_node *n, + struct hlist_node *next) +{ + next->next = n->next; + n->next = next; + next->pprev = &n->next; + + if(next->next) + next->next->pprev = &next->next; +} + +#define hlist_entry(ptr, type, member) container_of(ptr,type,member) + +#define hlist_for_each(pos, head) \ + for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \ + pos = pos->next) + +#define hlist_for_each_safe(pos, n, head) \ + for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \ + pos = n) + +/** + * hlist_for_each_entry - iterate over list of given type + * @tpos: the type * to use as a loop counter. + * @pos: the &struct hlist_node to use as a loop counter. + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry(tpos, pos, head, member) \ + for (pos = (head)->first; \ + pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) + +/** + * hlist_for_each_entry_continue - iterate over a hlist continuing after existing point + * @tpos: the type * to use as a loop counter. + * @pos: the &struct hlist_node to use as a loop counter. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_continue(tpos, pos, member) \ + for (pos = (pos)->next; \ + pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) + +/** + * hlist_for_each_entry_from - iterate over a hlist continuing from existing point + * @tpos: the type * to use as a loop counter. + * @pos: the &struct hlist_node to use as a loop counter. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_from(tpos, pos, member) \ + for (; pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) + +/** + * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @tpos: the type * to use as a loop counter. + * @pos: the &struct hlist_node to use as a loop counter. + * @n: another &struct hlist_node to use as temporary storage + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ + for (pos = (head)->first; \ + pos && ({ n = pos->next; 1; }) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = n) + +/** + * hlist_for_each_entry_rcu - iterate over rcu list of given type + * @pos: the type * to use as a loop counter. + * @pos: the &struct hlist_node to use as a loop counter. + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + * + * This list-traversal primitive may safely run concurrently with + * the _rcu list-mutation primitives such as hlist_add_rcu() + * as long as the traversal is guarded by rcu_read_lock(). + */ +#define hlist_for_each_entry_rcu(tpos, pos, head, member) \ + for (pos = (head)->first; \ + pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next, ({ smp_read_barrier_depends(); 0; }) ) + +#endif diff --git a/cli/src/Makefile.am b/cli/src/Makefile.am new file mode 100644 index 0000000..83cad99 --- /dev/null +++ b/cli/src/Makefile.am @@ -0,0 +1,7 @@ +include $(top_srcdir)/Make_global.am +LIBS = @CONNTRACK_LIBS@ + +sbin_PROGRAMS = conntrack +conntrack_SOURCES = conntrack.c +conntrack_LDFLAGS = -rdynamic + diff --git a/cli/src/conntrack.c b/cli/src/conntrack.c new file mode 100644 index 0000000..30fbf69 --- /dev/null +++ b/cli/src/conntrack.c @@ -0,0 +1,1131 @@ +/* + * (C) 2005 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Note: + * Yes, portions of this code has been stolen from iptables ;) + * Special thanks to the the Netfilter Core Team. + * Thanks to Javier de Miguel Rodriguez + * for introducing me to advanced firewalling stuff. + * + * --pablo 13/04/2005 + * + * 2005-04-16 Harald Welte : + * Add support for conntrack accounting and conntrack mark + * 2005-06-23 Harald Welte : + * Add support for expect creation + * 2005-09-24 Harald Welte : + * Remove remaints of "-A" + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_ARPA_INET_H +#include +#endif +#include +#include +#include +#include +#include "linux_list.h" +#include "conntrack.h" +#include +#include +#include + +static const char cmdflags[NUMBER_OF_CMD] += {'L','I','U','D','G','F','E','V','h','L','I','D','G','F','E'}; + +static const char cmd_need_param[NUMBER_OF_CMD] += { 2, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, 0, 2, 2 }; + +static const char optflags[NUMBER_OF_OPT] += {'s','d','r','q','p','t','u','z','e','[',']','{','}','a','m','i','f'}; + +static struct option original_opts[] = { + {"dump", 2, 0, 'L'}, + {"create", 1, 0, 'I'}, + {"delete", 1, 0, 'D'}, + {"update", 1, 0, 'U'}, + {"get", 1, 0, 'G'}, + {"flush", 1, 0, 'F'}, + {"event", 1, 0, 'E'}, + {"version", 0, 0, 'V'}, + {"help", 0, 0, 'h'}, + {"orig-src", 1, 0, 's'}, + {"orig-dst", 1, 0, 'd'}, + {"reply-src", 1, 0, 'r'}, + {"reply-dst", 1, 0, 'q'}, + {"protonum", 1, 0, 'p'}, + {"timeout", 1, 0, 't'}, + {"status", 1, 0, 'u'}, + {"zero", 0, 0, 'z'}, + {"event-mask", 1, 0, 'e'}, + {"tuple-src", 1, 0, '['}, + {"tuple-dst", 1, 0, ']'}, + {"mask-src", 1, 0, '{'}, + {"mask-dst", 1, 0, '}'}, + {"nat-range", 1, 0, 'a'}, + {"mark", 1, 0, 'm'}, + {"id", 2, 0, 'i'}, + {"family", 1, 0, 'f'}, + {0, 0, 0, 0} +}; + +#define OPTION_OFFSET 256 + +static struct nfct_handle *cth; +static struct option *opts = original_opts; +static unsigned int global_option_offset = 0; + +/* Table of legal combinations of commands and options. If any of the + * given commands make an option legal, that option is legal (applies to + * CMD_LIST and CMD_ZERO only). + * Key: + * 0 illegal + * 1 compulsory + * 2 optional + */ + +static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = +/* Well, it's better than "Re: Linux vs FreeBSD" */ +{ + /* s d r q p t u z e x y k l a m i f*/ +/*CT_LIST*/ {2,2,2,2,2,0,0,2,0,0,0,0,0,0,2,2,2}, +/*CT_CREATE*/ {2,2,2,2,1,1,1,0,0,0,0,0,0,2,2,0,0}, +/*CT_UPDATE*/ {2,2,2,2,1,2,2,0,0,0,0,0,0,0,2,2,0}, +/*CT_DELETE*/ {2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,2,0}, +/*CT_GET*/ {2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,2,0}, +/*CT_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*CT_EVENT*/ {2,2,2,2,2,0,0,0,2,0,0,0,0,0,2,0,0}, +/*VERSION*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*HELP*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*EXP_LIST*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2}, +/*EXP_CREATE*/{1,1,2,2,1,1,2,0,0,1,1,1,1,0,0,0,0}, +/*EXP_DELETE*/{1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0}, +/*EXP_GET*/ {1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0}, +/*EXP_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*EXP_EVENT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +}; + +static char *lib_dir = CONNTRACK_LIB_DIR; + +static LIST_HEAD(proto_list); + +void register_proto(struct ctproto_handler *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); +} + +static struct ctproto_handler *findproto(char *name) +{ + struct list_head *i; + struct ctproto_handler *cur = NULL, *handler = NULL; + + if (!name) + return handler; + + lib_dir = getenv("CONNTRACK_LIB_DIR"); + if (!lib_dir) + lib_dir = CONNTRACK_LIB_DIR; + + list_for_each(i, &proto_list) { + cur = (struct ctproto_handler *) i; + if (strcmp(cur->name, name) == 0) { + handler = cur; + break; + } + } + + if (!handler) { + char path[sizeof("ct_proto_.so") + + strlen(name) + strlen(lib_dir)]; + sprintf(path, "%s/ct_proto_%s.so", lib_dir, name); + if (dlopen(path, RTLD_NOW)) + handler = findproto(name); + else + fprintf(stderr, "%s\n", dlerror()); + } + + return handler; +} + +enum exittype { + OTHER_PROBLEM = 1, + PARAMETER_PROBLEM, + VERSION_PROBLEM +}; + +void extension_help(struct ctproto_handler *h) +{ + fprintf(stdout, "\n"); + fprintf(stdout, "Proto `%s' help:\n", h->name); + h->help(); +} + +void +exit_tryhelp(int status) +{ + fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n", + PROGNAME, PROGNAME); + exit(status); +} + +static void +exit_error(enum exittype status, char *msg, ...) +{ + va_list args; + + /* On error paths, make sure that we don't leak the memory + * reserved during options merging */ + if (opts != original_opts) { + free(opts); + opts = original_opts; + global_option_offset = 0; + } + va_start(args, msg); + fprintf(stderr,"%s v%s: ", PROGNAME, VERSION); + vfprintf(stderr, msg, args); + va_end(args); + fprintf(stderr, "\n"); + if (status == PARAMETER_PROBLEM) + exit_tryhelp(status); + exit(status); +} + +static void +generic_cmd_check(int command, int options) +{ + int i; + + for (i = 0; i < NUMBER_OF_CMD; i++) { + if (!(command & (1< illegal, 1 => legal, 0 => undecided. */ + + for (j = 0; j < NUMBER_OF_CMD; j++) { + if (!(command & (1<size; i++) + if (strncasecmp(str, p->parameter[i], strlen) == 0) { + *value |= p->value[i]; + ret = 1; + break; + } + + return ret; +} + +static void +parse_parameter(const char *arg, unsigned int *status, int parse_type) +{ + const char *comma; + + while ((comma = strchr(arg, ',')) != NULL) { + if (comma == arg + || !do_parse_parameter(arg, comma-arg, status, parse_type)) + exit_error(PARAMETER_PROBLEM,"Bad parameter `%s'", arg); + arg = comma+1; + } + + if (strlen(arg) == 0 + || !do_parse_parameter(arg, strlen(arg), status, parse_type)) + exit_error(PARAMETER_PROBLEM, "Bad parameter `%s'", arg); +} + +static void +add_command(unsigned int *cmd, const int newcmd, const int othercmds) +{ + if (*cmd & (~othercmds)) + exit_error(PARAMETER_PROBLEM, "Invalid commands combination\n"); + *cmd |= newcmd; +} + +unsigned int check_type(int argc, char *argv[]) +{ + char *table = NULL; + + /* Nasty bug or feature in getopt_long ? + * It seems that it behaves badly with optional arguments. + * Fortunately, I just stole the fix from iptables ;) */ + if (optarg) + return 0; + else if (optind < argc && argv[optind][0] != '-' + && argv[optind][0] != '!') + table = argv[optind++]; + + if (!table) + return 0; + + if (strncmp("expect", table, 6) == 0) + return 1; + else if (strncmp("conntrack", table, 9) == 0) + return 0; + else + exit_error(PARAMETER_PROBLEM, "unknown type `%s'\n", table); + + return 0; +} + +static void set_family(int *family, int new) +{ + if (*family == AF_UNSPEC) + *family = new; + else if (*family != new) + exit_error(PARAMETER_PROBLEM, "mismatched address family\n"); +} + +struct addr_parse { + struct in_addr addr; + struct in6_addr addr6; + unsigned int family; +}; + +int __parse_inetaddr(const char *cp, struct addr_parse *parse) +{ + if (inet_aton(cp, &parse->addr)) + return AF_INET; +#ifdef HAVE_INET_PTON_IPV6 + else if (inet_pton(AF_INET6, cp, &parse->addr6) > 0) + return AF_INET6; +#endif + + exit_error(PARAMETER_PROBLEM, "Invalid IP address `%s'.", cp); +} + +int parse_inetaddr(const char *cp, union nfct_address *address) +{ + struct addr_parse parse; + int ret; + + if ((ret = __parse_inetaddr(cp, &parse)) == AF_INET) + address->v4 = parse.addr.s_addr; + else if (ret == AF_INET6) + memcpy(address->v6, &parse.addr6, sizeof(parse.addr6)); + + return ret; +} + +/* Shamelessly stolen from libipt_DNAT ;). Ranges expected in network order. */ +static void +nat_parse(char *arg, int portok, struct nfct_nat *range) +{ + char *colon, *dash, *error; + struct addr_parse parse; + + memset(range, 0, sizeof(range)); + colon = strchr(arg, ':'); + + if (colon) { + int port; + + if (!portok) + exit_error(PARAMETER_PROBLEM, + "Need TCP or UDP with port specification"); + + port = atoi(colon+1); + if (port == 0 || port > 65535) + exit_error(PARAMETER_PROBLEM, + "Port `%s' not valid\n", colon+1); + + error = strchr(colon+1, ':'); + if (error) + exit_error(PARAMETER_PROBLEM, + "Invalid port:port syntax - use dash\n"); + + dash = strchr(colon, '-'); + if (!dash) { + range->l4min.tcp.port + = range->l4max.tcp.port + = htons(port); + } else { + int maxport; + + maxport = atoi(dash + 1); + if (maxport == 0 || maxport > 65535) + exit_error(PARAMETER_PROBLEM, + "Port `%s' not valid\n", dash+1); + if (maxport < port) + /* People are stupid. */ + exit_error(PARAMETER_PROBLEM, + "Port range `%s' funky\n", colon+1); + range->l4min.tcp.port = htons(port); + range->l4max.tcp.port = htons(maxport); + } + /* Starts with a colon? No IP info... */ + if (colon == arg) + return; + *colon = '\0'; + } + + dash = strchr(arg, '-'); + if (colon && dash && dash > colon) + dash = NULL; + + if (dash) + *dash = '\0'; + + if (__parse_inetaddr(arg, &parse) != AF_INET) + return; + + range->min_ip = parse.addr.s_addr; + if (dash) { + if (__parse_inetaddr(dash+1, &parse) != AF_INET) + return; + range->max_ip = parse.addr.s_addr; + } else + range->max_ip = parse.addr.s_addr; +} + +static void event_sighandler(int s) +{ + fprintf(stdout, "Now closing conntrack event dumping...\n"); + nfct_close(cth); + exit(0); +} + +static const char usage_commands[] = + "Commands:\n" + " -L [table] [options]\t\tList conntrack or expectation table\n" + " -G [table] parameters\t\tGet conntrack or expectation\n" + " -D [table] parameters\t\tDelete conntrack or expectation\n" + " -I [table] parameters\t\tCreate a conntrack or expectation\n" + " -U [table] parameters\t\tUpdate a conntrack\n" + " -E [table] [options]\t\tShow events\n" + " -F [table]\t\t\tFlush table\n"; + +static const char usage_tables[] = + "Tables: conntrack, expect\n"; + +static const char usage_conntrack_parameters[] = + "Conntrack parameters and options:\n" + " -a, --nat-range min_ip[-max_ip]\tNAT ip range\n" + " -m, --mark mark\t\t\tSet mark\n" + " -e, --event-mask eventmask\t\tEvent mask, eg. NEW,DESTROY\n" + " -z, --zero \t\t\t\tZero counters while listing\n" + ; + +static const char usage_expectation_parameters[] = + "Expectation parameters and options:\n" + " --tuple-src ip\tSource address in expect tuple\n" + " --tuple-dst ip\tDestination address in expect tuple\n" + " --mask-src ip\t\tSource mask address\n" + " --mask-dst ip\t\tDestination mask address\n"; + +static const char usage_parameters[] = + "Common parameters and options:\n" + " -s, --orig-src ip\t\tSource address from original direction\n" + " -d, --orig-dst ip\t\tDestination address from original direction\n" + " -r, --reply-src ip\t\tSource addres from reply direction\n" + " -q, --reply-dst ip\t\tDestination address from reply direction\n" + " -p, --protonum proto\t\tLayer 4 Protocol, eg. 'tcp'\n" + " -f, --family proto\t\tLayer 3 Protocol, eg. 'ipv6'\n" + " -t, --timeout timeout\t\tSet timeout\n" + " -u, --status status\t\tSet status, eg. ASSURED\n" + " -i, --id [id]\t\t\tShow or set conntrack ID\n" + ; + + +void usage(char *prog) { + fprintf(stdout, "Tool to manipulate conntrack and expectations. Version %s\n", VERSION); + fprintf(stdout, "Usage: %s [commands] [options]\n", prog); + + fprintf(stdout, "\n%s", usage_commands); + fprintf(stdout, "\n%s", usage_tables); + fprintf(stdout, "\n%s", usage_conntrack_parameters); + fprintf(stdout, "\n%s", usage_expectation_parameters); + fprintf(stdout, "\n%s", usage_parameters); +} + +#define CT_COMPARISON (CT_OPT_PROTO | CT_OPT_ORIG | CT_OPT_REPL | CT_OPT_MARK) + +static struct nfct_tuple orig, reply, mask; +static struct nfct_tuple exptuple; +static struct ctproto_handler *h; +static union nfct_protoinfo proto; +static struct nfct_nat range; +static struct nfct_conntrack *ct; +static struct nfct_expect *exp; +static unsigned long timeout; +static unsigned int status; +static unsigned int mark; +static unsigned int id = NFCT_ANY_ID; +static struct nfct_conntrack_compare cmp; + +int main(int argc, char *argv[]) +{ + int c; + unsigned int command = 0, options = 0; + unsigned int type = 0, event_mask = 0; + unsigned int l3flags = 0, l4flags = 0, metaflags = 0; + int res = 0; + int family = AF_UNSPEC; + struct nfct_conntrack_compare *pcmp; + + while ((c = getopt_long(argc, argv, + "L::I::U::D::G::E::F::hVs:d:r:q:p:t:u:e:a:z[:]:{:}:m:i::f:", + opts, NULL)) != -1) { + switch(c) { + case 'L': + type = check_type(argc, argv); + if (type == 0) + add_command(&command, CT_LIST, CT_NONE); + else if (type == 1) + add_command(&command, EXP_LIST, CT_NONE); + break; + case 'I': + type = check_type(argc, argv); + if (type == 0) + add_command(&command, CT_CREATE, CT_NONE); + else if (type == 1) + add_command(&command, EXP_CREATE, CT_NONE); + break; + case 'U': + type = check_type(argc, argv); + if (type == 0) + add_command(&command, CT_UPDATE, CT_NONE); + else + exit_error(PARAMETER_PROBLEM, "Can't update " + "expectations"); + break; + case 'D': + type = check_type(argc, argv); + if (type == 0) + add_command(&command, CT_DELETE, CT_NONE); + else if (type == 1) + add_command(&command, EXP_DELETE, CT_NONE); + break; + case 'G': + type = check_type(argc, argv); + if (type == 0) + add_command(&command, CT_GET, CT_NONE); + else if (type == 1) + add_command(&command, EXP_GET, CT_NONE); + break; + case 'F': + type = check_type(argc, argv); + if (type == 0) + add_command(&command, CT_FLUSH, CT_NONE); + else if (type == 1) + add_command(&command, EXP_FLUSH, CT_NONE); + break; + case 'E': + type = check_type(argc, argv); + if (type == 0) + add_command(&command, CT_EVENT, CT_NONE); + else if (type == 1) + add_command(&command, EXP_EVENT, CT_NONE); + break; + case 'V': + add_command(&command, CT_VERSION, CT_NONE); + break; + case 'h': + add_command(&command, CT_HELP, CT_NONE); + break; + case 's': + options |= CT_OPT_ORIG_SRC; + if (optarg) { + orig.l3protonum = + parse_inetaddr(optarg, &orig.src); + set_family(&family, orig.l3protonum); + if (orig.l3protonum == AF_INET) + l3flags |= IPV4_ORIG_SRC; + else if (orig.l3protonum == AF_INET6) + l3flags |= IPV6_ORIG_SRC; + } + break; + case 'd': + options |= CT_OPT_ORIG_DST; + if (optarg) { + orig.l3protonum = + parse_inetaddr(optarg, &orig.dst); + set_family(&family, orig.l3protonum); + if (orig.l3protonum == AF_INET) + l3flags |= IPV4_ORIG_DST; + else if (orig.l3protonum == AF_INET6) + l3flags |= IPV6_ORIG_DST; + } + break; + case 'r': + options |= CT_OPT_REPL_SRC; + if (optarg) { + reply.l3protonum = + parse_inetaddr(optarg, &reply.src); + set_family(&family, reply.l3protonum); + if (orig.l3protonum == AF_INET) + l3flags |= IPV4_REPL_SRC; + else if (orig.l3protonum == AF_INET6) + l3flags |= IPV6_REPL_SRC; + } + break; + case 'q': + options |= CT_OPT_REPL_DST; + if (optarg) { + reply.l3protonum = + parse_inetaddr(optarg, &reply.dst); + set_family(&family, reply.l3protonum); + if (orig.l3protonum == AF_INET) + l3flags |= IPV4_REPL_DST; + else if (orig.l3protonum == AF_INET6) + l3flags |= IPV6_REPL_DST; + } + break; + case 'p': + options |= CT_OPT_PROTO; + h = findproto(optarg); + if (!h) + exit_error(PARAMETER_PROBLEM, "proto needed\n"); + orig.protonum = h->protonum; + reply.protonum = h->protonum; + exptuple.protonum = h->protonum; + mask.protonum = h->protonum; + opts = merge_options(opts, h->opts, + &h->option_offset); + break; + case 't': + options |= CT_OPT_TIMEOUT; + if (optarg) + timeout = atol(optarg); + break; + case 'u': { + if (!optarg) + continue; + + options |= CT_OPT_STATUS; + parse_parameter(optarg, &status, PARSE_STATUS); + break; + } + case 'e': + options |= CT_OPT_EVENT_MASK; + parse_parameter(optarg, &event_mask, PARSE_EVENT); + break; + case 'z': + options |= CT_OPT_ZERO; + break; + case '{': + options |= CT_OPT_MASK_SRC; + if (optarg) { + mask.l3protonum = + parse_inetaddr(optarg, &mask.src); + set_family(&family, mask.l3protonum); + } + break; + case '}': + options |= CT_OPT_MASK_DST; + if (optarg) { + mask.l3protonum = + parse_inetaddr(optarg, &mask.dst); + set_family(&family, mask.l3protonum); + } + break; + case '[': + options |= CT_OPT_EXP_SRC; + if (optarg) { + exptuple.l3protonum = + parse_inetaddr(optarg, &exptuple.src); + set_family(&family, exptuple.l3protonum); + } + break; + case ']': + options |= CT_OPT_EXP_DST; + if (optarg) { + exptuple.l3protonum = + parse_inetaddr(optarg, &exptuple.dst); + set_family(&family, exptuple.l3protonum); + } + break; + case 'a': + options |= CT_OPT_NATRANGE; + set_family(&family, AF_INET); + nat_parse(optarg, 1, &range); + break; + case 'm': + options |= CT_OPT_MARK; + mark = atol(optarg); + metaflags |= NFCT_MARK; + break; + case 'i': { + char *s = NULL; + options |= CT_OPT_ID; + if (optarg) + break; + else if (optind < argc && argv[optind][0] != '-' + && argv[optind][0] != '!') + s = argv[optind++]; + + if (s) + id = atol(s); + break; + } + case 'f': + options |= CT_OPT_FAMILY; + if (strncmp(optarg, "ipv4", strlen("ipv4")) == 0) + set_family(&family, AF_INET); + else if (strncmp(optarg, "ipv6", strlen("ipv6")) == 0) + set_family(&family, AF_INET6); + else + exit_error(PARAMETER_PROBLEM, "Unknown " + "protocol family\n"); + break; + default: + if (h && h->parse_opts + &&!h->parse_opts(c - h->option_offset, argv, &orig, + &reply, &exptuple, &mask, &proto, + &l4flags)) + exit_error(PARAMETER_PROBLEM, "parse error\n"); + + /* Unknown argument... */ + if (!h) { + usage(argv[0]); + exit_error(PARAMETER_PROBLEM, "Missing " + "arguments...\n"); + } + break; + } + } + + /* default family */ + if (family == AF_UNSPEC) + family = AF_INET; + + generic_cmd_check(command, options); + generic_opt_check(command, options); + + if (!(command & CT_HELP) + && h && h->final_check + && !h->final_check(l4flags, command, &orig, &reply)) { + usage(argv[0]); + extension_help(h); + exit_error(PARAMETER_PROBLEM, "Missing protocol arguments!\n"); + } + + switch(command) { + + case CT_LIST: + cth = nfct_open(CONNTRACK, 0); + if (!cth) + exit_error(OTHER_PROBLEM, "Can't open handler"); + + if (options & CT_COMPARISON) { + + if (options & CT_OPT_ZERO) + exit_error(PARAMETER_PROBLEM, "Can't use -z " + "with filtering parameters"); + + ct = nfct_conntrack_alloc(&orig, &reply, timeout, + &proto, status, mark, id, + NULL); + if (!ct) + exit_error(OTHER_PROBLEM, "Not enough memory"); + + cmp.ct = ct; + cmp.flags = metaflags; + cmp.l3flags = l3flags; + cmp.l4flags = l4flags; + pcmp = &cmp; + } + + if (options & CT_OPT_ID) + nfct_register_callback(cth, + nfct_default_conntrack_display_id, + (void *) pcmp); + else + nfct_register_callback(cth, + nfct_default_conntrack_display, + (void *) pcmp); + + if (options & CT_OPT_ZERO) + res = + nfct_dump_conntrack_table_reset_counters(cth, family); + else + res = nfct_dump_conntrack_table(cth, family); + nfct_close(cth); + break; + + case EXP_LIST: + cth = nfct_open(EXPECT, 0); + if (!cth) + exit_error(OTHER_PROBLEM, "Can't open handler"); + if (options & CT_OPT_ID) + nfct_register_callback(cth, + nfct_default_expect_display_id, + NULL); + else + nfct_register_callback(cth, + nfct_default_expect_display, + NULL); + res = nfct_dump_expect_list(cth, family); + nfct_close(cth); + break; + + case CT_CREATE: + if ((options & CT_OPT_ORIG) + && !(options & CT_OPT_REPL)) { + reply.l3protonum = orig.l3protonum; + memcpy(&reply.src, &orig.dst, sizeof(reply.src)); + memcpy(&reply.dst, &orig.src, sizeof(reply.dst)); + } else if (!(options & CT_OPT_ORIG) + && (options & CT_OPT_REPL)) { + orig.l3protonum = reply.l3protonum; + memcpy(&orig.src, &reply.dst, sizeof(orig.src)); + memcpy(&orig.dst, &reply.src, sizeof(orig.dst)); + } + if (options & CT_OPT_NATRANGE) + ct = nfct_conntrack_alloc(&orig, &reply, timeout, + &proto, status, mark, id, + &range); + else + ct = nfct_conntrack_alloc(&orig, &reply, timeout, + &proto, status, mark, id, + NULL); + if (!ct) + exit_error(OTHER_PROBLEM, "Not Enough memory"); + + cth = nfct_open(CONNTRACK, 0); + if (!cth) { + nfct_conntrack_free(ct); + exit_error(OTHER_PROBLEM, "Can't open handler"); + } + res = nfct_create_conntrack(cth, ct); + nfct_close(cth); + nfct_conntrack_free(ct); + break; + + case EXP_CREATE: + if (options & CT_OPT_ORIG) + exp = nfct_expect_alloc(&orig, &exptuple, + &mask, timeout, id); + else if (options & CT_OPT_REPL) + exp = nfct_expect_alloc(&reply, &exptuple, + &mask, timeout, id); + if (!exp) + exit_error(OTHER_PROBLEM, "Not enough memory"); + + cth = nfct_open(EXPECT, 0); + if (!cth) { + nfct_expect_free(exp); + exit_error(OTHER_PROBLEM, "Can't open handler"); + } + res = nfct_create_expectation(cth, exp); + nfct_expect_free(exp); + nfct_close(cth); + break; + + case CT_UPDATE: + if ((options & CT_OPT_ORIG) + && !(options & CT_OPT_REPL)) { + reply.l3protonum = orig.l3protonum; + memcpy(&reply.src, &orig.dst, sizeof(reply.src)); + memcpy(&reply.dst, &orig.src, sizeof(reply.dst)); + } else if (!(options & CT_OPT_ORIG) + && (options & CT_OPT_REPL)) { + orig.l3protonum = reply.l3protonum; + memcpy(&orig.src, &reply.dst, sizeof(orig.src)); + memcpy(&orig.dst, &reply.src, sizeof(orig.dst)); + } + ct = nfct_conntrack_alloc(&orig, &reply, timeout, + &proto, status, mark, id, + NULL); + if (!ct) + exit_error(OTHER_PROBLEM, "Not enough memory"); + + cth = nfct_open(CONNTRACK, 0); + if (!cth) { + nfct_conntrack_free(ct); + exit_error(OTHER_PROBLEM, "Can't open handler"); + } + res = nfct_update_conntrack(cth, ct); + nfct_conntrack_free(ct); + nfct_close(cth); + break; + + case CT_DELETE: + if (!(options & CT_OPT_ORIG) && !(options & CT_OPT_REPL)) + exit_error(PARAMETER_PROBLEM, "Can't kill conntracks " + "just by its ID"); + cth = nfct_open(CONNTRACK, 0); + if (!cth) + exit_error(OTHER_PROBLEM, "Can't open handler"); + if (options & CT_OPT_ORIG) + res = nfct_delete_conntrack(cth, &orig, + NFCT_DIR_ORIGINAL, + id); + else if (options & CT_OPT_REPL) + res = nfct_delete_conntrack(cth, &reply, + NFCT_DIR_REPLY, + id); + nfct_close(cth); + break; + + case EXP_DELETE: + cth = nfct_open(EXPECT, 0); + if (!cth) + exit_error(OTHER_PROBLEM, "Can't open handler"); + if (options & CT_OPT_ORIG) + res = nfct_delete_expectation(cth, &orig, id); + else if (options & CT_OPT_REPL) + res = nfct_delete_expectation(cth, &reply, id); + nfct_close(cth); + break; + + case CT_GET: + cth = nfct_open(CONNTRACK, 0); + if (!cth) + exit_error(OTHER_PROBLEM, "Can't open handler"); + nfct_register_callback(cth, nfct_default_conntrack_display, + NULL); + if (options & CT_OPT_ORIG) + res = nfct_get_conntrack(cth, &orig, + NFCT_DIR_ORIGINAL, id); + else if (options & CT_OPT_REPL) + res = nfct_get_conntrack(cth, &reply, + NFCT_DIR_REPLY, id); + nfct_close(cth); + break; + + case EXP_GET: + cth = nfct_open(EXPECT, 0); + if (!cth) + exit_error(OTHER_PROBLEM, "Can't open handler"); + nfct_register_callback(cth, nfct_default_expect_display, + NULL); + if (options & CT_OPT_ORIG) + res = nfct_get_expectation(cth, &orig, id); + else if (options & CT_OPT_REPL) + res = nfct_get_expectation(cth, &reply, id); + nfct_close(cth); + break; + + case CT_FLUSH: + cth = nfct_open(CONNTRACK, 0); + if (!cth) + exit_error(OTHER_PROBLEM, "Can't open handler"); + res = nfct_flush_conntrack_table(cth, AF_INET); + nfct_close(cth); + break; + + case EXP_FLUSH: + cth = nfct_open(EXPECT, 0); + if (!cth) + exit_error(OTHER_PROBLEM, "Can't open handler"); + res = nfct_flush_expectation_table(cth, AF_INET); + nfct_close(cth); + break; + + case CT_EVENT: + if (options & CT_OPT_EVENT_MASK) + cth = nfct_open(CONNTRACK, event_mask); + else + cth = nfct_open(CONNTRACK, NFCT_ALL_CT_GROUPS); + + if (!cth) + exit_error(OTHER_PROBLEM, "Can't open handler"); + signal(SIGINT, event_sighandler); + + if (options & CT_COMPARISON) { + ct = nfct_conntrack_alloc(&orig, &reply, timeout, + &proto, status, mark, id, + NULL); + if (!ct) + exit_error(OTHER_PROBLEM, "Not enough memory"); + + cmp.ct = ct; + cmp.flags = metaflags; + cmp.l3flags = l3flags; + cmp.l4flags = l4flags; + pcmp = &cmp; + } + + nfct_register_callback(cth, + nfct_default_conntrack_event_display, + (void *) pcmp); + res = nfct_event_conntrack(cth); + nfct_close(cth); + break; + + case EXP_EVENT: + cth = nfct_open(EXPECT, NF_NETLINK_CONNTRACK_EXP_NEW); + if (!cth) + exit_error(OTHER_PROBLEM, "Can't open handler"); + signal(SIGINT, event_sighandler); + nfct_register_callback(cth, nfct_default_expect_display, + NULL); + res = nfct_event_expectation(cth); + nfct_close(cth); + break; + + case CT_VERSION: + fprintf(stdout, "%s v%s\n", PROGNAME, VERSION); + break; + case CT_HELP: + usage(argv[0]); + if (options & CT_OPT_PROTO) + extension_help(h); + break; + default: + usage(argv[0]); + break; + } + + if (opts != original_opts) { + free(opts); + opts = original_opts; + global_option_offset = 0; + } + + if (res < 0) { + fprintf(stderr, "Operation failed: %s\n", err2str(res, command)); + exit(OTHER_PROBLEM); + } + + return 0; +} diff --git a/cli/test.sh b/cli/test.sh new file mode 100644 index 0000000..4694236 --- /dev/null +++ b/cli/test.sh @@ -0,0 +1,110 @@ +CONNTRACK=conntrack + +SRC=1.1.1.1 +DST=2.2.2.2 +SPORT=2005 +DPORT=21 + +case $1 in + dump) + echo "Dumping conntrack table" + $CONNTRACK -L + ;; + flush) + echo "Flushing conntrack table" + $CONNTRACK -F + ;; + new) + echo "creating a new conntrack" + $CONNTRACK -I --orig-src $SRC --orig-dst $DST \ + --reply-src $DST --reply-dst $SRC -p tcp \ + --orig-port-src $SPORT --orig-port-dst $DPORT \ + --reply-port-src $DPORT --reply-port-dst $SPORT \ + --state LISTEN -u SEEN_REPLY -t 50 + ;; + new-simple) + echo "creating a new conntrack (simplified)" + $CONNTRACK -I --orig-src $SRC --orig-dst $DST \ + -p tcp --orig-port-src $SPORT --orig-port-dst $DPORT \ + --state LISTEN -u SEEN_REPLY -t 50 + ;; + new-nat) + echo "creating a new conntrack (NAT)" + $CONNTRACK -I --orig-src $SRC --orig-dst $DST \ + -p tcp --orig-port-src $SPORT --orig-port-dst $DPORT \ + --state LISTEN -u SEEN_REPLY,SRC_NAT -t 50 -a 8.8.8.8 + ;; + get) + echo "getting a conntrack" + $CONNTRACK -G --orig-src $SRC --orig-dst $DST \ + -p tcp --orig-port-src $SPORT --orig-port-dst $DPORT \ + --reply-port-src $DPORT --reply-port-dst $SPORT + ;; + change) + echo "change a conntrack" + $CONNTRACK -U --orig-src $SRC --orig-dst $DST \ + --reply-src $DST --reply-dst $SRC -p tcp \ + --orig-port-src $SPORT --orig-port-dst $DPORT \ + --reply-port-src $DPORT --reply-port-dst $SPORT \ + --state TIME_WAIT -u ASSURED,SEEN_REPLY -t 500 + ;; + delete) + $CONNTRACK -D --orig-src $SRC --orig-dst $DST \ + -p tcp --orig-port-src $SPORT --orig-port-dst $DPORT + ;; + output) + proc=$(cat /proc/net/ip_conntrack | wc -l) + netl=$($CONNTRACK -L | wc -l) + count=$(cat /proc/sys/net/ipv4/netfilter/ip_conntrack_count) + if [ $proc -ne $netl ]; then + echo "proc is $proc and netl is $netl and count is $count" + else + if [ $proc -ne $count ]; then + echo "proc is $proc and netl is $netl and count is $count" + else + echo "now $proc" + fi + fi + ;; + dump-expect) + $CONNTRACK -L expect + ;; + flush-expect) + $CONNTRACK -F expect + ;; + create-expect) + # requires modprobe ip_conntrack_ftp + $CONNTRACK -I expect --orig-src $SRC --orig-dst $DST \ + --tuple-src 4.4.4.4 --tuple-dst 5.5.5.5 \ + --mask-src 255.255.255.0 --mask-dst 255.255.255.255 \ + -p tcp --orig-port-src $SPORT --orig-port-dst $DPORT \ + -t 200 --tuple-port-src 10 --tuple-port-dst 300 \ + --mask-port-src 10 --mask-port-dst 300 + ;; + get-expect) + $CONNTRACK -G expect --orig-src 4.4.4.4 --orig-dst 5.5.5.5 \ + --p tcp --orig-port-src 0 --orig-port-dst 0 \ + --mask-port-src 10 --mask-port-dst 11 + ;; + delete-expect) + $CONNTRACK -D expect --orig-src 4.4.4.4 \ + --orig-dst 5.5.5.5 -p tcp --orig-port-src 0 \ + --orig-port-dst 0 --mask-port-src 10 --mask-port-dst 11 + ;; + *) + echo "Usage: $0 [dump" + echo " |new" + echo " |new-simple" + echo " |new-nat" + echo " |get" + echo " |change" + echo " |delete" + echo " |output" + echo " |flush" + echo " |dump-expect" + echo " |flush-expect" + echo " |create-expect" + echo " |get-expect" + echo " |delete-expect]" + ;; +esac diff --git a/configure.in b/configure.in deleted file mode 100644 index 1b1b391..0000000 --- a/configure.in +++ /dev/null @@ -1,72 +0,0 @@ -AC_INIT - -AC_CANONICAL_SYSTEM - -AM_INIT_AUTOMAKE(conntrack, 1.00beta2) - -AC_PROG_CC -AM_PROG_LIBTOOL -AC_PROG_INSTALL -AC_PROG_LN_S - -case $target in -*-*-linux*) ;; -*) AC_MSG_ERROR([Linux only, dude!]);; -esac - -dnl Dependencies -LIBNFCONNTRACK_REQUIRED=0.0.31 - -AC_CHECK_LIB(dl, dlopen) - -PKG_CHECK_MODULES(LIBNFCONNTRACK, libnetfilter_conntrack >= $LIBNFCONNTRACK_REQUIRED,, - AC_MSG_ERROR(Cannot find libnetfilter_conntrack >= $LIBNFCONNTRACK_REQUIRED)) - -AC_CHECK_HEADERS(arpa/inet.h) -dnl check for inet_pton -AC_CHECK_FUNCS(inet_pton) -dnl Some systems have it, but not IPv6 -if test "$ac_cv_func_inet_pton" = "yes" ; then -AC_MSG_CHECKING(if inet_pton supports IPv6) -AC_TRY_RUN( - [ -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif -int main() - { - struct in6_addr addr6; - if (inet_pton(AF_INET6, "::1", &addr6) < 1) - exit(1); - else - exit(0); - } - ], [ AC_MSG_RESULT(yes) - AC_DEFINE_UNQUOTED(HAVE_INET_PTON_IPV6, 1, [Define to 1 if inet_pton supports IPv6.]) - ], AC_MSG_RESULT(no), AC_MSG_RESULT(no)) -fi - -dnl-------------------------------- - -if test ! -z "$libdir"; then - MODULE_DIR="\\\"$libdir/conntrack/\\\"" - CFLAGS="$CFLAGS -DCONNTRACK_LIB_DIR=$MODULE_DIR" -fi - -dnl-------------------------------- - -CFLAGS="$CFLAGS $LIBNFCONNTRACK_CFLAGS" -CONNTRACK_LIBS="$LIBNFCONNTRACK_LIBS" - -AC_SUBST(CONNTRACK_LIBS) - -AC_OUTPUT(Makefile src/Makefile extensions/Makefile include/Makefile) diff --git a/conntrack.8 b/conntrack.8 deleted file mode 100644 index 307180b..0000000 --- a/conntrack.8 +++ /dev/null @@ -1,142 +0,0 @@ -.TH CONNTRACK 8 "Jun 23, 2005" "" "" - -.\" Man page written by Harald Welte . diff --git a/daemon/AUTHORS b/daemon/AUTHORS new file mode 100644 index 0000000..e6c2f6b --- /dev/null +++ b/daemon/AUTHORS @@ -0,0 +1 @@ +Pablo Neira Ayuso diff --git a/daemon/CHANGELOG b/daemon/CHANGELOG new file mode 100644 index 0000000..afab61d --- /dev/null +++ b/daemon/CHANGELOG @@ -0,0 +1,184 @@ +version 0.9.3 (yet unreleased) +------------------------------ +o fix commit of confirmed expectations (reported by Nishit Shah) +o fix double increment of counters in cache_update_force() (Niko Tyni) +o nl_dump_handler must return NFCT_CB_CONTINUE (Niko Tyni) +o initialize buffer in nl_event_handler() and nl_dump_handler() (Niko Tyni) +o CacheCommit value can be set via conntrackd.conf for the NACK approach +o fix leaks in the hashtable/cache flush path (Niko Tyni) +o fix leak if a connection already exists in the cache (Niko Tyni) +o introduce a new header that encapsulates netlink messages +o remove all '_entry' tail from all functions in cache.c +o split cache.c: move cache iterators to file cache_iterators.c +o fix inconsistencies in the cache API related to counters +o cleanup 'usage' message +o fix typo in examples/sync/nack/node1/conntrackd.conf +o introduce message checksumming as described in RFC1071 (enabled by default) +o major cleanups in the synchronization code +o just warn once that the maximum netlink socket buffer has been reached +o fix ignore conntrack entries by IP and introduce ignore pool abstraction layer +o introduce netlink socket buffer overrun handler +o constification of hash, compare and hashtable_test functions in hash.c +o introduce ACKnowledgement mechanisms to reduce the size of the resend queue +o remove OK messages at startup since provide useless data +o fix compilation warning in mcast.c: recvfrom takes socklen_t not size_t +o add a lock per buffer: makes buffer code thread safe +o introduce 'Replicate' clause to explicitely set states to be replicated +o kill cache feature abuse: introduce nicer cache hooks for sync algorithms +o fix oversized buffer allocated in the stack in the cache functions +o add support to dump internal/external cache in XML format '-x' + +version 0.9.2 (2006/01/17) +-------------------------- +o remove spamming packet lost messages +o generalize network netlink sequence tracking +o fix bogus error message on resync `-R' +o fix endianess issues in the network netlink message +o introduce generic netlink multicast primitives to send and receive +o fix bogus replayed multicast message due to sequence numbering wraparound +o introduce counter for malformed netlink messages received +o introduce a new syntax for the `Sync' section in the configuration file +o several cleanups and remove unused variables +o add autostuff to include examples in the tarball (reported by Victor Lozano) +o use the new API available in libnetfilter_conntrack-0.0.50 +o implement a NACK based protocol for replication + +version 0.9.1 (2006/11/06) +-------------------------- +o conntrackd requires kernel >= 2.6.18 +o remove bogus TIMERS_MODE constant +o implement bulk mode '-B': first works to address the preemption issue +o fix minor reduction conflicts in the configfile grammar +o check for CAP_NET_ADMIN instead of requiring root privileges +o check that linux/capability.h exists +o fix formatting at dump statistics '-s' +o move dump traffic stats before multicast traffic stats +o move event and dump handler to a generic infrastructure: kill events.c file +o kill unused function inc_ct_stats +o kill file resync.h +o cleanup broadcast_sync: renamed to mcast_send_sync +o sed 's/perror/debug/g' local.c +o fix bogus increment of update_fail stats at dump stage +o display descriptive error if we can't connect to conntrackd via UNIX socket +o remove debugging message from alarm.c +o move dump_mcast_stats to mcast.c where it really belongs +o rename stats.c to traffic_stats.c +o check for replayed/lost multicast message: simple seq tracking w/o recovery +o reissue nfnl_catch on ENOENT error: a message for other subsystem +o remove test/ directory in tree +o improve cache commit stats +o kill last_commit and last_flush from cache statistics: use the logfile +o recover cache naming for dump stats `-s' +o display multicast sequence tracking statistics: packets lost and replayed +o zero ct_sync_state and ct_stats_state structures after allocation +o improve keepalived scripts: + - resync with conntrack table on transition to master + - send bulk on transition to backup +o implement alarm cascade of ten levels +o implement timer cache flavour: limited life of entries in the external cache +o implement a global lock that protects operation with conntrack entries +o remove debug checking in cache_del_entry +o set a reduced timeout for committed entries: 180 seconds by default +o update comments on the sync-mode code +o introduce delay destroy messages facility +o increase timer for external states from 60 to 180 seconds +o remove unused replicate/dont_replicated constants +o fix cache entry clashing issue (reported by Maik Hentsche) +o fix bogus increment of error stats in the external cache +o remove pollution generated by `[REQ] cache dump' message from logfile + +version 0.9.0 (2006/09/17) +-------------------------- +o implement initial for IPv6 (untested) +o implement generic extensible cache: kill the internal and external caches +o implement persistence cache feature +o implement lifetime cache feature +o modify UNIX facilities identification numbers: + separate master conntrack facilities and internal plugin facilities +o break backward compatibility of configuration file: + remove IgnoreLoopback, use IgnoreTrafficFor instead + remove IgnoreMulticastTraffic, use IgnoreTrafficFor instead +o merge event/event_subsys and sync/sync_subsys initialization to run.c +o improve control of the iteration process in the hashtables +o fix wrong locking in the alarm thread +o supersede AcceptNAT by StripNAT clause +o replace ignore traffic array by a hashtable +o move lockfile checking before daemonization +o on initialization error give a descriptive error +o introduce netlink socket size grown limitator +o introduce force resync with master conntrack table facility '-R' +o ignore SIGPIPE signal +o kill post_step since it is not used anymore + +version 0.8.3 (2006/09/03) +-------------------------- +Author: Maik Hentsche + +o Fix typo in conntrackd -h +o Disable debugging messages by default +o No signals while signals handlings +o Add extra checkings at forking +o Check maximum size for file passed via -C + +Author: Pablo Neira Ayuso + +o retry select() if EINTR is returned (Reported by Maik Hentsche) +o Fix bug in slist_for_each_entry (Reported by Maik Hetsche) +o Signal handler registration done after intialization +o Implement alarm thread (based on Maik Hentsche's patch) +o Fix segfault on conntrackd -k (Reported by Maik Hentsche) +o Fix bug on alarm removal (Reported by Maik Hentsche) +o configure stops if bison, flex or yacc are not installed + +version 0.8.2 (2006/07/05) +-------------------------- +o RelaxTransitions clause introduced in Sync mode +o multicast messages sequence tracking +o SocketBufferSize clause to set up the netlink socket buffer +o use new libnfnetlink API to solve limitations of nfnl_listen +o extra sanity checkings for netlink multicast messages +o improve statistics +o tons of cleanups 8) + +version 0.8.1 (2006/06/13) +-------------------------- +o -f now just flushes the internal and external caches +o -F flushes the master conntrack table +o fix segfault under heavy load and signal received +o added -S mode for statistics: still needs more thinking + +version 0.8.0 (2006/06/11) +-------------------------- +o more work to generalize the daemon: now it's ready to implement +modular support for adaptive timers and conntrack statistics, time +to implement them ;). This is *still* a work in progress. + +version 0.7.2 (2006/06/05) +-------------------------- +o stupid bug in normal and alarm caches initialization: flush unset +o fix racy signal handling + +version 0.7.1 (2006/06/05) +-------------------------- +o Bugfix for multicast sockets communication + +version 0.7 (2006/06/01) +------------------------ +o Major code re-structuration: internal and external cache abstraction +o sequence tracking for event messages +o expect more changes, I still dislike some stuff in its current status ;) + +version 0.6 (2006/05/31) +------------------------ +o Lock file support +o use new API nfct_conntrack_event_raw +o major code clean ups + +version 0.5 (2006/05/30) +------------------------- +o Fix multicast server binds to wrong interface +o Include clause `IgnoreProtocol', deprecates IgnoreUDP and IgnoreICMP + +version 0.4 (2006/05/29) +------------------------ +o Initial release diff --git a/daemon/CONTRIBUTORS b/daemon/CONTRIBUTORS new file mode 100644 index 0000000..c5e40b4 --- /dev/null +++ b/daemon/CONTRIBUTORS @@ -0,0 +1,3 @@ +Maik Hentsche : + - Feedback & Brainstorming + - Bug hunting diff --git a/daemon/INSTALL b/daemon/INSTALL new file mode 100644 index 0000000..0de8dc0 --- /dev/null +++ b/daemon/INSTALL @@ -0,0 +1,199 @@ +Copyright (C) 2006-2007 Pablo Neira Ayuso + +1.Basic Installation +==================== + + To compile and install 'conntrackd' just follow the classical steps: + + $ ./configure + $ make + # make install + # mkdir /etc/conntrackd/ + +2.1. Synchronization Mode +========================= + + Conntrackd can replicate the status of the connections that are currently + being processed by your stateful firewall based on Linux. This section + describes how to setup the daemon in synchronization mode: + +2.1.1. Requirements + + You have to install the following software in order to get conntrackd working, + make sure that you have installed them correctly before going forward: + + o linux kernel version >= 2.6.18 (http://www.kernel.org) with support for: + - connection tracking system (quite obvious ;) + - nfnetlink + - ctnetlink (ip_conntrack_netlink) + - connection tracking event notification API + + o libnfnetlink: the netfilter netlink library + + Since conntrackd version 0.9.2 you can used the official release availble at + http://www.netfilter.org/projects/libnfnetlink/files/ + + Up to conntrackd version 0.9.1 use the unofficial release available at the + download section + + o libnetfilter_conntrack: the netfilter conntrack library + + Since conntrackd version 0.9.2 you can used the official release availble at + http://www.netfilter.org/projects/libnetfilter_conntrack/files/ + + Up to conntrackd version 0.9.1 use the unnoficial release available at the + download section + + o Keepalived version 1.x (http://www.keepalived.org) + check if your distribution comes with a recent version + +2.1.2. Configuration + + 1) Setting up keepalived + + There is an example file available inside the conntrackd tarball: + + For node 1: conntrackd-x.x.x/examples/sync/node1/keepalived.conf + For node 2: conntrackd-x.x.x/examples/sync/node2/keepalived.conf + + These files can be used to set up a simple VRRP cluster composed of + two machines that hold the virtual IPs 192.168.0.100 on eth0 and + 192.168.1.100 on eth1. + + If you are not familiar with keepalived, please read the official + docs available at http://www.keepalived.org + + Please, make sure that keepalived is correctly working before passing + to step 2) + + 2) Setting up conntrackd + + To setup 'conntrackd' in synchronization mode, you have to put the + configuration file in the directory /etc/conntrackd. + + On node 1: + # cp examples/sync/_type_/node1/conntrackd.conf /etc/conntrackd.conf + + On node 2: + # cp examples/sync/_type_/node1/conntrackd.conf /etc/conntrackd.conf + + Where _type_ is the synchronization type selected, currently there are + two: the persistent mode and the NACK mode. The persistent mode consumes + more resources than the NACK mode, however the NACK mode is still + experimental + + Do not forget to edit the files in order to adapt them to the + setting that you are deploying. + + Note: If you don't want to put the config file under /etc/conntrackd, + just tell conntrackd where to find it passing the option -C + + 3) Running conntrackd + + Conntrackd can run in console mode, in that case just type 'conntrackd', + otherwise, if you want to run it in daemon mode the type 'conntrackd -d'. + + 4) Checking that conntrackd is working fine + + Conntrackd comes with several facilities to check its status: + + - Dump the cache of connections that are currently being processed by + this node (aka. internal cache): + + # conntrackd -i + + - Dump the cache of connections that has been transfered from + others active nodes in the network (aka. external cache) + + # conntrackd -e + + - Dump statistics collected by the replication daemon: + + # conntrackd -s + + 5) Setting up interaction with keepalived + + If keepalived detects the failure of the active node, then it designates + a candidate node that will replace the failing active. On such event, + the external cache, eg. the cache that contains the connections processed + by other nodes, must be commited. To commit the external cache, just type: + + # conntrackd -c + + See that keepalived provides a shell script interface to interact with + other programs, so we can automate the process of commiting the external + cache by introducing the following line in the keepalived file: + + notify_master /etc/conntrackd/script_master.sh + + The script 'script_master.sh' just the following: + + #!/bin/sh + /usr/sbin/conntrackd -c + + Therefore, on failure event, the candidate node takes over the virtual + IPs and the connections that the failing active was processing. Observe + that this file differs for the NACK mode. + + 6) Disable TCP window tracking + + Until the appropiate patches don't go into kernel mainline, you will have + to disable TCP window tracking, consider this as a temporary solution: + + # echo 1 > /proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_be_liberal + +2.2. Statistics mode +==================== + + Conntrackd can also run as statistics daemon, if you are not interested in + this mode, just skip it. It is not required in order to get the + synchronization mode working. This section details how to setup the daemon + in statistics mode: + +2.2.1. Requirements + + You have to install the following software in order to get conntrackd working, + make sure that you have them installed correctly before going forward: + + o linux kernel version >= 2.6.18 (http://www.kernel.org) with support for: + - connection tracking system + - nfnetlink + - ctnetlink (ip_conntrack_netlink) + - connection tracking event notification API + + o libnfnetlink: the netfilter netlink library + + Since conntrackd version 0.9.2 you can used the official release availble at + http://www.netfilter.org/projects/libnfnetlink/files/ + + Up to conntrackd version 0.9.1 use the unofficial release available at the + download section + + o libnetfilter_conntrack: the netfilter conntrack library + + Since conntrackd version 0.9.2 you can used the official release availble at + http://www.netfilter.org/projects/libnetfilter_conntrack/files/ + + Up to conntrackd version 0.9.1 use the unnoficial release available at the + download section + +2.2.2. Configuration + + Setting up conntrackd in statistics mode is rather easy. Just copy the + configuration file + + # cp examples/stats/conntrackd.conf /etc/conntrackd.conf + +2.2.3. Running conntrackd in statistics mode + + To run conntrackd in statistics mode: + + # conntrackd -S + + Alternatively, you can run conntrackd in daemon mode: + + # conntrackd -S -d + + In order to dump the statistics, just type: + + # conntrackd -s diff --git a/daemon/Make_global.am b/daemon/Make_global.am new file mode 100644 index 0000000..685add7 --- /dev/null +++ b/daemon/Make_global.am @@ -0,0 +1 @@ +INCLUDES=$(all_includes) -I$(top_srcdir)/include diff --git a/daemon/Makefile.am b/daemon/Makefile.am new file mode 100644 index 0000000..998f4c6 --- /dev/null +++ b/daemon/Makefile.am @@ -0,0 +1,21 @@ +include Make_global.am + +# not a GNU package. You can remove this line, if +# have all needed files, that a GNU package needs +AUTOMAKE_OPTIONS = foreign dist-bzip2 1.6 + +# man_MANS = "" +# EXTRA_DIST = $(man_MANS) Make_global.am debian +EXTRA_DIST = Make_global.am CHANGELOG TODO + +SUBDIRS = src +DIST_SUBDIRS = include src examples +LINKOPTS = -lnfnetlink -lnetfilter_conntrack -lpthread +AM_CFLAGS = -g + +$(OBJECTS): libtool +libtool: $(LIBTOOL_DEPS) + $(SHELL) ./config.status --recheck + +dist-hook: + rm -rf `find $(distdir)/debian -name .svn` diff --git a/daemon/TODO b/daemon/TODO new file mode 100644 index 0000000..130b1f8 --- /dev/null +++ b/daemon/TODO @@ -0,0 +1,18 @@ +There are several tasks that are pending to be done, I have classified them +by dificulty levels: + +Relatively easy +=============== + +- test ipv6 support +- improve shell scripts +- test NACK based protocol +- manpage for conntrackd + +Requires some work +================== + +- study better keepalived transitions +- implement support for TCP window tracking (patches are on the table) + - at the moment you have to disable it: + echo 1 > /proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_be_liberal diff --git a/daemon/autogen.sh b/daemon/autogen.sh new file mode 100755 index 0000000..e76d3ef --- /dev/null +++ b/daemon/autogen.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +run () +{ + echo "running: $*" + eval $* + + if test $? != 0 ; then + echo "error: while running '$*'" + exit 1 + fi +} + +run aclocal +run libtoolize -f +#run autoheader +run automake -a +run autoconf diff --git a/daemon/configure.in b/daemon/configure.in new file mode 100644 index 0000000..92e512a --- /dev/null +++ b/daemon/configure.in @@ -0,0 +1,106 @@ +AC_INIT(conntrackd, 0.9.2, pablo@netfilter.org) + +AC_CANONICAL_SYSTEM + +AM_INIT_AUTOMAKE + +AC_PROG_CC +AM_PROG_LIBTOOL +AC_PROG_INSTALL +AC_PROG_LN_S +AM_PROG_LEX +AC_PROG_YACC + +case $target in +*-*-linux*) ;; +*) AC_MSG_ERROR([Linux only, dude!]);; +esac + +AC_CHECK_PROGS(XYACC,$YACC bison yacc,none) +if test "$XYACC" = "none" +then + echo "*** Error: No suitable bison/yacc found. ***" + echo " Please install the 'bison' package." + exit 1 +fi +AC_CHECK_PROGS(XLEX,$LEX flex lex,none) +if test "$XLEX" = "none" +then + echo "*** Error: No suitable bison/yacc found. ***" + echo " Please install the 'bison' package." + exit 1 +fi + +AC_CHECK_HEADERS([linux/capability.h],, [AC_MSG_ERROR([Cannot find linux/capabibility.h])]) + +# Checks for libraries. +# FIXME: Replace `main' with a function in `-lc': +dnl AC_CHECK_LIB([c], [main]) +# FIXME: Replace `main' with a function in `-ldl': + +AC_CHECK_LIB([nfnetlink], [nfnl_talk] ,,,[-lnfnetlink]) +AC_CHECK_LIB([netfilter_conntrack], [nfct_dump_conntrack_table] ,,,[-lnetfilter_conntrack]) +AC_CHECK_LIB([pthread], [pthread_create] ,,,[-lpthread]) + +AC_CHECK_HEADERS(arpa/inet.h) +dnl check for inet_pton +AC_CHECK_FUNCS(inet_pton) +dnl Some systems have it, but not IPv6 +if test "$ac_cv_func_inet_pton" = "yes" ; then +AC_MSG_CHECKING(if inet_pton supports IPv6) +AC_TRY_RUN( + [ +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +int main() + { + struct in6_addr addr6; + if (inet_pton(AF_INET6, "::1", &addr6) < 1) + exit(1); + else + exit(0); + } + ], [ AC_MSG_RESULT(yes) + AC_DEFINE_UNQUOTED(HAVE_INET_PTON_IPV6, 1, [Define to 1 if inet_pton supports IPv6.]) + ], AC_MSG_RESULT(no), AC_MSG_RESULT(no)) +fi + +# Checks for header files. +dnl AC_HEADER_STDC +dnl AC_CHECK_HEADERS([netinet/in.h stdlib.h]) + +# Checks for typedefs, structures, and compiler characteristics. +dnl AC_C_CONST +dnl AC_C_INLINE + +# Checks for library functions. +dnl AC_FUNC_MALLOC +dnl AC_FUNC_VPRINTF +dnl AC_CHECK_FUNCS([memset]) + +dnl-------------------------------- + +dnl if test ! -z "$libdir"; then +dnl MODULE_DIR="\\\"$libdir/conntrack/\\\"" +dnl CFLAGS="$CFLAGS -DCONNTRACK_LIB_DIR=$MODULE_DIR" +dnl fi + +dnl-------------------------------- + +dnl AC_CONFIG_FILES([Makefile +dnl debug/Makefile +dnl debug/src/Makefile +dnl extensions/Makefile +dnl src/Makefile]) + +AC_OUTPUT(Makefile src/Makefile include/Makefile examples/Makefile examples/stats/Makefile examples/sync/Makefile examples/sync/persistent/Makefile examples/sync/nack/Makefile examples/sync/persistent/node1/Makefile examples/sync/persistent/node2/Makefile examples/sync/nack/node1/Makefile examples/sync/nack/node2/Makefile) diff --git a/daemon/examples/Makefile.am b/daemon/examples/Makefile.am new file mode 100644 index 0000000..be83d42 --- /dev/null +++ b/daemon/examples/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = stats sync diff --git a/daemon/examples/debian.conntrackd.init.d b/daemon/examples/debian.conntrackd.init.d new file mode 100644 index 0000000..ba847dd --- /dev/null +++ b/daemon/examples/debian.conntrackd.init.d @@ -0,0 +1,48 @@ +#!/bin/sh +# +# /etc/init.d/conntrackd +# +# Maximilian Wilhelm +# -- Mon, 06 Nov 2006 18:39:07 +0100 +# + +export PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin + +NAME="conntrackd" +DAEMON=`command -v conntrackd` +CONFIG="/etc/conntrack/conntrackd.conf" +PIDFILE="/var/run/${NAME}.pid" + + +# Gracefully exit if there is no daemon (debian way of life) +if [ ! -x "${DAEMON}" ]; then + exit 0 +fi + +# Check for config file +if [ ! -f /etc/conntrackd/conntrackd.conf ]; then + echo "Error: There is no config file for $NAME" >&2 + exit 1; +fi + +case "$1" in + start) + echo -n "Starting $NAME: " + start-stop-daemon --start --quiet --make-pidfile --pidfile "/var/run/${NAME}.pid" --background --exec "${DAEMON}" && echo "done." || echo "FAILED!" + ;; + stop) + echo -n "Stopping $NAME:" + start-stop-daemon --stop --quiet --oknodo --pidfile "/var/run/${NAME}.pid" && echo "done." || echo "FAILED!" + ;; + + restart) + $0 start + $0 stop + ;; + + *) + echo "Usage: /etc/init.d/conntrackd {start|stop|restart}" + exit 1 +esac + +exit 0 diff --git a/daemon/examples/stats/Makefile.am b/daemon/examples/stats/Makefile.am new file mode 100644 index 0000000..b43c3b8 --- /dev/null +++ b/daemon/examples/stats/Makefile.am @@ -0,0 +1 @@ +EXTRA_DIST = conntrackd.conf diff --git a/daemon/examples/stats/conntrackd.conf b/daemon/examples/stats/conntrackd.conf new file mode 100644 index 0000000..e514ac0 --- /dev/null +++ b/daemon/examples/stats/conntrackd.conf @@ -0,0 +1,69 @@ +# +# General settings +# +General { + # + # Number of buckets in the caches: hash table + # + HashSize 8192 + + # + # Maximum number of conntracks: + # it must be >= $ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max + # + HashLimit 65535 + + # + # Logfile + # + LogFile /var/log/conntrackd.log + + # + # Lockfile + # + LockFile /var/lock/conntrack.lock + + # + # Unix socket configuration + # + UNIX { + Path /tmp/sync.sock + Backlog 20 + } + + # + # Netlink socket buffer size + # + SocketBufferSize 262142 + + # + # Increase the socket buffer up to maximun if required + # + SocketBufferSizeMaxGrown 655355 +} + +# +# Ignore traffic for a certain set of IP's: Usually +# all the IP assigned to the firewall since local +# traffic must be ignored, just forwarded connections +# are worth to replicate +# +IgnoreTrafficFor { + IPv4_address 127.0.0.1 # loopback +} + +# +# Do not replicate certain protocol traffic +# +IgnoreProtocol { + UDP +# ICMP +# IGMP +# VRRP + # numeric numbers also valid +} + +# +# Strip NAT traffic +# +StripNAT diff --git a/daemon/examples/sync/Makefile.am b/daemon/examples/sync/Makefile.am new file mode 100644 index 0000000..28e7643 --- /dev/null +++ b/daemon/examples/sync/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = persistent nack diff --git a/daemon/examples/sync/nack/Makefile.am b/daemon/examples/sync/nack/Makefile.am new file mode 100644 index 0000000..6fd99b1 --- /dev/null +++ b/daemon/examples/sync/nack/Makefile.am @@ -0,0 +1,2 @@ +EXTRA_DIST = script_backup.sh script_master.sh +SUBDIRS = node1 node2 diff --git a/daemon/examples/sync/nack/README b/daemon/examples/sync/nack/README new file mode 100644 index 0000000..66987f7 --- /dev/null +++ b/daemon/examples/sync/nack/README @@ -0,0 +1 @@ +This directory contains the files for the NACK based protocol diff --git a/daemon/examples/sync/nack/node1/Makefile.am b/daemon/examples/sync/nack/node1/Makefile.am new file mode 100644 index 0000000..edc0ed7 --- /dev/null +++ b/daemon/examples/sync/nack/node1/Makefile.am @@ -0,0 +1 @@ +EXTRA_DIST = conntrackd.conf keepalived.conf diff --git a/daemon/examples/sync/nack/node1/conntrackd.conf b/daemon/examples/sync/nack/node1/conntrackd.conf new file mode 100644 index 0000000..f24fa7e --- /dev/null +++ b/daemon/examples/sync/nack/node1/conntrackd.conf @@ -0,0 +1,125 @@ +# +# Synchronizer settings +# +Sync { + Mode NACK { + # + # Size of the buffer that hold destroy messages for + # possible resends (in bytes) + # + ResendBufferSize 262144 + + # + # Entries committed to the connection tracking table + # starts with a limited timeout of N seconds until the + # takeover process is completed. + # + CommitTimeout 180 + + # Set Acknowledgement window size + ACKWindowSize 20 + } + + # + # Multicast IP and interface where messages are + # broadcasted (dedicated link). IMPORTANT: Make sure + # that iptables accepts traffic for destination + # 225.0.0.50, eg: + # + # iptables -I INPUT -d 225.0.0.50 -j ACCEPT + # iptables -I OUTPUT -d 225.0.0.50 -j ACCEPT + # + Multicast { + IPv4_address 225.0.0.50 + IPv4_interface 192.168.100.100 # IP of dedicated link + Group 3780 + Backlog 20 + } + + # Enable/Disable message checksumming + Checksum on + + # Uncomment this if you want to replicate just certain TCP states. + # This option introduces a tradeoff in the replication: it reduces + # CPU consumption and lost messages rate at the cost of having + # backup replicas that don't contain the current state that the active + # replica holds. TCP states are: SYN_SENT, SYN_RECV, ESTABLISHED, + # FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN. + # + # Replicate ESTABLISHED TIME_WAIT for TCP +} + +# +# General settings +# +General { + # + # Number of buckets in the caches: hash table + # + HashSize 8192 + + # + # Maximum number of conntracks: + # it must be >= $ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max + # + HashLimit 65535 + + # + # Logfile + # + LogFile /var/log/conntrackd.log + + # + # Lockfile + # + LockFile /var/lock/conntrack.lock + + # + # Unix socket configuration + # + UNIX { + Path /tmp/sync.sock + Backlog 20 + } + + # + # Netlink socket buffer size + # + SocketBufferSize 262142 + + # + # Increase the socket buffer up to maximum if required + # + SocketBufferSizeMaxGrown 655355 +} + +# +# Ignore traffic for a certain set of IP's: Usually +# all the IP assigned to the firewall since local +# traffic must be ignored, just forwarded connections +# are worth to replicate +# +IgnoreTrafficFor { + IPv4_address 127.0.0.1 # loopback + IPv4_address 192.168.0.1 + IPv4_address 192.168.1.1 + IPv4_address 192.168.100.100 # dedicated link ip + IPv4_address 192.168.0.100 # virtual IP 1 + IPv4_address 192.168.1.100 # virtual IP 2 +} + +# +# Do not replicate certain protocol traffic +# +IgnoreProtocol { + UDP + ICMP + IGMP + VRRP + # numeric numbers also valid +} + +# +# Strip NAT traffic +# +StripNAT diff --git a/daemon/examples/sync/nack/node1/keepalived.conf b/daemon/examples/sync/nack/node1/keepalived.conf new file mode 100644 index 0000000..41aa35b --- /dev/null +++ b/daemon/examples/sync/nack/node1/keepalived.conf @@ -0,0 +1,38 @@ +vrrp_sync_group G1 { # must be before vrrp_instance declaration + group { + VI_1 + VI_2 + } + notify_master /etc/conntrackd/script_master.sh + notify_backup /etc/conntrackd/script_backup.sh +} + +vrrp_instance VI_1 { + interface eth1 + state SLAVE + virtual_router_id 61 + priority 80 + advert_int 3 + authentication { + auth_type PASS + auth_pass papas_con_tomate + } + virtual_ipaddress { + 192.168.0.100 # default CIDR mask is /32 + } +} + +vrrp_instance VI_2 { + interface eth0 + state SLAVE + virtual_router_id 62 + priority 80 + advert_int 3 + authentication { + auth_type PASS + auth_pass papas_con_tomate + } + virtual_ipaddress { + 192.168.1.100 + } +} diff --git a/daemon/examples/sync/nack/node2/Makefile.am b/daemon/examples/sync/nack/node2/Makefile.am new file mode 100644 index 0000000..edc0ed7 --- /dev/null +++ b/daemon/examples/sync/nack/node2/Makefile.am @@ -0,0 +1 @@ +EXTRA_DIST = conntrackd.conf keepalived.conf diff --git a/daemon/examples/sync/nack/node2/conntrackd.conf b/daemon/examples/sync/nack/node2/conntrackd.conf new file mode 100644 index 0000000..4f15773 --- /dev/null +++ b/daemon/examples/sync/nack/node2/conntrackd.conf @@ -0,0 +1,124 @@ +# +# Synchronizer settings +# +Sync { + Mode NACK { + # + # Size of the buffer that hold destroy messages for + # possible resends (in bytes) + # + ResendBufferSize 262144 + + # Entries committed to the connection tracking table + # starts with a limited timeout of N seconds until the + # takeover process is completed. + # + CommitTimeout 180 + + # Set Acknowledgement window size + ACKWindowSize 20 + } + + # + # Multicast IP and interface where messages are + # broadcasted (dedicated link). IMPORTANT: Make sure + # that iptables accepts traffic for destination + # 225.0.0.50, eg: + # + # iptables -I INPUT -d 225.0.0.50 -j ACCEPT + # iptables -I OUTPUT -d 225.0.0.50 -j ACCEPT + # + Multicast { + IPv4_address 225.0.0.50 + IPv4_interface 192.168.100.200 # IP of dedicated link + Group 3780 + Backlog 20 + } + + # Enable/Disable message checksumming + Checksum on + + # Uncomment this if you want to replicate just certain TCP states. + # This option introduces a tradeoff in the replication: it reduces + # CPU consumption and lost messages rate at the cost of having + # backup replicas that don't contain the current state that the active + # replica holds. TCP states are: SYN_SENT, SYN_RECV, ESTABLISHED, + # FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN. + # + # Replicate ESTABLISHED TIME_WAIT for TCP +} + +# +# General settings +# +General { + # + # Number of buckets in the caches: hash table + # + HashSize 8192 + + # + # Maximum number of conntracks: + # it must be >= $ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max + # + HashLimit 65535 + + # + # Logfile + # + LogFile /var/log/conntrackd.log + + # + # Lockfile + # + LockFile /var/lock/conntrack.lock + + # + # Unix socket configuration + # + UNIX { + Path /tmp/sync.sock + Backlog 20 + } + + # + # Netlink socket buffer size + # + SocketBufferSize 262142 + + # + # Increase the socket buffer up to maximum if required + # + SocketBufferSizeMaxGrown 655355 +} + +# +# Ignore traffic for a certain set of IP's: Usually +# all the IP assigned to the firewall since local +# traffic must be ignored, just forwarded connections +# are worth to replicate +# +IgnoreTrafficFor { + IPv4_address 127.0.0.1 # loopback + IPv4_address 192.168.0.2 + IPv4_address 192.168.1.2 + IPv4_address 192.168.100.200 # dedicated link ip + IPv4_address 192.168.0.200 # virtual IP 1 + IPv4_address 192.168.1.200 # virtual IP 2 +} + +# +# Do not replicate certain protocol traffic +# +IgnoreProtocol { + UDP + ICMP + IGMP + VRRP + # numeric numbers also valid +} + +# +# Strip NAT traffic +# +StripNAT diff --git a/daemon/examples/sync/nack/node2/keepalived.conf b/daemon/examples/sync/nack/node2/keepalived.conf new file mode 100644 index 0000000..41aa35b --- /dev/null +++ b/daemon/examples/sync/nack/node2/keepalived.conf @@ -0,0 +1,38 @@ +vrrp_sync_group G1 { # must be before vrrp_instance declaration + group { + VI_1 + VI_2 + } + notify_master /etc/conntrackd/script_master.sh + notify_backup /etc/conntrackd/script_backup.sh +} + +vrrp_instance VI_1 { + interface eth1 + state SLAVE + virtual_router_id 61 + priority 80 + advert_int 3 + authentication { + auth_type PASS + auth_pass papas_con_tomate + } + virtual_ipaddress { + 192.168.0.100 # default CIDR mask is /32 + } +} + +vrrp_instance VI_2 { + interface eth0 + state SLAVE + virtual_router_id 62 + priority 80 + advert_int 3 + authentication { + auth_type PASS + auth_pass papas_con_tomate + } + virtual_ipaddress { + 192.168.1.100 + } +} diff --git a/daemon/examples/sync/nack/script_backup.sh b/daemon/examples/sync/nack/script_backup.sh new file mode 100755 index 0000000..813e375 --- /dev/null +++ b/daemon/examples/sync/nack/script_backup.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +/usr/sbin/conntrackd -n # request a resync from other nodes via multicast diff --git a/daemon/examples/sync/nack/script_master.sh b/daemon/examples/sync/nack/script_master.sh new file mode 100755 index 0000000..ff1dbc0 --- /dev/null +++ b/daemon/examples/sync/nack/script_master.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +/usr/sbin/conntrackd -c # commit the cache +/usr/sbin/conntrackd -f # flush the caches +/usr/sbin/conntrackd -R # resync with kernel conntrack table diff --git a/daemon/examples/sync/persistent/Makefile.am b/daemon/examples/sync/persistent/Makefile.am new file mode 100644 index 0000000..6fd99b1 --- /dev/null +++ b/daemon/examples/sync/persistent/Makefile.am @@ -0,0 +1,2 @@ +EXTRA_DIST = script_backup.sh script_master.sh +SUBDIRS = node1 node2 diff --git a/daemon/examples/sync/persistent/README b/daemon/examples/sync/persistent/README new file mode 100644 index 0000000..36b5989 --- /dev/null +++ b/daemon/examples/sync/persistent/README @@ -0,0 +1 @@ +This directory contains the files for the PERSISTENT based protocol diff --git a/daemon/examples/sync/persistent/node1/Makefile.am b/daemon/examples/sync/persistent/node1/Makefile.am new file mode 100644 index 0000000..edc0ed7 --- /dev/null +++ b/daemon/examples/sync/persistent/node1/Makefile.am @@ -0,0 +1 @@ +EXTRA_DIST = conntrackd.conf keepalived.conf diff --git a/daemon/examples/sync/persistent/node1/conntrackd.conf b/daemon/examples/sync/persistent/node1/conntrackd.conf new file mode 100644 index 0000000..90afeb7 --- /dev/null +++ b/daemon/examples/sync/persistent/node1/conntrackd.conf @@ -0,0 +1,130 @@ +# +# Synchronizer settings +# +Sync { + Mode PERSISTENT { + # + # If a conntrack entry is not modified in <= 15 seconds, then + # a message is broadcasted. This mechanism is used to + # resynchronize nodes that just joined the multicast group + # + RefreshTime 15 + + # + # If we don't receive a notification about the state of + # an entry in the external cache after N seconds, then + # remove it. + # + CacheTimeout 180 + + # + # Entries committed to the connection tracking table + # starts with a limited timeout of N seconds until the + # takeover process is completed. + # + CommitTimeout 180 + } + + # + # Multicast IP and interface where messages are + # broadcasted (dedicated link). IMPORTANT: Make sure + # that iptables accepts traffic for destination + # 225.0.0.50, eg: + # + # iptables -I INPUT -d 225.0.0.50 -j ACCEPT + # iptables -I OUTPUT -d 225.0.0.50 -j ACCEPT + # + Multicast { + IPv4_address 225.0.0.50 + IPv4_interface 192.168.100.100 # IP of dedicated link + Group 3780 + Backlog 20 + } + + # Enable/Disable message checksumming + Checksum on + + # Uncomment this if you want to replicate just certain TCP states. + # This option introduces a tradeoff in the replication: it reduces + # CPU consumption and lost messages rate at the cost of having + # backup replicas that don't contain the current state that the active + # replica holds. TCP states are: SYN_SENT, SYN_RECV, ESTABLISHED, + # FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN. + # + # Replicate ESTABLISHED TIME_WAIT for TCP +} + +# +# General settings +# +General { + # + # Number of buckets in the caches: hash table + # + HashSize 8192 + + # + # Maximum number of conntracks: + # it must be >= $ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max + # + HashLimit 65535 + + # + # Logfile + # + LogFile /var/log/conntrackd.log + + # + # Lockfile + # + LockFile /var/lock/conntrack.lock + + # + # Unix socket configuration + # + UNIX { + Path /tmp/sync.sock + Backlog 20 + } + + # + # Netlink socket buffer size + # + SocketBufferSize 262142 + + # + # Increase the socket buffer up to maximum if required + # + SocketBufferSizeMaxGrown 655355 +} + +# +# Ignore traffic for a certain set of IP's: Usually +# all the IP assigned to the firewall since local +# traffic must be ignored, just forwarded connections +# are worth to replicate +# +IgnoreTrafficFor { + IPv4_address 127.0.0.1 # loopback + IPv4_address 192.168.0.1 + IPv4_address 192.168.1.1 + IPv4_address 192.168.100.100 # dedicated link ip + IPv4_address 192.168.0.100 # virtual IP 1 + IPv4_address 192.168.1.100 # virtual IP 2 +} + +# +# Do not replicate certain protocol traffic +# +IgnoreProtocol { + UDP + ICMP + IGMP + VRRP + # numeric numbers also valid +} + +# +# Strip NAT traffic +# +StripNAT diff --git a/daemon/examples/sync/persistent/node1/keepalived.conf b/daemon/examples/sync/persistent/node1/keepalived.conf new file mode 100644 index 0000000..41aa35b --- /dev/null +++ b/daemon/examples/sync/persistent/node1/keepalived.conf @@ -0,0 +1,38 @@ +vrrp_sync_group G1 { # must be before vrrp_instance declaration + group { + VI_1 + VI_2 + } + notify_master /etc/conntrackd/script_master.sh + notify_backup /etc/conntrackd/script_backup.sh +} + +vrrp_instance VI_1 { + interface eth1 + state SLAVE + virtual_router_id 61 + priority 80 + advert_int 3 + authentication { + auth_type PASS + auth_pass papas_con_tomate + } + virtual_ipaddress { + 192.168.0.100 # default CIDR mask is /32 + } +} + +vrrp_instance VI_2 { + interface eth0 + state SLAVE + virtual_router_id 62 + priority 80 + advert_int 3 + authentication { + auth_type PASS + auth_pass papas_con_tomate + } + virtual_ipaddress { + 192.168.1.100 + } +} diff --git a/daemon/examples/sync/persistent/node2/Makefile.am b/daemon/examples/sync/persistent/node2/Makefile.am new file mode 100644 index 0000000..edc0ed7 --- /dev/null +++ b/daemon/examples/sync/persistent/node2/Makefile.am @@ -0,0 +1 @@ +EXTRA_DIST = conntrackd.conf keepalived.conf diff --git a/daemon/examples/sync/persistent/node2/conntrackd.conf b/daemon/examples/sync/persistent/node2/conntrackd.conf new file mode 100644 index 0000000..aee4a29 --- /dev/null +++ b/daemon/examples/sync/persistent/node2/conntrackd.conf @@ -0,0 +1,130 @@ +# +# Synchronizer settings +# +Sync { + Mode PERSISTENT { + # + # If a conntrack entry is not modified in <= 15 seconds, then + # a message is broadcasted. This mechanism is used to + # resynchronize nodes that just joined the multicast group + # + RefreshTime 15 + + # + # If we don't receive a notification about the state of + # an entry in the external cache after N seconds, then + # remove it. + # + CacheTimeout 180 + + # + # Entries committed to the connection tracking table + # starts with a limited timeout of N seconds until the + # takeover process is completed. + # + CommitTimeout 180 + } + + # + # Multicast IP and interface where messages are + # broadcasted (dedicated link). IMPORTANT: Make sure + # that iptables accepts traffic for destination + # 225.0.0.50, eg: + # + # iptables -I INPUT -d 225.0.0.50 -j ACCEPT + # iptables -I OUTPUT -d 225.0.0.50 -j ACCEPT + # + Multicast { + IPv4_address 225.0.0.50 + IPv4_interface 192.168.100.200 # IP of dedicated link + Group 3780 + Backlog 20 + } + + # Enable/Disable message checksumming + Checksum on + + # Uncomment this if you want to replicate just certain TCP states. + # This option introduces a tradeoff in the replication: it reduces + # CPU consumption and lost messages rate at the cost of having + # backup replicas that don't contain the current state that the active + # replica holds. TCP states are: SYN_SENT, SYN_RECV, ESTABLISHED, + # FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN. + # + # Replicate ESTABLISHED TIME_WAIT for TCP +} + +# +# General settings +# +General { + # + # Number of buckets in the caches: hash table + # + HashSize 8192 + + # + # Maximum number of conntracks: + # it must be >= $ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max + # + HashLimit 65535 + + # + # Logfile + # + LogFile /var/log/conntrackd.log + + # + # Lockfile + # + LockFile /var/lock/conntrack.lock + + # + # Unix socket configuration + # + UNIX { + Path /tmp/sync.sock + Backlog 20 + } + + # + # Netlink socket buffer size + # + SocketBufferSize 262142 + + # + # Increase the socket buffer up to maximum if required + # + SocketBufferSizeMaxGrown 655355 +} + +# +# Ignore traffic for a certain set of IP's: Usually +# all the IP assigned to the firewall since local +# traffic must be ignored, just forwarded connections +# are worth to replicate +# +IgnoreTrafficFor { + IPv4_address 127.0.0.1 # loopback + IPv4_address 192.168.0.2 + IPv4_address 192.168.1.2 + IPv4_address 192.168.100.200 # dedicated link ip + IPv4_address 192.168.0.200 # virtual IP 1 + IPv4_address 192.168.1.200 # virtual IP 2 +} + +# +# Do not replicate certain protocol traffic +# +IgnoreProtocol { + UDP + ICMP + IGMP + VRRP + # numeric numbers also valid +} + +# +# Strip NAT traffic +# +StripNAT diff --git a/daemon/examples/sync/persistent/node2/keepalived.conf b/daemon/examples/sync/persistent/node2/keepalived.conf new file mode 100644 index 0000000..41aa35b --- /dev/null +++ b/daemon/examples/sync/persistent/node2/keepalived.conf @@ -0,0 +1,38 @@ +vrrp_sync_group G1 { # must be before vrrp_instance declaration + group { + VI_1 + VI_2 + } + notify_master /etc/conntrackd/script_master.sh + notify_backup /etc/conntrackd/script_backup.sh +} + +vrrp_instance VI_1 { + interface eth1 + state SLAVE + virtual_router_id 61 + priority 80 + advert_int 3 + authentication { + auth_type PASS + auth_pass papas_con_tomate + } + virtual_ipaddress { + 192.168.0.100 # default CIDR mask is /32 + } +} + +vrrp_instance VI_2 { + interface eth0 + state SLAVE + virtual_router_id 62 + priority 80 + advert_int 3 + authentication { + auth_type PASS + auth_pass papas_con_tomate + } + virtual_ipaddress { + 192.168.1.100 + } +} diff --git a/daemon/examples/sync/persistent/script_backup.sh b/daemon/examples/sync/persistent/script_backup.sh new file mode 100755 index 0000000..8ea2ad8 --- /dev/null +++ b/daemon/examples/sync/persistent/script_backup.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +/usr/sbin/conntrackd -B diff --git a/daemon/examples/sync/persistent/script_master.sh b/daemon/examples/sync/persistent/script_master.sh new file mode 100755 index 0000000..70c26c9 --- /dev/null +++ b/daemon/examples/sync/persistent/script_master.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +/usr/sbin/conntrackd -c +/usr/sbin/conntrackd -R diff --git a/daemon/include/Makefile.am b/daemon/include/Makefile.am new file mode 100644 index 0000000..e669d73 --- /dev/null +++ b/daemon/include/Makefile.am @@ -0,0 +1,5 @@ + +noinst_HEADERS = alarm.h jhash.h slist.h cache.h linux_list.h \ + sync.h conntrackd.h local.h us-conntrack.h \ + debug.h log.h hash.h mcast.h buffer.h + diff --git a/daemon/include/alarm.h b/daemon/include/alarm.h new file mode 100644 index 0000000..93e6482 --- /dev/null +++ b/daemon/include/alarm.h @@ -0,0 +1,13 @@ +#ifndef _TIMER_H_ +#define _TIMER_H_ + +#include "linux_list.h" + +struct alarm_list { + struct list_head head; + unsigned long expires; + void *data; + void (*function)(struct alarm_list *a, void *data); +}; + +#endif diff --git a/daemon/include/buffer.h b/daemon/include/buffer.h new file mode 100644 index 0000000..8d72dfb --- /dev/null +++ b/daemon/include/buffer.h @@ -0,0 +1,32 @@ +#ifndef _BUFFER_H_ +#define _BUFFER_H_ + +#include +#include +#include +#include +#include "linux_list.h" + +struct buffer { + pthread_mutex_t lock; + size_t max_size; + size_t cur_size; + struct list_head head; +}; + +struct buffer_node { + struct list_head head; + size_t size; + char data[0]; +}; + +struct buffer *buffer_create(size_t max_size); +void buffer_destroy(struct buffer *b); +int buffer_add(struct buffer *b, const void *data, size_t size); +void buffer_del(struct buffer *b, void *data); +void __buffer_del(struct buffer *b, void *data); +void buffer_iterate(struct buffer *b, + void *data, + int (*iterate)(void *data1, void *data2)); + +#endif diff --git a/daemon/include/cache.h b/daemon/include/cache.h new file mode 100644 index 0000000..7d9559a --- /dev/null +++ b/daemon/include/cache.h @@ -0,0 +1,92 @@ +#ifndef _CACHE_H_ +#define _CACHE_H_ + +#include +#include + +/* cache features */ +enum { + NO_FEATURES = 0, + + TIMER_FEATURE = 0, + TIMER = (1 << TIMER_FEATURE), + + LIFETIME_FEATURE = 2, + LIFETIME = (1 << LIFETIME_FEATURE), + + __CACHE_MAX_FEATURE +}; +#define CACHE_MAX_FEATURE __CACHE_MAX_FEATURE + +struct cache; +struct us_conntrack; + +struct cache_feature { + size_t size; + void (*add)(struct us_conntrack *u, void *data); + void (*update)(struct us_conntrack *u, void *data); + void (*destroy)(struct us_conntrack *u, void *data); + int (*dump)(struct us_conntrack *u, void *data, char *buf, int type); +}; + +extern struct cache_feature lifetime_feature; +extern struct cache_feature timer_feature; + +#define CACHE_MAX_NAMELEN 32 + +struct cache { + char name[CACHE_MAX_NAMELEN]; + struct hashtable *h; + + unsigned int num_features; + struct cache_feature **features; + unsigned int feature_type[CACHE_MAX_FEATURE]; + unsigned int *feature_offset; + struct cache_extra *extra; + unsigned int extra_offset; + + /* statistics */ + unsigned int add_ok; + unsigned int del_ok; + unsigned int upd_ok; + + unsigned int add_fail; + unsigned int del_fail; + unsigned int upd_fail; + + unsigned int commit_ok; + unsigned int commit_exist; + unsigned int commit_fail; + + unsigned int flush; +}; + +struct cache_extra { + unsigned int size; + + void (*add)(struct us_conntrack *u, void *data); + void (*update)(struct us_conntrack *u, void *data); + void (*destroy)(struct us_conntrack *u, void *data); +}; + +struct nf_conntrack; + +struct cache *cache_create(char *name, unsigned int features, u_int8_t proto, struct cache_extra *extra); +void cache_destroy(struct cache *e); + +struct us_conntrack *cache_add(struct cache *c, struct nf_conntrack *ct); +struct us_conntrack *cache_update(struct cache *c, struct nf_conntrack *ct); +struct us_conntrack *cache_update_force(struct cache *c, struct nf_conntrack *ct); +int cache_del(struct cache *c, struct nf_conntrack *ct); +int cache_test(struct cache *c, struct nf_conntrack *ct); +void cache_stats(struct cache *c, int fd); +struct us_conntrack *cache_get_conntrack(struct cache *, void *); +void *cache_get_extra(struct cache *, void *); + +/* iterators */ +void cache_dump(struct cache *c, int fd, int type); +void cache_commit(struct cache *c); +void cache_flush(struct cache *c); +void cache_bulk(struct cache *c); + +#endif diff --git a/daemon/include/conntrackd.h b/daemon/include/conntrackd.h new file mode 100644 index 0000000..a5f7a3a --- /dev/null +++ b/daemon/include/conntrackd.h @@ -0,0 +1,174 @@ +#ifndef _CONNTRACKD_H_ +#define _CONNTRACKD_H_ + +#include "mcast.h" +#include "local.h" + +#include +#include +#include "cache.h" +#include "debug.h" +#include +#include "state_helper.h" +#include + +/* UNIX facilities */ +#define FLUSH_MASTER 0 /* flush kernel conntrack table */ +#define RESYNC_MASTER 1 /* resync with kernel conntrack table */ +#define DUMP_INTERNAL 16 /* dump internal cache */ +#define DUMP_EXTERNAL 17 /* dump external cache */ +#define COMMIT 18 /* commit external cache */ +#define FLUSH_CACHE 19 /* flush cache */ +#define KILL 20 /* kill conntrackd */ +#define STATS 21 /* dump statistics */ +#define SEND_BULK 22 /* send a bulk */ +#define REQUEST_DUMP 23 /* request dump */ +#define DUMP_INT_XML 24 /* dump internal cache in XML */ +#define DUMP_EXT_XML 25 /* dump external cache in XML */ + +#define DEFAULT_CONFIGFILE "/etc/conntrackd/conntrackd.conf" +#define DEFAULT_LOCKFILE "/var/lock/conntrackd.lock" + +enum { + STRIP_NAT_BIT = 0, + STRIP_NAT = (1 << STRIP_NAT_BIT), + + DELAY_DESTROY_MSG_BIT = 1, + DELAY_DESTROY_MSG = (1 << DELAY_DESTROY_MSG_BIT), + + RELAX_TRANSITIONS_BIT = 2, + RELAX_TRANSITIONS = (1 << RELAX_TRANSITIONS_BIT), + + SYNC_MODE_PERSISTENT_BIT = 3, + SYNC_MODE_PERSISTENT = (1 << SYNC_MODE_PERSISTENT_BIT), + + SYNC_MODE_NACK_BIT = 4, + SYNC_MODE_NACK = (1 << SYNC_MODE_NACK_BIT), + + DONT_CHECKSUM_BIT = 5, + DONT_CHECKSUM = (1 << DONT_CHECKSUM_BIT), +}; + +/* daemon/request modes */ +#define NOT_SET 0 +#define DAEMON 1 +#define REQUEST 2 + +/* conntrackd modes */ +#define SYNC_MODE 0 +#define STATS_MODE 1 + +/* FILENAME_MAX is 4096 on my system, perhaps too much? */ +#ifndef FILENAME_MAXLEN +#define FILENAME_MAXLEN 256 +#endif + +union inet_address { + u_int32_t ipv4; + u_int32_t ipv6[4]; + u_int32_t all[4]; +}; + +#define CONFIG(x) conf.x + +struct ct_conf { + char logfile[FILENAME_MAXLEN]; + char lockfile[FILENAME_MAXLEN]; + int hashsize; /* hashtable size */ + struct mcast_conf mcast; /* multicast settings */ + struct local_conf local; /* unix socket facilities */ + int limit; + int refresh; + int cache_timeout; /* cache entries timeout */ + int commit_timeout; /* committed entries timeout */ + unsigned int netlink_buffer_size; + unsigned int netlink_buffer_size_max_grown; + unsigned char ignore_protocol[IPPROTO_MAX]; + union inet_address *listen_to; + unsigned int listen_to_len; + unsigned int flags; + int family; /* protocol family */ + unsigned int resend_buffer_size;/* NACK protocol */ + unsigned int window_size; +}; + +#define STATE(x) st.x + +struct ct_general_state { + sigset_t block; + FILE *log; + int local; + struct ct_mode *mode; + struct ignore_pool *ignore_pool; + + struct nfnl_handle *event; /* event handler */ + struct nfnl_handle *sync; /* sync handler */ + struct nfnl_handle *dump; /* dump handler */ + + struct nfnl_subsys_handle *subsys_event; /* events */ + struct nfnl_subsys_handle *subsys_sync; /* resync */ + struct nfnl_subsys_handle *subsys_dump; /* dump */ + + /* statistics */ + u_int64_t malformed; + u_int64_t bytes[NFCT_DIR_MAX]; + u_int64_t packets[NFCT_DIR_MAX]; +}; + +#define STATE_SYNC(x) state.sync->x + +struct ct_sync_state { + struct cache *internal; /* internal events cache (netlink) */ + struct cache *external; /* external events cache (mcast) */ + + struct mcast_sock *mcast_server; /* multicast socket: incoming */ + struct mcast_sock *mcast_client; /* multicast socket: outgoing */ + + struct sync_mode *mcast_sync; + struct buffer *buffer; + + u_int32_t last_seq_sent; /* last sequence number sent */ + u_int32_t last_seq_recv; /* last sequence number recv */ + u_int64_t packets_replayed; /* number of replayed packets */ + u_int64_t packets_lost; /* lost packets: sequence tracking */ +}; + +#define STATE_STATS(x) state.stats->x + +struct ct_stats_state { + struct cache *cache; /* internal events cache (netlink) */ +}; + +union ct_state { + struct ct_sync_state *sync; + struct ct_stats_state *stats; +}; + +extern struct ct_conf conf; +extern union ct_state state; +extern struct ct_general_state st; + +#ifndef IPPROTO_VRRP +#define IPPROTO_VRRP 112 +#endif + +struct ct_mode { + int (*init)(void); + int (*add_fds_to_set)(fd_set *readfds); + void (*step)(fd_set *readfds); + int (*local)(int fd, int type, void *data); + void (*kill)(void); + void (*dump)(struct nf_conntrack *ct, struct nlmsghdr *nlh); + void (*overrun)(struct nf_conntrack *ct, struct nlmsghdr *nlh); + void (*event_new)(struct nf_conntrack *ct, struct nlmsghdr *nlh); + void (*event_upd)(struct nf_conntrack *ct, struct nlmsghdr *nlh); + int (*event_dst)(struct nf_conntrack *ct, struct nlmsghdr *nlh); +}; + +/* conntrackd modes */ +extern struct ct_mode sync_mode; +extern struct ct_mode stats_mode; + +#define MAX(x, y) x > y ? x : y + +#endif diff --git a/daemon/include/debug.h b/daemon/include/debug.h new file mode 100644 index 0000000..67f2c71 --- /dev/null +++ b/daemon/include/debug.h @@ -0,0 +1,53 @@ +#ifndef _DEBUG_H +#define _DEBUG_H + +#if 0 +#define debug printf +#else +#define debug +#endif + +#include +#include +#include + +static inline void debug_ct(struct nf_conntrack *ct, char *msg) +{ + struct in_addr addr, addr2, addr3, addr4; + + debug("----%s (%p) ----\n", msg, ct); + memcpy(&addr, + nfct_get_attr(ct, ATTR_ORIG_IPV4_SRC), + sizeof(u_int32_t)); + memcpy(&addr2, + nfct_get_attr(ct, ATTR_ORIG_IPV4_DST), + sizeof(u_int32_t)); + memcpy(&addr3, + nfct_get_attr(ct, ATTR_REPL_IPV4_SRC), + sizeof(u_int32_t)); + memcpy(&addr4, + nfct_get_attr(ct, ATTR_REPL_IPV4_DST), + sizeof(u_int32_t)); + + debug("status: %x\n", nfct_get_attr_u32(ct, ATTR_STATUS)); + debug("l3:%d l4:%d ", + nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO), + nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO)); + debug("%s:%hu ->", inet_ntoa(addr), + ntohs(nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC))); + debug("%s:%hu\n", + inet_ntoa(addr2), + ntohs(nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST))); + debug("l3:%d l4:%d ", + nfct_get_attr_u8(ct, ATTR_REPL_L3PROTO), + nfct_get_attr_u8(ct, ATTR_REPL_L4PROTO)); + debug("%s:%hu ->", + inet_ntoa(addr3), + ntohs(nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC))); + debug("%s:%hu\n", + inet_ntoa(addr4), + ntohs(nfct_get_attr_u16(ct, ATTR_REPL_PORT_DST))); + debug("-------------------------\n"); +} + +#endif diff --git a/daemon/include/hash.h b/daemon/include/hash.h new file mode 100644 index 0000000..fd971e7 --- /dev/null +++ b/daemon/include/hash.h @@ -0,0 +1,47 @@ +#ifndef _NF_SET_HASH_H_ +#define _NF_SET_HASH_H_ + +#include +#include +#include "slist.h" +#include "linux_list.h" + +struct hashtable; +struct hashtable_node; + +struct hashtable { + u_int32_t hashsize; + u_int32_t limit; + u_int32_t count; + u_int32_t initval; + u_int32_t datasize; + + u_int32_t (*hash)(const void *data, struct hashtable *table); + int (*compare)(const void *data1, const void *data2); + + struct slist_head members[0]; +}; + +struct hashtable_node { + struct slist_head head; + char data[0]; +}; + +struct hashtable_node *hashtable_alloc_node(int datasize, void *data); +void hashtable_destroy_node(struct hashtable_node *h); + +struct hashtable * +hashtable_create(int hashsize, int limit, int datasize, + u_int32_t (*hash)(const void *data, struct hashtable *table), + int (*compare)(const void *data1, const void *data2)); +void hashtable_destroy(struct hashtable *h); + +void *hashtable_add(struct hashtable *table, void *data); +void *hashtable_test(struct hashtable *table, const void *data); +int hashtable_del(struct hashtable *table, void *data); +int hashtable_flush(struct hashtable *table); +int hashtable_iterate(struct hashtable *table, void *data, + int (*iterate)(void *data1, void *data2)); +unsigned int hashtable_counter(struct hashtable *table); + +#endif diff --git a/daemon/include/ignore.h b/daemon/include/ignore.h new file mode 100644 index 0000000..40cb02d --- /dev/null +++ b/daemon/include/ignore.h @@ -0,0 +1,12 @@ +#ifndef _IGNORE_H_ +#define _IGNORE_H_ + +struct ignore_pool { + struct hashtable *h; +}; + +struct ignore_pool *ignore_pool_create(u_int8_t family); +void ignore_pool_destroy(struct ignore_pool *ip); +int ignore_pool_add(struct ignore_pool *ip, void *data); + +#endif diff --git a/daemon/include/jhash.h b/daemon/include/jhash.h new file mode 100644 index 0000000..38b8780 --- /dev/null +++ b/daemon/include/jhash.h @@ -0,0 +1,146 @@ +#ifndef _LINUX_JHASH_H +#define _LINUX_JHASH_H + +#define u32 unsigned int +#define u8 char + +/* jhash.h: Jenkins hash support. + * + * Copyright (C) 1996 Bob Jenkins (bob_jenkins@burtleburtle.net) + * + * http://burtleburtle.net/bob/hash/ + * + * These are the credits from Bob's sources: + * + * lookup2.c, by Bob Jenkins, December 1996, Public Domain. + * hash(), hash2(), hash3, and mix() are externally useful functions. + * Routines to test the hash are included if SELF_TEST is defined. + * You can use this free for any purpose. It has no warranty. + * + * Copyright (C) 2003 David S. Miller (davem@redhat.com) + * + * I've modified Bob's hash to be useful in the Linux kernel, and + * any bugs present are surely my fault. -DaveM + */ + +/* NOTE: Arguments are modified. */ +#define __jhash_mix(a, b, c) \ +{ \ + a -= b; a -= c; a ^= (c>>13); \ + b -= c; b -= a; b ^= (a<<8); \ + c -= a; c -= b; c ^= (b>>13); \ + a -= b; a -= c; a ^= (c>>12); \ + b -= c; b -= a; b ^= (a<<16); \ + c -= a; c -= b; c ^= (b>>5); \ + a -= b; a -= c; a ^= (c>>3); \ + b -= c; b -= a; b ^= (a<<10); \ + c -= a; c -= b; c ^= (b>>15); \ +} + +/* The golden ration: an arbitrary value */ +#define JHASH_GOLDEN_RATIO 0x9e3779b9 + +/* The most generic version, hashes an arbitrary sequence + * of bytes. No alignment or length assumptions are made about + * the input key. + */ +static inline u32 jhash(const void *key, u32 length, u32 initval) +{ + u32 a, b, c, len; + const u8 *k = key; + + len = length; + a = b = JHASH_GOLDEN_RATIO; + c = initval; + + while (len >= 12) { + a += (k[0] +((u32)k[1]<<8) +((u32)k[2]<<16) +((u32)k[3]<<24)); + b += (k[4] +((u32)k[5]<<8) +((u32)k[6]<<16) +((u32)k[7]<<24)); + c += (k[8] +((u32)k[9]<<8) +((u32)k[10]<<16)+((u32)k[11]<<24)); + + __jhash_mix(a,b,c); + + k += 12; + len -= 12; + } + + c += length; + switch (len) { + case 11: c += ((u32)k[10]<<24); + case 10: c += ((u32)k[9]<<16); + case 9 : c += ((u32)k[8]<<8); + case 8 : b += ((u32)k[7]<<24); + case 7 : b += ((u32)k[6]<<16); + case 6 : b += ((u32)k[5]<<8); + case 5 : b += k[4]; + case 4 : a += ((u32)k[3]<<24); + case 3 : a += ((u32)k[2]<<16); + case 2 : a += ((u32)k[1]<<8); + case 1 : a += k[0]; + }; + + __jhash_mix(a,b,c); + + return c; +} + +/* A special optimized version that handles 1 or more of u32s. + * The length parameter here is the number of u32s in the key. + */ +static inline u32 jhash2(u32 *k, u32 length, u32 initval) +{ + u32 a, b, c, len; + + a = b = JHASH_GOLDEN_RATIO; + c = initval; + len = length; + + while (len >= 3) { + a += k[0]; + b += k[1]; + c += k[2]; + __jhash_mix(a, b, c); + k += 3; len -= 3; + } + + c += length * 4; + + switch (len) { + case 2 : b += k[1]; + case 1 : a += k[0]; + }; + + __jhash_mix(a,b,c); + + return c; +} + + +/* A special ultra-optimized versions that knows they are hashing exactly + * 3, 2 or 1 word(s). + * + * NOTE: In partilar the "c += length; __jhash_mix(a,b,c);" normally + * done at the end is not done here. + */ +static inline u32 jhash_3words(u32 a, u32 b, u32 c, u32 initval) +{ + a += JHASH_GOLDEN_RATIO; + b += JHASH_GOLDEN_RATIO; + c += initval; + + __jhash_mix(a, b, c); + + return c; +} + +static inline u32 jhash_2words(u32 a, u32 b, u32 initval) +{ + return jhash_3words(a, b, 0, initval); +} + +static inline u32 jhash_1word(u32 a, u32 initval) +{ + return jhash_3words(a, 0, 0, initval); +} + +#endif /* _LINUX_JHASH_H */ diff --git a/daemon/include/linux_list.h b/daemon/include/linux_list.h new file mode 100644 index 0000000..57b56d7 --- /dev/null +++ b/daemon/include/linux_list.h @@ -0,0 +1,725 @@ +#ifndef _LINUX_LIST_H +#define _LINUX_LIST_H + +#undef offsetof +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) + +/** + * container_of - cast a member of a structure out to the containing structure + * + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + * + */ +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +/* + * Check at compile time that something is of a particular type. + * Always evaluates to 1 so you may use it easily in comparisons. + */ +#define typecheck(type,x) \ +({ type __dummy; \ + typeof(x) __dummy2; \ + (void)(&__dummy == &__dummy2); \ + 1; \ +}) + +#define prefetch(x) 1 + +/* empty define to make this work in userspace -HW */ +#ifndef smp_wmb +#define smp_wmb() +#endif + +/* + * These are non-NULL pointers that will result in page faults + * under normal circumstances, used to verify that nobody uses + * non-initialized list entries. + */ +#define LIST_POISON1 ((void *) 0x00100100) +#define LIST_POISON2 ((void *) 0x00200200) + +/* + * Simple doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +struct list_head { + struct list_head *next, *prev; +}; + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +#define INIT_LIST_HEAD(ptr) do { \ + (ptr)->next = (ptr); (ptr)->prev = (ptr); \ +} while (0) + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +/** + * list_add - add a new entry + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} + +/** + * list_add_tail - add a new entry + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static inline void list_add_tail(struct list_head *new, struct list_head *head) +{ + __list_add(new, head->prev, head); +} + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_add_rcu(struct list_head * new, + struct list_head * prev, struct list_head * next) +{ + new->next = next; + new->prev = prev; + smp_wmb(); + next->prev = new; + prev->next = new; +} + +/** + * list_add_rcu - add a new entry to rcu-protected list + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + * + * The caller must take whatever precautions are necessary + * (such as holding appropriate locks) to avoid racing + * with another list-mutation primitive, such as list_add_rcu() + * or list_del_rcu(), running on this same list. + * However, it is perfectly legal to run concurrently with + * the _rcu list-traversal primitives, such as + * list_for_each_entry_rcu(). + */ +static inline void list_add_rcu(struct list_head *new, struct list_head *head) +{ + __list_add_rcu(new, head, head->next); +} + +/** + * list_add_tail_rcu - add a new entry to rcu-protected list + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + * + * The caller must take whatever precautions are necessary + * (such as holding appropriate locks) to avoid racing + * with another list-mutation primitive, such as list_add_tail_rcu() + * or list_del_rcu(), running on this same list. + * However, it is perfectly legal to run concurrently with + * the _rcu list-traversal primitives, such as + * list_for_each_entry_rcu(). + */ +static inline void list_add_tail_rcu(struct list_head *new, + struct list_head *head) +{ + __list_add_rcu(new, head->prev, head); +} + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head * prev, struct list_head * next) +{ + next->prev = prev; + prev->next = next; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty on entry does not return true after this, the entry is + * in an undefined state. + */ +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->next = LIST_POISON1; + entry->prev = LIST_POISON2; +} + +/** + * list_del_rcu - deletes entry from list without re-initialization + * @entry: the element to delete from the list. + * + * Note: list_empty on entry does not return true after this, + * the entry is in an undefined state. It is useful for RCU based + * lockfree traversal. + * + * In particular, it means that we can not poison the forward + * pointers that may still be used for walking the list. + * + * The caller must take whatever precautions are necessary + * (such as holding appropriate locks) to avoid racing + * with another list-mutation primitive, such as list_del_rcu() + * or list_add_rcu(), running on this same list. + * However, it is perfectly legal to run concurrently with + * the _rcu list-traversal primitives, such as + * list_for_each_entry_rcu(). + * + * Note that the caller is not permitted to immediately free + * the newly deleted entry. Instead, either synchronize_kernel() + * or call_rcu() must be used to defer freeing until an RCU + * grace period has elapsed. + */ +static inline void list_del_rcu(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->prev = LIST_POISON2; +} + +/** + * list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list. + */ +static inline void list_del_init(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + INIT_LIST_HEAD(entry); +} + +/** + * list_move - delete from one list and add as another's head + * @list: the entry to move + * @head: the head that will precede our entry + */ +static inline void list_move(struct list_head *list, struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add(list, head); +} + +/** + * list_move_tail - delete from one list and add as another's tail + * @list: the entry to move + * @head: the head that will follow our entry + */ +static inline void list_move_tail(struct list_head *list, + struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add_tail(list, head); +} + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static inline int list_empty(const struct list_head *head) +{ + return head->next == head; +} + +/** + * list_empty_careful - tests whether a list is + * empty _and_ checks that no other CPU might be + * in the process of still modifying either member + * + * NOTE: using list_empty_careful() without synchronization + * can only be safe if the only activity that can happen + * to the list entry is list_del_init(). Eg. it cannot be used + * if another CPU could re-list_add() it. + * + * @head: the list to test. + */ +static inline int list_empty_careful(const struct list_head *head) +{ + struct list_head *next = head->next; + return (next == head) && (next == head->prev); +} + +static inline void __list_splice(struct list_head *list, + struct list_head *head) +{ + struct list_head *first = list->next; + struct list_head *last = list->prev; + struct list_head *at = head->next; + + first->prev = head; + head->next = first; + + last->next = at; + at->prev = last; +} + +/** + * list_splice - join two lists + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static inline void list_splice(struct list_head *list, struct list_head *head) +{ + if (!list_empty(list)) + __list_splice(list, head); +} + +/** + * list_splice_init - join two lists and reinitialise the emptied list. + * @list: the new list to add. + * @head: the place to add it in the first list. + * + * The list at @list is reinitialised + */ +static inline void list_splice_init(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) { + __list_splice(list, head); + INIT_LIST_HEAD(list); + } +} + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +/** + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next, prefetch(pos->next); pos != (head); \ + pos = pos->next, prefetch(pos->next)) + +/** + * __list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + * + * This variant differs from list_for_each() in that it's the + * simplest possible list iteration code, no prefetching is done. + * Use this for code that knows the list to be very short (empty + * or 1 entry) most of the time. + */ +#define __list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_for_each_prev - iterate over a list backwards + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + */ +#define list_for_each_prev(pos, head) \ + for (pos = (head)->prev, prefetch(pos->prev); pos != (head); \ + pos = pos->prev, prefetch(pos->prev)) + +/** + * list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the &struct list_head to use as a loop counter. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + prefetch(pos->member.next); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member), \ + prefetch(pos->member.next)) + +/** + * list_for_each_entry_reverse - iterate backwards over list of given type. + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_reverse(pos, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member), \ + prefetch(pos->member.prev); \ + &pos->member != (head); \ + pos = list_entry(pos->member.prev, typeof(*pos), member), \ + prefetch(pos->member.prev)) + +/** + * list_prepare_entry - prepare a pos entry for use as a start point in + * list_for_each_entry_continue + * @pos: the type * to use as a start point + * @head: the head of the list + * @member: the name of the list_struct within the struct. + */ +#define list_prepare_entry(pos, head, member) \ + ((pos) ? : list_entry(head, typeof(*pos), member)) + +/** + * list_for_each_entry_continue - iterate over list of given type + * continuing after existing point + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_continue(pos, head, member) \ + for (pos = list_entry(pos->member.next, typeof(*pos), member), \ + prefetch(pos->member.next); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member), \ + prefetch(pos->member.next)) + +/** + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos: the type * to use as a loop counter. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_rcu - iterate over an rcu-protected list + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + * + * This list-traversal primitive may safely run concurrently with + * the _rcu list-mutation primitives such as list_add_rcu() + * as long as the traversal is guarded by rcu_read_lock(). + */ +#define list_for_each_rcu(pos, head) \ + for (pos = (head)->next, prefetch(pos->next); pos != (head); \ + pos = pos->next, ({ smp_read_barrier_depends(); 0;}), prefetch(pos->next)) + +#define __list_for_each_rcu(pos, head) \ + for (pos = (head)->next; pos != (head); \ + pos = pos->next, ({ smp_read_barrier_depends(); 0;})) + +/** + * list_for_each_safe_rcu - iterate over an rcu-protected list safe + * against removal of list entry + * @pos: the &struct list_head to use as a loop counter. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + * + * This list-traversal primitive may safely run concurrently with + * the _rcu list-mutation primitives such as list_add_rcu() + * as long as the traversal is guarded by rcu_read_lock(). + */ +#define list_for_each_safe_rcu(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, ({ smp_read_barrier_depends(); 0;}), n = pos->next) + +/** + * list_for_each_entry_rcu - iterate over rcu list of given type + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * This list-traversal primitive may safely run concurrently with + * the _rcu list-mutation primitives such as list_add_rcu() + * as long as the traversal is guarded by rcu_read_lock(). + */ +#define list_for_each_entry_rcu(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + prefetch(pos->member.next); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member), \ + ({ smp_read_barrier_depends(); 0;}), \ + prefetch(pos->member.next)) + + +/** + * list_for_each_continue_rcu - iterate over an rcu-protected list + * continuing after existing point. + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + * + * This list-traversal primitive may safely run concurrently with + * the _rcu list-mutation primitives such as list_add_rcu() + * as long as the traversal is guarded by rcu_read_lock(). + */ +#define list_for_each_continue_rcu(pos, head) \ + for ((pos) = (pos)->next, prefetch((pos)->next); (pos) != (head); \ + (pos) = (pos)->next, ({ smp_read_barrier_depends(); 0;}), prefetch((pos)->next)) + +/* + * Double linked lists with a single pointer list head. + * Mostly useful for hash tables where the two pointer list head is + * too wasteful. + * You lose the ability to access the tail in O(1). + */ + +struct hlist_head { + struct hlist_node *first; +}; + +struct hlist_node { + struct hlist_node *next, **pprev; +}; + +#define HLIST_HEAD_INIT { .first = NULL } +#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL } +#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) +#define INIT_HLIST_NODE(ptr) ((ptr)->next = NULL, (ptr)->pprev = NULL) + +static inline int hlist_unhashed(const struct hlist_node *h) +{ + return !h->pprev; +} + +static inline int hlist_empty(const struct hlist_head *h) +{ + return !h->first; +} + +static inline void __hlist_del(struct hlist_node *n) +{ + struct hlist_node *next = n->next; + struct hlist_node **pprev = n->pprev; + *pprev = next; + if (next) + next->pprev = pprev; +} + +static inline void hlist_del(struct hlist_node *n) +{ + __hlist_del(n); + n->next = LIST_POISON1; + n->pprev = LIST_POISON2; +} + +/** + * hlist_del_rcu - deletes entry from hash list without re-initialization + * @n: the element to delete from the hash list. + * + * Note: list_unhashed() on entry does not return true after this, + * the entry is in an undefined state. It is useful for RCU based + * lockfree traversal. + * + * In particular, it means that we can not poison the forward + * pointers that may still be used for walking the hash list. + * + * The caller must take whatever precautions are necessary + * (such as holding appropriate locks) to avoid racing + * with another list-mutation primitive, such as hlist_add_head_rcu() + * or hlist_del_rcu(), running on this same list. + * However, it is perfectly legal to run concurrently with + * the _rcu list-traversal primitives, such as + * hlist_for_each_entry(). + */ +static inline void hlist_del_rcu(struct hlist_node *n) +{ + __hlist_del(n); + n->pprev = LIST_POISON2; +} + +static inline void hlist_del_init(struct hlist_node *n) +{ + if (n->pprev) { + __hlist_del(n); + INIT_HLIST_NODE(n); + } +} + +#define hlist_del_rcu_init hlist_del_init + +static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) +{ + struct hlist_node *first = h->first; + n->next = first; + if (first) + first->pprev = &n->next; + h->first = n; + n->pprev = &h->first; +} + + +/** + * hlist_add_head_rcu - adds the specified element to the specified hlist, + * while permitting racing traversals. + * @n: the element to add to the hash list. + * @h: the list to add to. + * + * The caller must take whatever precautions are necessary + * (such as holding appropriate locks) to avoid racing + * with another list-mutation primitive, such as hlist_add_head_rcu() + * or hlist_del_rcu(), running on this same list. + * However, it is perfectly legal to run concurrently with + * the _rcu list-traversal primitives, such as + * hlist_for_each_entry(), but only if smp_read_barrier_depends() + * is used to prevent memory-consistency problems on Alpha CPUs. + * Regardless of the type of CPU, the list-traversal primitive + * must be guarded by rcu_read_lock(). + * + * OK, so why don't we have an hlist_for_each_entry_rcu()??? + */ +static inline void hlist_add_head_rcu(struct hlist_node *n, + struct hlist_head *h) +{ + struct hlist_node *first = h->first; + n->next = first; + n->pprev = &h->first; + smp_wmb(); + if (first) + first->pprev = &n->next; + h->first = n; +} + +/* next must be != NULL */ +static inline void hlist_add_before(struct hlist_node *n, + struct hlist_node *next) +{ + n->pprev = next->pprev; + n->next = next; + next->pprev = &n->next; + *(n->pprev) = n; +} + +static inline void hlist_add_after(struct hlist_node *n, + struct hlist_node *next) +{ + next->next = n->next; + n->next = next; + next->pprev = &n->next; + + if(next->next) + next->next->pprev = &next->next; +} + +#define hlist_entry(ptr, type, member) container_of(ptr,type,member) + +#define hlist_for_each(pos, head) \ + for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \ + pos = pos->next) + +#define hlist_for_each_safe(pos, n, head) \ + for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \ + pos = n) + +/** + * hlist_for_each_entry - iterate over list of given type + * @tpos: the type * to use as a loop counter. + * @pos: the &struct hlist_node to use as a loop counter. + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry(tpos, pos, head, member) \ + for (pos = (head)->first; \ + pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) + +/** + * hlist_for_each_entry_continue - iterate over a hlist continuing after existing point + * @tpos: the type * to use as a loop counter. + * @pos: the &struct hlist_node to use as a loop counter. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_continue(tpos, pos, member) \ + for (pos = (pos)->next; \ + pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) + +/** + * hlist_for_each_entry_from - iterate over a hlist continuing from existing point + * @tpos: the type * to use as a loop counter. + * @pos: the &struct hlist_node to use as a loop counter. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_from(tpos, pos, member) \ + for (; pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) + +/** + * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @tpos: the type * to use as a loop counter. + * @pos: the &struct hlist_node to use as a loop counter. + * @n: another &struct hlist_node to use as temporary storage + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ + for (pos = (head)->first; \ + pos && ({ n = pos->next; 1; }) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = n) + +/** + * hlist_for_each_entry_rcu - iterate over rcu list of given type + * @pos: the type * to use as a loop counter. + * @pos: the &struct hlist_node to use as a loop counter. + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + * + * This list-traversal primitive may safely run concurrently with + * the _rcu list-mutation primitives such as hlist_add_rcu() + * as long as the traversal is guarded by rcu_read_lock(). + */ +#define hlist_for_each_entry_rcu(tpos, pos, head, member) \ + for (pos = (head)->first; \ + pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next, ({ smp_read_barrier_depends(); 0; }) ) + +#endif diff --git a/daemon/include/local.h b/daemon/include/local.h new file mode 100644 index 0000000..350b8bf --- /dev/null +++ b/daemon/include/local.h @@ -0,0 +1,29 @@ +#ifndef _LOCAL_SOCKET_H_ +#define _LOCAL_SOCKET_H_ + +#include + +#ifndef UNIX_PATH_MAX +#define UNIX_PATH_MAX 108 +#endif + +struct local_conf { + int backlog; + int reuseaddr; + char path[UNIX_PATH_MAX]; +}; + +/* local server */ +int local_server_create(struct local_conf *conf); +void local_server_destroy(int fd); +int do_local_server_step(int fd, void *data, + void (*process)(int fd, void *data)); + +/* local client */ +int local_client_create(struct local_conf *conf); +void local_client_destroy(int fd); +int do_local_client_step(int fd, void (*process)(char *buf)); +int do_local_request(int, struct local_conf *,void (*step)(char *buf)); +void local_step(char *buf); + +#endif diff --git a/daemon/include/log.h b/daemon/include/log.h new file mode 100644 index 0000000..9ecff30 --- /dev/null +++ b/daemon/include/log.h @@ -0,0 +1,10 @@ +#ifndef _LOG_H_ +#define _LOG_H_ + +#include + +FILE *init_log(char *filename); +void dlog(FILE *fd, char *format, ...); +void close_log(FILE *fd); + +#endif diff --git a/daemon/include/mcast.h b/daemon/include/mcast.h new file mode 100644 index 0000000..0f3e3cd --- /dev/null +++ b/daemon/include/mcast.h @@ -0,0 +1,48 @@ +#ifndef _MCAST_H_ +#define _MCAST_H_ + +#include + +struct mcast_conf { + int ipproto; + int backlog; + int reuseaddr; + unsigned short port; + union { + struct in_addr inet_addr; + struct in6_addr inet_addr6; + } in; + union { + struct in_addr interface_addr; + struct in6_addr interface_addr6; + } ifa; +}; + +struct mcast_stats { + u_int64_t bytes; + u_int64_t messages; + u_int64_t error; +}; + +struct mcast_sock { + int fd; + union { + struct sockaddr_in ipv4; + struct sockaddr_in6 ipv6; + } addr; + struct mcast_stats stats; +}; + +struct mcast_sock *mcast_server_create(struct mcast_conf *conf); +void mcast_server_destroy(struct mcast_sock *m); + +struct mcast_sock *mcast_client_create(struct mcast_conf *conf); +void mcast_client_destroy(struct mcast_sock *m); + +int mcast_send(struct mcast_sock *m, void *data, int size); +int mcast_recv(struct mcast_sock *m, void *data, int size); + +struct mcast_stats *mcast_get_stats(struct mcast_sock *m); +void mcast_dump_stats(int fd, struct mcast_sock *s, struct mcast_sock *r); + +#endif diff --git a/daemon/include/network.h b/daemon/include/network.h new file mode 100644 index 0000000..dab50db --- /dev/null +++ b/daemon/include/network.h @@ -0,0 +1,34 @@ +#ifndef _NETWORK_H_ +#define _NETWORK_H_ + +#include + +struct nlnetwork { + u_int16_t flags; + u_int16_t checksum; + u_int32_t seq; +}; + +struct nlnetwork_ack { + u_int16_t flags; + u_int16_t checksum; + u_int32_t seq; + u_int32_t from; + u_int32_t to; +}; + +enum { + NET_HELLO_BIT = 0, + NET_HELLO = (1 << NET_HELLO_BIT), + + NET_RESYNC_BIT = 1, + NET_RESYNC = (1 << NET_RESYNC_BIT), + + NET_NACK_BIT = 2, + NET_NACK = (1 << NET_NACK_BIT), + + NET_ACK_BIT = 3, + NET_ACK = (1 << NET_ACK_BIT), +}; + +#endif diff --git a/daemon/include/slist.h b/daemon/include/slist.h new file mode 100644 index 0000000..ab7fa34 --- /dev/null +++ b/daemon/include/slist.h @@ -0,0 +1,41 @@ +#ifndef _SLIST_H_ +#define _SLIST_H_ + +#include "linux_list.h" + +#define INIT_SLIST_HEAD(ptr) ((ptr).next = NULL) + +struct slist_head { + struct slist_head *next; +}; + +static inline int slist_empty(const struct slist_head *h) +{ + return !h->next; +} + +static inline void slist_del(struct slist_head *t, struct slist_head *prev) +{ + prev->next = t->next; + t->next = LIST_POISON1; +} + +static inline void slist_add(struct slist_head *head, struct slist_head *t) +{ + struct slist_head *tmp = head->next; + head->next = t; + t->next = tmp; +} + +#define slist_entry(ptr, type, member) container_of(ptr,type,member) + +#define slist_for_each(pos, head) \ + for (pos = (head)->next; pos && ({ prefetch(pos.next); 1; }); \ + pos = pos->next) + +#define slist_for_each_safe(pos, prev, next, head) \ + for (pos = (head)->next, prev = (head); \ + pos && ({ next = pos->next; 1; }); \ + ({ prev = (prev->next != next) ? prev->next : prev; }), pos = next) + +#endif diff --git a/daemon/include/state_helper.h b/daemon/include/state_helper.h new file mode 100644 index 0000000..1ed0b79 --- /dev/null +++ b/daemon/include/state_helper.h @@ -0,0 +1,20 @@ +#ifndef _STATE_HELPER_H_ +#define _STATE_HELPER_H_ + +enum { + ST_H_SKIP, + ST_H_REPLICATE +}; + +struct state_replication_helper { + u_int8_t proto; + unsigned int state; + + int (*verdict)(const struct state_replication_helper *h, + const struct nf_conntrack *ct); +}; + +int state_helper_verdict(int type, struct nf_conntrack *ct); +void state_helper_register(struct state_replication_helper *h, int state); + +#endif diff --git a/daemon/include/sync.h b/daemon/include/sync.h new file mode 100644 index 0000000..7756c87 --- /dev/null +++ b/daemon/include/sync.h @@ -0,0 +1,23 @@ +#ifndef _SYNC_HOOKS_H_ +#define _SYNC_HOOKS_H_ + +struct nlnetwork; +struct us_conntrack; + +struct sync_mode { + int internal_cache_flags; + int external_cache_flags; + struct cache_extra *internal_cache_extra; + struct cache_extra *external_cache_extra; + + int (*init)(void); + void (*kill)(void); + int (*local)(int fd, int type, void *data); + int (*pre_recv)(const struct nlnetwork *net); + void (*post_send)(const struct nlnetwork *net, struct us_conntrack *u); +}; + +extern struct sync_mode notrack; +extern struct sync_mode nack; + +#endif diff --git a/daemon/include/us-conntrack.h b/daemon/include/us-conntrack.h new file mode 100644 index 0000000..3d71e22 --- /dev/null +++ b/daemon/include/us-conntrack.h @@ -0,0 +1,13 @@ +#ifndef _US_CONNTRACK_H_ +#define _US_CONNTRACK_H_ + +#include + +/* be careful, do not modify the layout */ +struct us_conntrack { + struct nf_conntrack *ct; + struct cache *cache; /* add new attributes here */ + char data[0]; +}; + +#endif diff --git a/daemon/src/Makefile.am b/daemon/src/Makefile.am new file mode 100644 index 0000000..5d1c6cb --- /dev/null +++ b/daemon/src/Makefile.am @@ -0,0 +1,22 @@ +include $(top_srcdir)/Make_global.am + +YACC=@YACC@ -d + +CLEANFILES = read_config_yy.c read_config_lex.c + +sbin_PROGRAMS = conntrackd +conntrackd_SOURCES = alarm.c main.c run.c hash.c buffer.c \ + local.c log.c mcast.c netlink.c proxy.c lock.c \ + ignore_pool.c \ + cache.c cache_iterators.c \ + cache_lifetime.c cache_timer.c \ + sync-mode.c sync-notrack.c sync-nack.c \ + traffic_stats.c stats-mode.c \ + network.c checksum.c \ + state_helper.c state_helper_tcp.c \ + read_config_yy.y read_config_lex.l + +conntrackd_LDFLAGS = $(all_libraries) -lnfnetlink -lnetfilter_conntrack \ + -lpthread + +EXTRA_DIST = read_config_yy.h diff --git a/daemon/src/alarm.c b/daemon/src/alarm.c new file mode 100644 index 0000000..1a465c2 --- /dev/null +++ b/daemon/src/alarm.c @@ -0,0 +1,141 @@ +/* + * (C) 2006 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include "linux_list.h" +#include "conntrackd.h" +#include "alarm.h" +#include "jhash.h" +#include +#include +#include + +/* alarm cascade */ +#define ALARM_CASCADE_SIZE 10 +static struct list_head *alarm_cascade; + +/* thread stuff */ +static pthread_t alarm_thread; + +struct alarm_list *create_alarm() +{ + return (struct alarm_list *) malloc(sizeof(struct alarm_list)); +} + +void destroy_alarm(struct alarm_list *t) +{ + free(t); +} + +void set_alarm_expiration(struct alarm_list *t, unsigned long expires) +{ + t->expires = expires; +} + +void set_alarm_function(struct alarm_list *t, + void (*fcn)(struct alarm_list *a, void *data)) +{ + t->function = fcn; +} + +void set_alarm_data(struct alarm_list *t, void *data) +{ + t->data = data; +} + +void init_alarm(struct alarm_list *t) +{ + INIT_LIST_HEAD(&t->head); + + t->expires = 0; + t->data = 0; + t->function = NULL; +} + +void add_alarm(struct alarm_list *alarm) +{ + unsigned int pos = jhash(alarm, sizeof(alarm), 0) % ALARM_CASCADE_SIZE; + + list_add(&alarm->head, &alarm_cascade[pos]); +} + +void del_alarm(struct alarm_list *alarm) +{ + list_del(&alarm->head); +} + +int mod_alarm(struct alarm_list *alarm, unsigned long expires) +{ + alarm->expires = expires; + return 0; +} + +void __run_alarms() +{ + struct list_head *i, *tmp; + struct alarm_list *t; + struct timespec req = {0, 1000000000 / ALARM_CASCADE_SIZE}; + struct timespec rem; + static int step = 0; + +retry: + if (nanosleep(&req, &rem) == -1) { + /* interrupted syscall: retry with remaining time */ + if (errno == EINTR) { + memcpy(&req, &rem, sizeof(struct timespec)); + goto retry; + } + } + + lock(); + list_for_each_safe(i, tmp, &alarm_cascade[step]) { + t = (struct alarm_list *) i; + + t->expires--; + if (t->expires == 0) + t->function(t, t->data); + } + step = (step + 1) < ALARM_CASCADE_SIZE ? step + 1 : 0; + unlock(); +} + +void *run_alarms(void *foo) +{ + while(1) + __run_alarms(); +} + +int create_alarm_thread() +{ + int i; + + alarm_cascade = malloc(sizeof(struct list_head) * ALARM_CASCADE_SIZE); + if (alarm_cascade == NULL) + return -1; + + for (i=0; i + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "buffer.h" + +struct buffer *buffer_create(size_t max_size) +{ + struct buffer *b; + + b = malloc(sizeof(struct buffer)); + if (b == NULL) + return NULL; + memset(b, 0, sizeof(struct buffer)); + + b->max_size = max_size; + INIT_LIST_HEAD(&b->head); + pthread_mutex_init(&b->lock, NULL); + + return b; +} + +void buffer_destroy(struct buffer *b) +{ + struct list_head *i, *tmp; + struct buffer_node *node; + + pthread_mutex_lock(&b->lock); + list_for_each_safe(i, tmp, &b->head) { + node = (struct buffer_node *) i; + list_del(i); + free(node); + } + pthread_mutex_unlock(&b->lock); + pthread_mutex_destroy(&b->lock); + free(b); +} + +static struct buffer_node *buffer_node_create(const void *data, size_t size) +{ + struct buffer_node *n; + + n = malloc(sizeof(struct buffer_node) + size); + if (n == NULL) + return NULL; + + INIT_LIST_HEAD(&n->head); + n->size = size; + memcpy(n->data, data, size); + + return n; +} + +int buffer_add(struct buffer *b, const void *data, size_t size) +{ + int ret = 0; + struct buffer_node *n; + + pthread_mutex_lock(&b->lock); + + /* does it fit this buffer? */ + if (size > b->max_size) { + errno = ENOSPC; + ret = -1; + goto err; + } + +retry: + /* buffer is full: kill the oldest entry */ + if (b->cur_size + size > b->max_size) { + n = (struct buffer_node *) b->head.prev; + list_del(b->head.prev); + b->cur_size -= n->size; + free(n); + goto retry; + } + + n = buffer_node_create(data, size); + if (n == NULL) { + ret = -1; + goto err; + } + + list_add(&n->head, &b->head); + b->cur_size += size; + +err: + pthread_mutex_unlock(&b->lock); + return ret; +} + +void __buffer_del(struct buffer *b, void *data) +{ + struct buffer_node *n = container_of(data, struct buffer_node, data); + + list_del(&n->head); + b->cur_size -= n->size; + free(n); +} + +void buffer_del(struct buffer *b, void *data) +{ + pthread_mutex_lock(&b->lock); + buffer_del(b, data); + pthread_mutex_unlock(&b->lock); +} + +void buffer_iterate(struct buffer *b, + void *data, + int (*iterate)(void *data1, void *data2)) +{ + struct list_head *i, *tmp; + struct buffer_node *n; + + pthread_mutex_lock(&b->lock); + list_for_each_safe(i, tmp, &b->head) { + n = (struct buffer_node *) i; + if (iterate(n->data, data)) + break; + } + pthread_mutex_unlock(&b->lock); +} diff --git a/daemon/src/cache.c b/daemon/src/cache.c new file mode 100644 index 0000000..6f7442b --- /dev/null +++ b/daemon/src/cache.c @@ -0,0 +1,446 @@ +/* + * (C) 2006-2007 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "jhash.h" +#include "hash.h" +#include "conntrackd.h" +#include +#include +#include "us-conntrack.h" +#include "cache.h" +#include "debug.h" + +static u_int32_t hash(const void *data, struct hashtable *table) +{ + unsigned int a, b; + const struct us_conntrack *u = data; + struct nf_conntrack *ct = u->ct; + + a = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV4_SRC), sizeof(u_int32_t), + ((nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO) << 16) | + (nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO)))); + + b = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV4_DST), sizeof(u_int32_t), + ((nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC) << 16) | + (nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST)))); + + return jhash_2words(a, b, 0) % table->hashsize; +} + +static u_int32_t hash6(const void *data, struct hashtable *table) +{ + unsigned int a, b; + const struct us_conntrack *u = data; + struct nf_conntrack *ct = u->ct; + + a = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV6_SRC), sizeof(u_int32_t), + ((nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO) << 16) | + (nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO)))); + + b = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV6_DST), sizeof(u_int32_t), + ((nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC) << 16) | + (nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST)))); + + return jhash_2words(a, b, 0) % table->hashsize; +} + +static int __compare(const struct nf_conntrack *ct1, + const struct nf_conntrack *ct2) +{ + return ((nfct_get_attr_u8(ct1, ATTR_ORIG_L3PROTO) == + nfct_get_attr_u8(ct2, ATTR_ORIG_L3PROTO)) && + (nfct_get_attr_u8(ct1, ATTR_ORIG_L4PROTO) == + nfct_get_attr_u8(ct2, ATTR_ORIG_L4PROTO)) && + (nfct_get_attr_u16(ct1, ATTR_ORIG_PORT_SRC) == + nfct_get_attr_u16(ct2, ATTR_ORIG_PORT_SRC)) && + (nfct_get_attr_u16(ct1, ATTR_ORIG_PORT_DST) == + nfct_get_attr_u16(ct2, ATTR_ORIG_PORT_DST)) && + (nfct_get_attr_u16(ct1, ATTR_REPL_PORT_SRC) == + nfct_get_attr_u16(ct2, ATTR_REPL_PORT_SRC)) && + (nfct_get_attr_u16(ct1, ATTR_REPL_PORT_DST) == + nfct_get_attr_u16(ct2, ATTR_REPL_PORT_DST))); +} + +static int compare(const void *data1, const void *data2) +{ + const struct us_conntrack *u1 = data1; + const struct us_conntrack *u2 = data2; + + return ((nfct_get_attr_u32(u1->ct, ATTR_ORIG_IPV4_SRC) == + nfct_get_attr_u32(u2->ct, ATTR_ORIG_IPV4_SRC)) && + (nfct_get_attr_u32(u1->ct, ATTR_ORIG_IPV4_DST) == + nfct_get_attr_u32(u2->ct, ATTR_ORIG_IPV4_DST)) && + (nfct_get_attr_u32(u1->ct, ATTR_REPL_IPV4_SRC) == + nfct_get_attr_u32(u2->ct, ATTR_REPL_IPV4_SRC)) && + (nfct_get_attr_u32(u1->ct, ATTR_REPL_IPV4_DST) == + nfct_get_attr_u32(u2->ct, ATTR_REPL_IPV4_DST)) && + __compare(u1->ct, u2->ct)); +} + +static int compare6(const void *data1, const void *data2) +{ + const struct us_conntrack *u1 = data1; + const struct us_conntrack *u2 = data2; + + return ((nfct_get_attr_u32(u1->ct, ATTR_ORIG_IPV6_SRC) == + nfct_get_attr_u32(u2->ct, ATTR_ORIG_IPV6_SRC)) && + (nfct_get_attr_u32(u1->ct, ATTR_ORIG_IPV6_DST) == + nfct_get_attr_u32(u2->ct, ATTR_ORIG_IPV6_DST)) && + (nfct_get_attr_u32(u1->ct, ATTR_REPL_IPV6_SRC) == + nfct_get_attr_u32(u2->ct, ATTR_REPL_IPV6_SRC)) && + (nfct_get_attr_u32(u1->ct, ATTR_REPL_IPV6_DST) == + nfct_get_attr_u32(u2->ct, ATTR_REPL_IPV6_DST)) && + __compare(u1->ct, u2->ct)); +} + +struct cache_feature *cache_feature[CACHE_MAX_FEATURE] = { + [TIMER_FEATURE] = &timer_feature, + [LIFETIME_FEATURE] = &lifetime_feature, +}; + +struct cache *cache_create(char *name, + unsigned int features, + u_int8_t proto, + struct cache_extra *extra) +{ + size_t size = sizeof(struct us_conntrack); + int i, j = 0; + struct cache *c; + struct cache_feature *feature_array[CACHE_MAX_FEATURE] = {}; + unsigned int feature_offset[CACHE_MAX_FEATURE] = {}; + unsigned int feature_type[CACHE_MAX_FEATURE] = {}; + + c = malloc(sizeof(struct cache)); + if (!c) + return NULL; + memset(c, 0, sizeof(struct cache)); + + strcpy(c->name, name); + + for (i = 0; i < CACHE_MAX_FEATURE; i++) { + if ((1 << i) & features) { + feature_array[j] = cache_feature[i]; + feature_offset[j] = size; + feature_type[i] = j; + size += cache_feature[i]->size; + j++; + } + } + + memcpy(c->feature_type, feature_type, sizeof(feature_type)); + + c->features = malloc(sizeof(struct cache_feature) * j); + if (!c->features) { + free(c); + return NULL; + } + memcpy(c->features, feature_array, sizeof(struct cache_feature) * j); + c->num_features = j; + + c->extra_offset = size; + c->extra = extra; + if (extra) + size += extra->size; + + c->feature_offset = malloc(sizeof(unsigned int) * j); + if (!c->feature_offset) { + free(c->features); + free(c); + return NULL; + } + memcpy(c->feature_offset, feature_offset, sizeof(unsigned int) * j); + + switch(proto) { + case AF_INET: + c->h = hashtable_create(CONFIG(hashsize), + CONFIG(limit), + size, + hash, + compare); + break; + case AF_INET6: + c->h = hashtable_create(CONFIG(hashsize), + CONFIG(limit), + size, + hash6, + compare6); + break; + } + + if (!c->h) { + free(c->features); + free(c->feature_offset); + free(c); + return NULL; + } + + return c; +} + +void cache_destroy(struct cache *c) +{ + lock(); + hashtable_destroy(c->h); + unlock(); + free(c->features); + free(c->feature_offset); + free(c); +} + +static struct us_conntrack *__add(struct cache *c, struct nf_conntrack *ct) +{ + int i; + size_t size = c->h->datasize; + char buf[size]; + struct us_conntrack *u = (struct us_conntrack *) buf; + struct nf_conntrack *newct; + + memset(u, 0, size); + + u->cache = c; + if ((u->ct = newct = nfct_new()) == NULL) { + errno = ENOMEM; + return 0; + } + memcpy(u->ct, ct, nfct_sizeof(ct)); + + u = hashtable_add(c->h, u); + if (u) { + void *data = u->data; + + for (i = 0; i < c->num_features; i++) { + c->features[i]->add(u, data); + data += c->features[i]->size; + } + + if (c->extra) + c->extra->add(u, ((void *) u) + c->extra_offset); + + return u; + } + free(newct); + + return NULL; +} + +struct us_conntrack *__cache_add(struct cache *c, struct nf_conntrack *ct) +{ + struct us_conntrack *u; + + u = __add(c, ct); + if (u) { + c->add_ok++; + return u; + } + c->add_fail++; + + return NULL; +} + +struct us_conntrack *cache_add(struct cache *c, struct nf_conntrack *ct) +{ + struct us_conntrack *u; + + lock(); + u = __cache_add(c, ct); + unlock(); + + return u; +} + +static struct us_conntrack *__update(struct cache *c, struct nf_conntrack *ct) +{ + size_t size = c->h->datasize; + char buf[size]; + struct us_conntrack *u = (struct us_conntrack *) buf; + + u->ct = ct; + + u = (struct us_conntrack *) hashtable_test(c->h, u); + if (u) { + int i; + void *data = u->data; + + for (i = 0; i < c->num_features; i++) { + c->features[i]->update(u, data); + data += c->features[i]->size; + } + + if (c->extra) + c->extra->update(u, ((void *) u) + c->extra_offset); + + if (nfct_attr_is_set(ct, ATTR_STATUS)) + nfct_set_attr_u32(u->ct, ATTR_STATUS, + nfct_get_attr_u32(ct, ATTR_STATUS)); + if (nfct_attr_is_set(ct, ATTR_TCP_STATE)) + nfct_set_attr_u8(u->ct, ATTR_TCP_STATE, + nfct_get_attr_u8(ct, ATTR_TCP_STATE)); + if (nfct_attr_is_set(ct, ATTR_TIMEOUT)) + nfct_set_attr_u32(u->ct, ATTR_TIMEOUT, + nfct_get_attr_u32(ct, ATTR_TIMEOUT)); + + return u; + } + return NULL; +} + +struct us_conntrack *__cache_update(struct cache *c, struct nf_conntrack *ct) +{ + struct us_conntrack *u; + + u = __update(c, ct); + if (u) { + c->upd_ok++; + return u; + } + c->upd_fail++; + + return NULL; +} + +struct us_conntrack *cache_update(struct cache *c, struct nf_conntrack *ct) +{ + struct us_conntrack *u; + + lock(); + u = __cache_update(c, ct); + unlock(); + + return u; +} + +struct us_conntrack *cache_update_force(struct cache *c, + struct nf_conntrack *ct) +{ + struct us_conntrack *u; + + lock(); + if ((u = __update(c, ct)) != NULL) { + c->upd_ok++; + unlock(); + return u; + } + if ((u = __add(c, ct)) != NULL) { + c->add_ok++; + unlock(); + return u; + } + c->add_fail++; + unlock(); + return NULL; +} + +int cache_test(struct cache *c, struct nf_conntrack *ct) +{ + size_t size = c->h->datasize; + char buf[size]; + struct us_conntrack *u = (struct us_conntrack *) buf; + void *ret; + + u->ct = ct; + + lock(); + ret = hashtable_test(c->h, u); + unlock(); + + return ret != NULL; +} + +static int __del(struct cache *c, struct nf_conntrack *ct) +{ + size_t size = c->h->datasize; + char buf[size]; + struct us_conntrack *u = (struct us_conntrack *) buf; + + u->ct = ct; + + u = (struct us_conntrack *) hashtable_test(c->h, u); + if (u) { + int i; + void *data = u->data; + struct nf_conntrack *p = u->ct; + + for (i = 0; i < c->num_features; i++) { + c->features[i]->destroy(u, data); + data += c->features[i]->size; + } + + if (c->extra) + c->extra->destroy(u, ((void *) u) + c->extra_offset); + + hashtable_del(c->h, u); + free(p); + return 1; + } + return 0; +} + +int __cache_del(struct cache *c, struct nf_conntrack *ct) +{ + if (__del(c, ct)) { + c->del_ok++; + return 1; + } + c->del_fail++; + + return 0; +} + +int cache_del(struct cache *c, struct nf_conntrack *ct) +{ + int ret; + + lock(); + ret = __cache_del(c, ct); + unlock(); + + return ret; +} + +struct us_conntrack *cache_get_conntrack(struct cache *c, void *data) +{ + return data - c->extra_offset; +} + +void *cache_get_extra(struct cache *c, void *data) +{ + return data + c->extra_offset; +} + +void cache_stats(struct cache *c, int fd) +{ + char buf[512]; + int size; + + lock(); + size = sprintf(buf, "cache %s:\n" + "current active connections:\t%12u\n" + "connections created:\t\t%12u\tfailed:\t%12u\n" + "connections updated:\t\t%12u\tfailed:\t%12u\n" + "connections destroyed:\t\t%12u\tfailed:\t%12u\n\n", + c->name, + hashtable_counter(c->h), + c->add_ok, + c->add_fail, + c->upd_ok, + c->upd_fail, + c->del_ok, + c->del_fail); + unlock(); + send(fd, buf, size, 0); +} diff --git a/daemon/src/cache_iterators.c b/daemon/src/cache_iterators.c new file mode 100644 index 0000000..5d5d22b --- /dev/null +++ b/daemon/src/cache_iterators.c @@ -0,0 +1,229 @@ +/* + * (C) 2006-2007 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "cache.h" +#include "jhash.h" +#include "hash.h" +#include "conntrackd.h" +#include +#include +#include "us-conntrack.h" +#include "debug.h" + +struct __dump_container { + int fd; + int type; +}; + +static int do_dump(void *data1, void *data2) +{ + char buf[1024]; + int size; + struct __dump_container *container = data1; + struct us_conntrack *u = data2; + void *data = u->data; + int i; + + memset(buf, 0, sizeof(buf)); + size = nfct_snprintf(buf, + sizeof(buf), + u->ct, + NFCT_T_UNKNOWN, + container->type, + 0); + + for (i = 0; i < u->cache->num_features; i++) { + if (u->cache->features[i]->dump) { + size += u->cache->features[i]->dump(u, + data, + buf+size, + container->type); + data += u->cache->features[i]->size; + } + } + size += sprintf(buf+size, "\n"); + if (send(container->fd, buf, size, 0) == -1) { + if (errno != EPIPE) + return -1; + } + + return 0; +} + +void cache_dump(struct cache *c, int fd, int type) +{ + struct __dump_container tmp = { + .fd = fd, + .type = type + }; + + lock(); + hashtable_iterate(c->h, (void *) &tmp, do_dump); + unlock(); +} + +static int do_commit(void *data1, void *data2) +{ + int ret; + struct cache *c = data1; + struct us_conntrack *u = data2; + struct nf_conntrack *ct; + char buf[4096]; + struct nlmsghdr *nlh = (struct nlmsghdr *)buf; + + ct = nfct_clone(u->ct); + if (ct == NULL) + return 0; + + if (nfct_attr_is_set(ct, ATTR_STATUS)) { + u_int32_t status = nfct_get_attr_u32(ct, ATTR_STATUS); + status &= ~IPS_EXPECTED; + nfct_set_attr_u32(ct, ATTR_STATUS, status); + } + + if (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) + nfct_setobjopt(ct, NFCT_SOPT_UNDO_SNAT); + if (nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) + nfct_setobjopt(ct, NFCT_SOPT_UNDO_DNAT); + if (nfct_getobjopt(ct, NFCT_GOPT_IS_SPAT)) + nfct_setobjopt(ct, NFCT_SOPT_UNDO_SPAT); + if (nfct_getobjopt(ct, NFCT_GOPT_IS_DPAT)) + nfct_setobjopt(ct, NFCT_SOPT_UNDO_DPAT); + + /* + * Set a reduced timeout for candidate-to-be-committed + * conntracks that live in the external cache + */ + nfct_set_attr_u32(ct, ATTR_TIMEOUT, CONFIG(commit_timeout)); + + ret = nfct_build_query(STATE(subsys_sync), + NFCT_Q_CREATE, + ct, + nlh, + sizeof(buf)); + + free(ct); + + if (ret == -1) { + /* XXX: Please cleanup this debug crap, default in logfile */ + debug("--- failed to build: %s --- \n", strerror(errno)); + return 0; + } + + ret = nfnl_query(STATE(sync), nlh); + if (ret == -1) { + switch(errno) { + case EEXIST: + c->commit_exist++; + break; + default: + c->commit_fail++; + break; + } + debug("--- failed to commit: %s --- \n", strerror(errno)); + } else { + c->commit_ok++; + debug("----- commit -----\n"); + } + + /* keep iterating even if we have found errors */ + return 0; +} + +void cache_commit(struct cache *c) +{ + unsigned int commit_ok = c->commit_ok; + unsigned int commit_exist = c->commit_exist; + unsigned int commit_fail = c->commit_fail; + + lock(); + hashtable_iterate(c->h, c, do_commit); + unlock(); + + /* calculate new entries committed */ + commit_ok = c->commit_ok - commit_ok; + commit_fail = c->commit_fail - commit_fail; + commit_exist = c->commit_exist - commit_exist; + + /* log results */ + dlog(STATE(log), "Committed %u new entries", commit_ok); + + if (commit_exist) + dlog(STATE(log), "%u entries ignored, " + "already exist", commit_exist); + if (commit_fail) + dlog(STATE(log), "%u entries can't be " + "committed", commit_fail); +} + +static int do_flush(void *data1, void *data2) +{ + struct cache *c = data1; + struct us_conntrack *u = data2; + void *data = u->data; + int i; + + for (i = 0; i < c->num_features; i++) { + c->features[i]->destroy(u, data); + data += c->features[i]->size; + } + free(u->ct); + + return 0; +} + +void cache_flush(struct cache *c) +{ + lock(); + hashtable_iterate(c->h, c, do_flush); + hashtable_flush(c->h); + c->flush++; + unlock(); +} + +#include "sync.h" +#include "network.h" + +static int do_bulk(void *data1, void *data2) +{ + int ret; + struct us_conntrack *u = data2; + char buf[4096]; + struct nlnetwork *net = (struct nlnetwork *) buf; + + ret = build_network_msg(NFCT_Q_UPDATE, + STATE(subsys_sync), + u->ct, + buf, + sizeof(buf)); + if (ret == -1) + debug_ct(u->ct, "failed to build"); + + mcast_send_netmsg(STATE_SYNC(mcast_client), net); + STATE_SYNC(mcast_sync)->post_send(net, u); + + /* keep iterating even if we have found errors */ + return 0; +} + +void cache_bulk(struct cache *c) +{ + lock(); + hashtable_iterate(c->h, NULL, do_bulk); + unlock(); +} diff --git a/daemon/src/cache_lifetime.c b/daemon/src/cache_lifetime.c new file mode 100644 index 0000000..ae54df2 --- /dev/null +++ b/daemon/src/cache_lifetime.c @@ -0,0 +1,65 @@ +/* + * (C) 2006 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include "conntrackd.h" +#include "us-conntrack.h" +#include "cache.h" +#include "alarm.h" + +static void lifetime_add(struct us_conntrack *u, void *data) +{ + long *lifetime = data; + struct timeval tv; + + gettimeofday(&tv, NULL); + + *lifetime = tv.tv_sec; +} + +static void lifetime_update(struct us_conntrack *u, void *data) +{ +} + +static void lifetime_destroy(struct us_conntrack *u, void *data) +{ +} + +static int lifetime_dump(struct us_conntrack *u, + void *data, + char *buf, + int type) +{ + long *lifetime = data; + struct timeval tv; + + if (type == NFCT_O_XML) + return 0; + + gettimeofday(&tv, NULL); + + return sprintf(buf, " [active since %lds]", tv.tv_sec - *lifetime); +} + +struct cache_feature lifetime_feature = { + .size = sizeof(long), + .add = lifetime_add, + .update = lifetime_update, + .destroy = lifetime_destroy, + .dump = lifetime_dump +}; diff --git a/daemon/src/cache_timer.c b/daemon/src/cache_timer.c new file mode 100644 index 0000000..213b59a --- /dev/null +++ b/daemon/src/cache_timer.c @@ -0,0 +1,72 @@ +/* + * (C) 2006 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include "conntrackd.h" +#include "us-conntrack.h" +#include "cache.h" +#include "alarm.h" + +static void timeout(struct alarm_list *a, void *data) +{ + struct us_conntrack *u = data; + + debug_ct(u->ct, "expired timeout"); + __cache_del(u->cache, u->ct); +} + +static void timer_add(struct us_conntrack *u, void *data) +{ + struct alarm_list *alarm = data; + + init_alarm(alarm); + set_alarm_expiration(alarm, CONFIG(cache_timeout)); + set_alarm_data(alarm, u); + set_alarm_function(alarm, timeout); + add_alarm(alarm); +} + +static void timer_update(struct us_conntrack *u, void *data) +{ + struct alarm_list *alarm = data; + mod_alarm(alarm, CONFIG(cache_timeout)); +} + +static void timer_destroy(struct us_conntrack *u, void *data) +{ + struct alarm_list *alarm = data; + del_alarm(alarm); +} + +static int timer_dump(struct us_conntrack *u, void *data, char *buf, int type) +{ + struct alarm_list *alarm = data; + + if (type == NFCT_O_XML) + return 0; + + return sprintf(buf, " [expires in %ds]", alarm->expires); +} + +struct cache_feature timer_feature = { + .size = sizeof(struct alarm_list), + .add = timer_add, + .update = timer_update, + .destroy = timer_destroy, + .dump = timer_dump +}; diff --git a/daemon/src/checksum.c b/daemon/src/checksum.c new file mode 100644 index 0000000..41866ff --- /dev/null +++ b/daemon/src/checksum.c @@ -0,0 +1,32 @@ +/* + * Extracted from RFC 1071 with some minor changes to fix compilation on GCC, + * this can probably be improved + * --pablo 11/feb/07 + */ + +#include + +unsigned short do_csum(const void *addr, unsigned int count) +{ + unsigned int sum = 0; + + /* checksumming disabled, just skip */ + if (CONFIG(flags) & DONT_CHECKSUM) + return 0; + + while(count > 1) { + /* This is the inner loop */ + sum += *((unsigned short *) addr++); + count -= 2; + } + + /* Add left-over byte, if any */ + if(count > 0) + sum += *((unsigned char *) addr); + + /* Fold 32-bit sum to 16 bits */ + while (sum>>16) + sum = (sum & 0xffff) + (sum >> 16); + + return ~sum; +} diff --git a/daemon/src/hash.c b/daemon/src/hash.c new file mode 100644 index 0000000..274a140 --- /dev/null +++ b/daemon/src/hash.c @@ -0,0 +1,199 @@ +/* + * (C) 2006-2007 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Description: generic hash table implementation + */ + +#include +#include +#include +#include +#include +#include "slist.h" +#include "hash.h" + + +struct hashtable_node *hashtable_alloc_node(int datasize, void *data) +{ + struct hashtable_node *n; + int size = sizeof(struct hashtable_node) + datasize; + + n = malloc(size); + if (!n) + return NULL; + memset(n, 0, size); + memcpy(n->data, data, datasize); + + return n; +} + +void hashtable_destroy_node(struct hashtable_node *h) +{ + free(h); +} + +struct hashtable * +hashtable_create(int hashsize, int limit, int datasize, + u_int32_t (*hash)(const void *data, struct hashtable *table), + int (*compare)(const void *data1, const void *data2)) +{ + int i; + struct hashtable *h; + struct hashtype *t; + int size = sizeof(struct hashtable) + + hashsize * sizeof(struct slist_head); + + h = (struct hashtable *) malloc(size); + if (!h) { + errno = ENOMEM; + return NULL; + } + + memset(h, 0, size); + for (i=0; imembers[i]); + + h->hashsize = hashsize; + h->limit = limit; + h->datasize = datasize; + h->hash = hash; + h->compare = compare; + + return h; +} + +void hashtable_destroy(struct hashtable *h) +{ + hashtable_flush(h); + free(h); +} + +void *hashtable_add(struct hashtable *table, void *data) +{ + struct slist_head *e; + struct hashtable_node *n; + u_int32_t id; + int i; + + /* hash table is full */ + if (table->count >= table->limit) { + errno = ENOSPC; + return NULL; + } + + id = table->hash(data, table); + + slist_for_each(e, &table->members[id]) { + n = slist_entry(e, struct hashtable_node, head); + if (table->compare(n->data, data)) { + errno = EEXIST; + return NULL; + } + } + + n = hashtable_alloc_node(table->datasize, data); + if (n == NULL) { + errno = ENOMEM; + return NULL; + } + + slist_add(&table->members[id], &n->head); + table->count++; + + return n->data; +} + +void *hashtable_test(struct hashtable *table, const void *data) +{ + struct slist_head *e; + u_int32_t id; + struct hashtable_node *n; + int i; + + id = table->hash(data, table); + + slist_for_each(e, &table->members[id]) { + n = slist_entry(e, struct hashtable_node, head); + if (table->compare(n->data, data)) + return n->data; + } + + errno = ENOENT; + return NULL; +} + +int hashtable_del(struct hashtable *table, void *data) +{ + struct slist_head *e, *next, *prev; + u_int32_t id; + struct hashtable_node *n; + int i; + + id = table->hash(data, table); + + slist_for_each_safe(e, prev, next, &table->members[id]) { + n = slist_entry(e, struct hashtable_node, head); + if (table->compare(n->data, data)) { + slist_del(e, prev); + hashtable_destroy_node(n); + table->count--; + return 0; + } + } + errno = ENOENT; + return -1; +} + +int hashtable_flush(struct hashtable *table) +{ + int i; + struct slist_head *e, *next, *prev; + struct hashtable_node *n; + + for (i=0; i < table->hashsize; i++) + slist_for_each_safe(e, prev, next, &table->members[i]) { + n = slist_entry(e, struct hashtable_node, head); + slist_del(e, prev); + hashtable_destroy_node(n); + } + + table->count = 0; + + return 0; +} + +int hashtable_iterate(struct hashtable *table, void *data, + int (*iterate)(void *data1, void *data2)) +{ + int i; + struct slist_head *e, *next, *prev; + struct hashtable_node *n; + + for (i=0; i < table->hashsize; i++) { + slist_for_each_safe(e, prev, next, &table->members[i]) { + n = slist_entry(e, struct hashtable_node, head); + if (iterate(data, n->data) == -1) + return -1; + } + } + return 0; +} + +unsigned int hashtable_counter(struct hashtable *table) +{ + return table->count; +} diff --git a/daemon/src/ignore_pool.c b/daemon/src/ignore_pool.c new file mode 100644 index 0000000..5946617 --- /dev/null +++ b/daemon/src/ignore_pool.c @@ -0,0 +1,136 @@ +/* + * (C) 2006-2007 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "jhash.h" +#include "hash.h" +#include "conntrackd.h" +#include "ignore.h" +#include "debug.h" +#include + +#define IGNORE_POOL_SIZE 32 +#define IGNORE_POOL_LIMIT 1024 + +static u_int32_t hash(const void *data, struct hashtable *table) +{ + const u_int32_t *ip = data; + + return jhash_1word(*ip, 0) % table->hashsize; +} + +static u_int32_t hash6(const void *data, struct hashtable *table) +{ + return jhash(data, sizeof(u_int32_t)*4, 0) % table->hashsize; +} + +static int compare(const void *data1, const void *data2) +{ + const u_int32_t *ip1 = data1; + const u_int32_t *ip2 = data2; + + return *ip1 == *ip2; +} + +static int compare6(const void *data1, const void *data2) +{ + return memcmp(data1, data2, sizeof(u_int32_t)*4) == 0; +} + +struct ignore_pool *ignore_pool_create(u_int8_t proto) +{ + int i, j = 0; + struct ignore_pool *ip; + + ip = malloc(sizeof(struct ignore_pool)); + if (!ip) + return NULL; + memset(ip, 0, sizeof(struct ignore_pool)); + + switch(proto) { + case AF_INET: + ip->h = hashtable_create(IGNORE_POOL_SIZE, + IGNORE_POOL_LIMIT, + sizeof(u_int32_t), + hash, + compare); + break; + case AF_INET6: + ip->h = hashtable_create(IGNORE_POOL_SIZE, + IGNORE_POOL_LIMIT, + sizeof(u_int32_t)*4, + hash6, + compare6); + break; + } + + if (!ip->h) { + free(ip); + return NULL; + } + + return ip; +} + +void ignore_pool_destroy(struct ignore_pool *ip) +{ + hashtable_destroy(ip->h); + free(ip); +} + +int ignore_pool_add(struct ignore_pool *ip, void *data) +{ + if (!hashtable_add(ip->h, data)) + return 0; + + return 1; +} + +int __ignore_pool_test_ipv4(struct ignore_pool *ip, struct nf_conntrack *ct) +{ + return (hashtable_test(ip->h, nfct_get_attr(ct, ATTR_ORIG_IPV4_SRC)) || + hashtable_test(ip->h, nfct_get_attr(ct, ATTR_ORIG_IPV4_DST)) || + hashtable_test(ip->h, nfct_get_attr(ct, ATTR_REPL_IPV4_SRC)) || + hashtable_test(ip->h, nfct_get_attr(ct, ATTR_REPL_IPV4_DST))); +} + +int __ignore_pool_test_ipv6(struct ignore_pool *ip, struct nf_conntrack *ct) +{ + return (hashtable_test(ip->h, nfct_get_attr(ct, ATTR_ORIG_IPV6_SRC)) || + hashtable_test(ip->h, nfct_get_attr(ct, ATTR_ORIG_IPV6_DST)) || + hashtable_test(ip->h, nfct_get_attr(ct, ATTR_REPL_IPV6_SRC)) || + hashtable_test(ip->h, nfct_get_attr(ct, ATTR_REPL_IPV6_DST))); +} + +int ignore_pool_test(struct ignore_pool *ip, struct nf_conntrack *ct) +{ + int ret; + + switch(nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO)) { + case AF_INET: + ret = __ignore_pool_test_ipv4(ip, ct); + break; + case AF_INET6: + ret = __ignore_pool_test_ipv6(ip, ct); + break; + default: + dlog(STATE(log), "unknown conntrack layer 3 protocol?"); + break; + } + + return ret; +} diff --git a/daemon/src/local.c b/daemon/src/local.c new file mode 100644 index 0000000..eef70ad --- /dev/null +++ b/daemon/src/local.c @@ -0,0 +1,159 @@ +/* + * (C) 2006 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Description: UNIX sockets library + */ + +#include +#include +#include +#include +#include "debug.h" + +#include "local.h" + +int local_server_create(struct local_conf *conf) +{ + int fd; + int len; + struct sockaddr_un local; + + if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + debug("local_server_create:socket"); + return -1; + } + + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &conf->reuseaddr, + sizeof(conf->reuseaddr)) == -1) { + debug("local_server_create:setsockopt"); + close(fd); + return -1; + } + + local.sun_family = AF_UNIX; + strcpy(local.sun_path, conf->path); + len = strlen(local.sun_path) + sizeof(local.sun_family); + unlink(conf->path); + + if (bind(fd, (struct sockaddr *) &local, len) == -1) { + debug("local_server_create:bind"); + close(fd); + return -1; + } + + if (listen(fd, conf->backlog) == -1) { + close(fd); + debug("local_server_create:listen"); + return -1; + } + + return fd; +} + +void local_server_destroy(int fd) +{ + close(fd); +} + +int do_local_server_step(int fd, void *data, + void (*process)(int fd, void *data)) +{ + int rfd; + struct sockaddr_un local; + size_t sin_size = sizeof(struct sockaddr_un); + + if ((rfd = accept(fd, (struct sockaddr *)&local, &sin_size)) == -1) { + debug("do_local_server_step:accept"); + return -1; + } + + process(rfd, data); + close(rfd); + + return 0; +} + +int local_client_create(struct local_conf *conf) +{ + int len; + struct sockaddr_un local; + int fd; + + if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) + return -1; + + local.sun_family = AF_UNIX; + strcpy(local.sun_path, conf->path); + len = strlen(local.sun_path) + sizeof(local.sun_family); + + if (connect(fd, (struct sockaddr *) &local, len) == -1) { + close(fd); + debug("local_client_create: connect: "); + return -1; + } + + return fd; +} + +void local_client_destroy(int fd) +{ + close(fd); +} + +int do_local_client_step(int fd, void (*process)(char *buf)) +{ + int numbytes; + char buf[1024]; + + memset(buf, 0, sizeof(buf)); + while ((numbytes = recv(fd, buf, sizeof(buf)-1, 0)) > 0) { + buf[sizeof(buf)-1] = '\0'; + if (process) + process(buf); + memset(buf, 0, sizeof(buf)); + } + + return 0; +} + +void local_step(char *buf) +{ + printf(buf); +} + +int do_local_request(int request, + struct local_conf *conf, + void (*step)(char *buf)) +{ + int fd, ret; + + fd = local_client_create(conf); + if (fd == -1) + return -1; + + ret = send(fd, &request, sizeof(int), 0); + if (ret == -1) { + debug("send:"); + return -1; + } + + do_local_client_step(fd, step); + + local_client_destroy(fd); + + return 0; +} diff --git a/daemon/src/lock.c b/daemon/src/lock.c new file mode 100644 index 0000000..cd68baf --- /dev/null +++ b/daemon/src/lock.c @@ -0,0 +1,32 @@ +/* + * (C) 2006 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include + +static pthread_mutex_t global_lock = PTHREAD_MUTEX_INITIALIZER; + +void lock() +{ + pthread_mutex_lock(&global_lock); +} + +void unlock() +{ + pthread_mutex_unlock(&global_lock); +} diff --git a/daemon/src/log.c b/daemon/src/log.c new file mode 100644 index 0000000..88cadea --- /dev/null +++ b/daemon/src/log.c @@ -0,0 +1,57 @@ +/* + * (C) 2006 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Description: Logging support for the conntrack daemon + */ + +#include +#include +#include +#include + +FILE *init_log(char *filename) +{ + FILE *fd; + + fd = fopen(filename, "a+"); + if (fd == NULL) { + fprintf(stderr, "can't open log file `%s'\n", filename); + return NULL; + } + + return fd; +} + +void dlog(FILE *fd, char *format, ...) +{ + time_t t = time(NULL); + char *buf = ctime(&t); + va_list args; + + buf[strlen(buf)-1]='\0'; + va_start(args, format); + fprintf(fd, "[%s] (pid=%d) ", buf, getpid()); + vfprintf(fd, format, args); + va_end(args); + fprintf(fd, "\n"); + fflush(fd); +} + +void close_log(FILE *fd) +{ + fclose(fd); +} diff --git a/daemon/src/main.c b/daemon/src/main.c new file mode 100644 index 0000000..1c75970 --- /dev/null +++ b/daemon/src/main.c @@ -0,0 +1,302 @@ +/* + * (C) 2006-2007 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include "conntrackd.h" +#include "log.h" +#include +#include +#include +#include +#include +#include +#include "hash.h" +#include "jhash.h" + +struct ct_general_state st; +union ct_state state; + +static const char usage_daemon_commands[] = + "Daemon mode commands:\n" + " -d [options]\t\tRun in daemon mode\n" + " -S [options]\t\tRun in statistics mode\n"; + +static const char usage_client_commands[] = + "Client mode commands:\n" + " -c, commit external cache to conntrack table\n" + " -f, flush internal and external cache\n" + " -F, flush kernel conntrack table\n" + " -i, display content of the internal cache\n" + " -e, display the content of the external cache\n" + " -k, kill conntrack daemon\n" + " -s, dump statistics\n" + " -R, resync with kernel conntrack table\n" + " -n, request resync with other node (only NACK mode)\n" + " -x, dump cache in XML format (requires -i or -e)"; + +static const char usage_options[] = + "Options:\n" + " -C [configfile], configuration file path\n"; + +void show_usage(char *progname) +{ + fprintf(stdout, "Connection tracking userspace daemon v%s\n", VERSION); + fprintf(stdout, "Usage: %s [commands] [options]\n\n", progname); + fprintf(stdout, "%s\n", usage_daemon_commands); + fprintf(stdout, "%s\n", usage_client_commands); + fprintf(stdout, "%s\n", usage_options); +} + +/* These live in run.c */ +int init(int); +void run(void); + +void set_operation_mode(int *current, int want, char *argv[]) +{ + if (*current == NOT_SET) { + *current = want; + return; + } + if (*current != want) { + show_usage(argv[0]); + fprintf(stderr, "\nError: Invalid parameters\n"); + exit(EXIT_FAILURE); + } +} + +static int check_capabilities(void) +{ + int ret; + cap_user_header_t hcap; + cap_user_data_t dcap; + + hcap = malloc(sizeof(cap_user_header_t)); + if (!hcap) + return -1; + + hcap->version = _LINUX_CAPABILITY_VERSION; + hcap->pid = getpid(); + + dcap = malloc(sizeof(cap_user_data_t)); + if (!dcap) { + free(hcap); + return -1; + } + + if (capget(hcap, dcap) == -1) { + free(hcap); + free(dcap); + return -1; + } + + ret = dcap->permitted & (1 << CAP_NET_ADMIN); + + free(hcap); + free(dcap); + + return ret; +} + +int main(int argc, char *argv[]) +{ + int ret, i, config_set = 0, action; + char config_file[PATH_MAX]; + int type = 0, mode = 0; + struct utsname u; + int version, major, minor; + + /* Check kernel version: it must be >= 2.6.18 */ + if (uname(&u) == -1) { + fprintf(stderr, "Can't retrieve kernel version via uname()\n"); + exit(EXIT_FAILURE); + } + sscanf(u.release, "%d.%d.%d", &version, &major, &minor); + if (version < 2 && major < 6) { + fprintf(stderr, "Linux kernel version must be >= 2.6.18\n"); + exit(EXIT_FAILURE); + } + + if (major == 6 && minor < 18) { + fprintf(stderr, "Linux kernel version must be >= 2.6.18\n"); + exit(EXIT_FAILURE); + } + + ret = check_capabilities(); + switch (ret) { + case -1: + fprintf(stderr, "Can't get capabilities\n"); + exit(EXIT_FAILURE); + break; + case 0: + fprintf(stderr, "You require CAP_NET_ADMIN in order " + "to run conntrackd\n"); + exit(EXIT_FAILURE); + break; + default: + break; + } + + for (i=1; i= PATH_MAX){ + config_file[PATH_MAX-1]='\0'; + fprintf(stderr, "Path to config file " + "to long. Cutting it " + "down to %d characters", + PATH_MAX); + } + config_set = 1; + break; + } + show_usage(argv[0]); + fprintf(stderr, "Missing config filename\n"); + break; + case 'F': + set_operation_mode(&type, REQUEST, argv); + action = FLUSH_MASTER; + case 'f': + set_operation_mode(&type, REQUEST, argv); + action = FLUSH_CACHE; + break; + case 'R': + set_operation_mode(&type, REQUEST, argv); + action = RESYNC_MASTER; + break; + case 'B': + set_operation_mode(&type, REQUEST, argv); + action = SEND_BULK; + break; + case 'k': + set_operation_mode(&type, REQUEST, argv); + action = KILL; + break; + case 's': + set_operation_mode(&type, REQUEST, argv); + action = STATS; + break; + case 'S': + set_operation_mode(&mode, STATS_MODE, argv); + break; + case 'n': + set_operation_mode(&type, REQUEST, argv); + action = REQUEST_DUMP; + break; + case 'x': + if (action == DUMP_INTERNAL) + action = DUMP_INT_XML; + else if (action == DUMP_EXTERNAL) + action = DUMP_EXT_XML; + else { + show_usage(argv[0]); + fprintf(stderr, "Error: Invalid parameters\n"); + exit(EXIT_FAILURE); + + } + break; + default: + show_usage(argv[0]); + fprintf(stderr, "Unknown option: %s\n", argv[i]); + return 0; + break; + } + } + + if (config_set == 0) + strcpy(config_file, DEFAULT_CONFIGFILE); + + if ((ret = init_config(config_file)) == -1) { + fprintf(stderr, "can't open config file `%s'\n", config_file); + exit(EXIT_FAILURE); + } + + /* + * Setting up logfile + */ + STATE(log) = init_log(CONFIG(logfile)); + if (!STATE(log)) { + fprintf(stdout, "can't open logfile `%s\n'", CONFIG(logfile)); + exit(EXIT_FAILURE); + } + + if (type == REQUEST) { + if (do_local_request(action, &conf.local, local_step) == -1) + fprintf(stderr, "can't connect: is conntrackd " + "running? appropiate permissions?\n"); + exit(EXIT_SUCCESS); + } + + /* + * lock file + */ + if ((ret = open(CONFIG(lockfile), O_CREAT | O_EXCL | O_TRUNC)) == -1) { + fprintf(stderr, "lockfile `%s' exists, perhaps conntrackd " + "already running?\n", CONFIG(lockfile)); + exit(EXIT_FAILURE); + } + close(ret); + + /* Daemonize conntrackd */ + if (type == DAEMON) { + pid_t pid; + + if ((pid = fork()) == -1) { + dlog(STATE(log), "fork() failed: " + "%s", strerror(errno)); + exit(EXIT_FAILURE); + } else if (pid) + exit(EXIT_SUCCESS); + + dlog(STATE(log), "--- starting in daemon mode ---"); + } else + dlog(STATE(log), "--- starting in console mode ---"); + + /* + * initialization process + */ + + if (init(mode) == -1) { + close_log(STATE(log)); + fprintf(stderr, "ERROR: conntrackd cannot start, please " + "check the logfile for more info\n"); + unlink(CONFIG(lockfile)); + exit(EXIT_FAILURE); + } + + /* + * run main process + */ + run(); +} diff --git a/daemon/src/mcast.c b/daemon/src/mcast.c new file mode 100644 index 0000000..9904544 --- /dev/null +++ b/daemon/src/mcast.c @@ -0,0 +1,287 @@ +/* + * (C) 2006 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Description: multicast socket library + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mcast.h" +#include "debug.h" + +struct mcast_sock *mcast_server_create(struct mcast_conf *conf) +{ + int yes = 1; + union { + struct ip_mreq ipv4; + struct ipv6_mreq ipv6; + } mreq; + struct mcast_sock *m; + + m = (struct mcast_sock *) malloc(sizeof(struct mcast_sock)); + if (!m) + return NULL; + memset(m, 0, sizeof(struct mcast_sock)); + + switch(conf->ipproto) { + case AF_INET: + mreq.ipv4.imr_multiaddr.s_addr = conf->in.inet_addr.s_addr; + mreq.ipv4.imr_interface.s_addr =conf->ifa.interface_addr.s_addr; + + m->addr.ipv4.sin_family = AF_INET; + m->addr.ipv4.sin_port = htons(conf->port); + m->addr.ipv4.sin_addr.s_addr = htonl(INADDR_ANY); + break; + + case AF_INET6: + memcpy(&mreq.ipv6.ipv6mr_multiaddr, &conf->in.inet_addr6, + sizeof(u_int32_t) * 4); + memcpy(&mreq.ipv6.ipv6mr_interface, &conf->ifa.interface_addr6, + sizeof(u_int32_t) * 4); + + m->addr.ipv6.sin6_family = AF_INET6; + m->addr.ipv6.sin6_port = htons(conf->port); + m->addr.ipv6.sin6_addr = in6addr_any; + break; + } + + if ((m->fd = socket(conf->ipproto, SOCK_DGRAM, 0)) == -1) { + debug("mcast_sock_server_create:socket"); + free(m); + return NULL; + } + + if (setsockopt(m->fd, SOL_SOCKET, SO_REUSEADDR, &yes, + sizeof(int)) == -1) { + debug("mcast_sock_server_create:setsockopt1"); + close(m->fd); + free(m); + return NULL; + } + + if (bind(m->fd, (struct sockaddr *) &m->addr, + sizeof(struct sockaddr)) == -1) { + debug("mcast_sock_server_create:bind"); + close(m->fd); + free(m); + return NULL; + } + + + switch(conf->ipproto) { + case AF_INET: + if (setsockopt(m->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, + &mreq.ipv4, sizeof(mreq.ipv4)) < 0) { + debug("mcast_sock_server_create:setsockopt2"); + close(m->fd); + free(m); + return NULL; + } + break; + case AF_INET6: + if (setsockopt(m->fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, + &mreq.ipv6, sizeof(mreq.ipv6)) < 0) { + debug("mcast_sock_server_create:setsockopt2"); + close(m->fd); + free(m); + return NULL; + } + break; + } + + return m; +} + +void mcast_server_destroy(struct mcast_sock *m) +{ + close(m->fd); + free(m); +} + +static int +__mcast_client_create_ipv4(struct mcast_sock *m, struct mcast_conf *conf) +{ + int no = 0; + + m->addr.ipv4.sin_family = AF_INET; + m->addr.ipv4.sin_port = htons(conf->port); + m->addr.ipv4.sin_addr = conf->in.inet_addr; + + if (setsockopt(m->fd, IPPROTO_IP, IP_MULTICAST_LOOP, &no, + sizeof(int)) < 0) { + debug("mcast_sock_client_create:setsockopt2"); + close(m->fd); + return -1; + } + + if (setsockopt(m->fd, IPPROTO_IP, IP_MULTICAST_IF, + &conf->ifa.interface_addr, + sizeof(struct in_addr)) == -1) { + debug("mcast_sock_client_create:setsockopt3"); + close(m->fd); + free(m); + return -1; + } + + return 0; +} + +static int +__mcast_client_create_ipv6(struct mcast_sock *m, struct mcast_conf *conf) +{ + int no = 0; + + m->addr.ipv6.sin6_family = AF_INET6; + m->addr.ipv6.sin6_port = htons(conf->port); + memcpy(&m->addr.ipv6.sin6_addr, + &conf->in.inet_addr6, + sizeof(struct in6_addr)); + + if (setsockopt(m->fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &no, + sizeof(int)) < 0) { + debug("mcast_sock_client_create:setsockopt2"); + close(m->fd); + return -1; + } + + if (setsockopt(m->fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, + &conf->ifa.interface_addr, + sizeof(struct in_addr)) == -1) { + debug("mcast_sock_client_create:setsockopt3"); + close(m->fd); + free(m); + return -1; + } + + return 0; +} + +struct mcast_sock *mcast_client_create(struct mcast_conf *conf) +{ + int ret = 0; + struct sockaddr_in addr; + struct mcast_sock *m; + + m = (struct mcast_sock *) malloc(sizeof(struct mcast_sock)); + if (!m) + return NULL; + memset(m, 0, sizeof(struct mcast_sock)); + + if ((m->fd = socket(conf->ipproto, SOCK_DGRAM, 0)) == -1) { + debug("mcast_sock_client_create:socket"); + return NULL; + } + + switch(conf->ipproto) { + case AF_INET: + ret = __mcast_client_create_ipv4(m, conf); + break; + case AF_INET6: + ret = __mcast_client_create_ipv6(m, conf); + break; + default: + break; + } + + if (ret == -1) { + free(m); + m = NULL; + } + + return m; +} + +void mcast_client_destroy(struct mcast_sock *m) +{ + close(m->fd); + free(m); +} + +int mcast_send(struct mcast_sock *m, void *data, int size) +{ + int ret; + + ret = sendto(m->fd, + data, + size, + 0, + (struct sockaddr *) &m->addr, + sizeof(struct sockaddr)); + if (ret == -1) { + debug("mcast_sock_send"); + m->stats.error++; + return ret; + } + + m->stats.bytes += ret; + m->stats.messages++; + + return ret; +} + +int mcast_recv(struct mcast_sock *m, void *data, int size) +{ + int ret; + socklen_t sin_size = sizeof(struct sockaddr_in); + + ret = recvfrom(m->fd, + data, + size, + 0, + (struct sockaddr *)&m->addr, + &sin_size); + if (ret == -1) { + debug("mcast_sock_recv"); + m->stats.error++; + return ret; + } + + m->stats.bytes += ret; + m->stats.messages++; + + return ret; +} + +struct mcast_stats *mcast_get_stats(struct mcast_sock *m) +{ + return &m->stats; +} + +void mcast_dump_stats(int fd, struct mcast_sock *s, struct mcast_sock *r) +{ + char buf[512]; + int size; + + size = sprintf(buf, "multicast traffic:\n" + "%20llu Bytes sent " + "%20llu Bytes recv\n" + "%20llu Pckts sent " + "%20llu Pckts recv\n" + "%20llu Error send " + "%20llu Error recv\n\n", + s->stats.bytes, r->stats.bytes, + s->stats.messages, r->stats.messages, + s->stats.error, r->stats.error); + + send(fd, buf, size, 0); +} diff --git a/daemon/src/netlink.c b/daemon/src/netlink.c new file mode 100644 index 0000000..0bde632 --- /dev/null +++ b/daemon/src/netlink.c @@ -0,0 +1,326 @@ +/* + * (C) 2006 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "conntrackd.h" +#include +#include +#include +#include "us-conntrack.h" +#include +#include +#include "network.h" + +static int ignore_conntrack(struct nf_conntrack *ct) +{ + /* ignore a certain protocol */ + if (CONFIG(ignore_protocol)[nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO)]) + return 1; + + /* Accept DNAT'ed traffic: not really coming to the local machine */ + if ((CONFIG(flags) & STRIP_NAT) && + nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) { + debug_ct(ct, "DNAT"); + return 0; + } + + /* Accept SNAT'ed traffic: not really coming to the local machine */ + if ((CONFIG(flags) & STRIP_NAT) && + nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) { + debug_ct(ct, "SNAT"); + return 0; + } + + /* Ignore traffic */ + if (ignore_pool_test(STATE(ignore_pool), ct)) { + debug_ct(ct, "ignore traffic"); + return 1; + } + + return 0; +} + +static int nl_event_handler(struct nlmsghdr *nlh, + struct nfattr *nfa[], + void *data) +{ + char tmp[1024]; + struct nf_conntrack *ct = (struct nf_conntrack *) tmp; + int type; + + memset(tmp, 0, sizeof(tmp)); + + if ((type = nfct_parse_conntrack(NFCT_T_ALL, nlh, ct)) == NFCT_T_ERROR) + return NFCT_CB_STOP; + + /* + * Ignore this conntrack: it talks about a + * connection that is not interesting for us. + */ + if (ignore_conntrack(ct)) + return NFCT_CB_STOP; + + switch(type) { + case NFCT_T_NEW: + STATE(mode)->event_new(ct, nlh); + break; + case NFCT_T_UPDATE: + STATE(mode)->event_upd(ct, nlh); + break; + case NFCT_T_DESTROY: + if (STATE(mode)->event_dst(ct, nlh)) + update_traffic_stats(ct); + break; + default: + dlog(STATE(log), "received unknown msg from ctnetlink\n"); + break; + } + + return NFCT_CB_STOP; +} + +int nl_init_event_handler(void) +{ + struct nfnl_callback cb_events = { + .call = nl_event_handler, + .attr_count = CTA_MAX + }; + + /* open event netlink socket */ + STATE(event) = nfnl_open(); + if (!STATE(event)) + return -1; + + /* set up socket buffer size */ + if (CONFIG(netlink_buffer_size)) + nfnl_rcvbufsiz(STATE(event), CONFIG(netlink_buffer_size)); + else { + socklen_t socklen = sizeof(unsigned int); + unsigned int read_size; + + /* get current buffer size */ + getsockopt(nfnl_fd(STATE(event)), SOL_SOCKET, + SO_RCVBUF, &read_size, &socklen); + + CONFIG(netlink_buffer_size) = read_size; + } + + /* ensure that maximum grown size is >= than maximum size */ + if (CONFIG(netlink_buffer_size_max_grown) < CONFIG(netlink_buffer_size)) + CONFIG(netlink_buffer_size_max_grown) = + CONFIG(netlink_buffer_size); + + /* open event subsystem */ + STATE(subsys_event) = nfnl_subsys_open(STATE(event), + NFNL_SUBSYS_CTNETLINK, + IPCTNL_MSG_MAX, + NFCT_ALL_CT_GROUPS); + if (STATE(subsys_event) == NULL) + return -1; + + /* register callback for new and update events */ + nfnl_callback_register(STATE(subsys_event), + IPCTNL_MSG_CT_NEW, + &cb_events); + + /* register callback for delete events */ + nfnl_callback_register(STATE(subsys_event), + IPCTNL_MSG_CT_DELETE, + &cb_events); + + return 0; +} + +static int nl_dump_handler(struct nlmsghdr *nlh, + struct nfattr *nfa[], + void *data) +{ + char buf[1024]; + struct nf_conntrack *ct = (struct nf_conntrack *) buf; + int type; + + memset(buf, 0, sizeof(buf)); + + if ((type = nfct_parse_conntrack(NFCT_T_ALL, nlh, ct)) == NFCT_T_ERROR) + return NFCT_CB_CONTINUE; + + /* + * Ignore this conntrack: it talks about a + * connection that is not interesting for us. + */ + if (ignore_conntrack(ct)) + return NFCT_CB_CONTINUE; + + switch(type) { + case NFCT_T_UPDATE: + STATE(mode)->dump(ct, nlh); + break; + default: + dlog(STATE(log), "received unknown msg from ctnetlink"); + break; + } + return NFCT_CB_CONTINUE; +} + +int nl_init_dump_handler(void) +{ + struct nfnl_callback cb_dump = { + .call = nl_dump_handler, + .attr_count = CTA_MAX + }; + + /* open dump netlink socket */ + STATE(dump) = nfnl_open(); + if (!STATE(dump)) + return -1; + + /* open dump subsystem */ + STATE(subsys_dump) = nfnl_subsys_open(STATE(dump), + NFNL_SUBSYS_CTNETLINK, + IPCTNL_MSG_MAX, + 0); + if (STATE(subsys_dump) == NULL) + return -1; + + /* register callback for dumped entries */ + nfnl_callback_register(STATE(subsys_dump), + IPCTNL_MSG_CT_NEW, + &cb_dump); + + if (nl_dump_conntrack_table(STATE(dump), STATE(subsys_dump)) == -1) + return -1; + + return 0; +} + +static int nl_overrun_handler(struct nlmsghdr *nlh, + struct nfattr *nfa[], + void *data) +{ + char buf[1024]; + struct nf_conntrack *ct = (struct nf_conntrack *) buf; + int type; + + memset(buf, 0, sizeof(buf)); + + if ((type = nfct_parse_conntrack(NFCT_T_ALL, nlh, ct)) == NFCT_T_ERROR) + return NFCT_CB_CONTINUE; + + /* + * Ignore this conntrack: it talks about a + * connection that is not interesting for us. + */ + if (ignore_conntrack(ct)) + return NFCT_CB_CONTINUE; + + switch(type) { + case NFCT_T_UPDATE: + if (STATE(mode)->overrun) + STATE(mode)->overrun(ct, nlh); + break; + default: + dlog(STATE(log), "received unknown msg from ctnetlink"); + break; + } + return NFCT_CB_CONTINUE; +} + +int nl_init_overrun_handler(void) +{ + struct nfnl_callback cb_sync = { + .call = nl_overrun_handler, + .attr_count = CTA_MAX + }; + + /* open sync netlink socket */ + STATE(sync) = nfnl_open(); + if (!STATE(sync)) + return -1; + + /* open synchronizer subsystem */ + STATE(subsys_sync) = nfnl_subsys_open(STATE(sync), + NFNL_SUBSYS_CTNETLINK, + IPCTNL_MSG_MAX, + 0); + if (STATE(subsys_sync) == NULL) + return -1; + + /* register callback for dumped entries */ + nfnl_callback_register(STATE(subsys_sync), + IPCTNL_MSG_CT_NEW, + &cb_sync); + + return 0; +} + +static int warned = 0; + +void nl_resize_socket_buffer(struct nfnl_handle *h) +{ + unsigned int s = CONFIG(netlink_buffer_size) * 2; + + /* already warned that we have reached the maximum buffer size */ + if (warned) + return; + + if (s > CONFIG(netlink_buffer_size_max_grown)) { + dlog(STATE(log), "maximum netlink socket buffer size reached"); + s = CONFIG(netlink_buffer_size_max_grown); + warned = 1; + } + + CONFIG(netlink_buffer_size) = nfnl_rcvbufsiz(h, s); + + /* notify the sysadmin */ + dlog(STATE(log), "netlink socket buffer size has been set to %u bytes", + CONFIG(netlink_buffer_size)); +} + +int nl_dump_conntrack_table(struct nfnl_handle *h, + struct nfnl_subsys_handle *subsys) +{ + struct nfnlhdr req; + + memset(&req, 0, sizeof(req)); + nfct_build_query(subsys, + NFCT_Q_DUMP, + &CONFIG(family), + &req, + sizeof(req)); + + if (nfnl_query(h, &req.nlh) == -1) + return -1; + + return 0; +} + +int nl_flush_master_conntrack_table(void) +{ + struct nfnlhdr req; + + memset(&req, 0, sizeof(req)); + nfct_build_query(STATE(subsys_sync), + NFCT_Q_FLUSH, + &CONFIG(family), + &req, + sizeof(req)); + + if (nfnl_query(STATE(sync), &req.nlh) == -1) + return -1; + + return 0; +} diff --git a/daemon/src/network.c b/daemon/src/network.c new file mode 100644 index 0000000..b9be318 --- /dev/null +++ b/daemon/src/network.c @@ -0,0 +1,282 @@ +/* + * (C) 2006-2007 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "conntrackd.h" +#include "network.h" + +#if 0 +#define _TEST_DROP +#else +#undef _TEST_DROP +#endif + +static int drop = 0; /* debugging purposes */ +static unsigned int seq_set, cur_seq; + +static int send_netmsg(struct mcast_sock *m, void *data, unsigned int len) +{ + struct nlnetwork *net = data; + +#ifdef _TEST_DROP + if (++drop > 10) { + drop = 0; + printf("dropping resend (seq=%u)\n", ntohl(net->seq)); + return 0; + } +#endif + return mcast_send(m, net, len); +} + +int mcast_send_netmsg(struct mcast_sock *m, void *data) +{ + struct nlmsghdr *nlh = data + sizeof(struct nlnetwork); + unsigned int len = nlh->nlmsg_len + sizeof(struct nlnetwork); + struct nlnetwork *net = data; + + if (!seq_set) { + seq_set = 1; + cur_seq = time(NULL); + net->flags |= NET_HELLO; + } + + net->flags = htons(net->flags); + net->seq = htonl(cur_seq++); + + if (nlh_host2network(nlh) == -1) + return -1; + + net->checksum = 0; + net->checksum = ntohs(do_csum(data, len)); + + return send_netmsg(m, data, len); +} + +int mcast_resend_netmsg(struct mcast_sock *m, void *data) +{ + struct nlnetwork *net = data; + struct nlmsghdr *nlh = data + sizeof(struct nlnetwork); + unsigned int len = htonl(nlh->nlmsg_len) + sizeof(struct nlnetwork); + + net->flags = ntohs(net->flags); + + if (!seq_set) { + seq_set = 1; + cur_seq = time(NULL); + net->flags |= NET_HELLO; + } + + if (net->flags & NET_NACK || net->flags & NET_ACK) { + struct nlnetwork_ack *nack = (struct nlnetwork_ack *) net; + len = sizeof(struct nlnetwork_ack); + } + + net->flags = htons(net->flags); + net->seq = htonl(cur_seq++); + net->checksum = 0; + net->checksum = ntohs(do_csum(data, len)); + + return send_netmsg(m, data, len); +} + +int mcast_send_error(struct mcast_sock *m, void *data) +{ + struct nlnetwork *net = data; + unsigned int len = sizeof(struct nlnetwork); + + if (!seq_set) { + seq_set = 1; + cur_seq = time(NULL); + net->flags |= NET_HELLO; + } + + if (net->flags & NET_NACK || net->flags & NET_ACK) { + struct nlnetwork_ack *nack = (struct nlnetwork_ack *) net; + nack->from = htonl(nack->from); + nack->to = htonl(nack->to); + len = sizeof(struct nlnetwork_ack); + } + + net->flags = htons(net->flags); + net->seq = htonl(cur_seq++); + net->checksum = 0; + net->checksum = ntohs(do_csum(data, len)); + + return send_netmsg(m, data, len); +} + +static int valid_checksum(void *data, unsigned int len) +{ + struct nlnetwork *net = data; + unsigned short checksum, tmp; + + checksum = ntohs(net->checksum); + + /* no checksum, skip */ + if (!checksum) + return 1; + + net->checksum = 0; + tmp = do_csum(data, len); + + return tmp == checksum; +} + +int mcast_recv_netmsg(struct mcast_sock *m, void *data, int len) +{ + int ret; + struct nlnetwork *net = data; + struct nlmsghdr *nlh = data + sizeof(struct nlnetwork); + struct nfgenmsg *nfhdr; + + ret = mcast_recv(m, net, len); + if (ret <= 0) + return ret; + + if (ret < sizeof(struct nlnetwork)) + return -1; + + if (!valid_checksum(data, ret)) + return -1; + + net->flags = ntohs(net->flags); + net->seq = ntohl(net->seq); + + if (net->flags & NET_HELLO) + STATE_SYNC(last_seq_recv) = net->seq-1; + + if (net->flags & NET_NACK || net->flags & NET_ACK) { + struct nlnetwork_ack *nack = (struct nlnetwork_ack *) net; + + if (ret < sizeof(struct nlnetwork_ack)) + return -1; + + nack->from = ntohl(nack->from); + nack->to = ntohl(nack->to); + + return ret; + } + + if (net->flags & NET_RESYNC) + return ret; + + /* information received is too small */ + if (ret < NLMSG_SPACE(sizeof(struct nfgenmsg))) + return -1; + + /* information received and message length does not match */ + if (ret != ntohl(nlh->nlmsg_len) + sizeof(struct nlnetwork)) + return -1; + + /* this message does not come from ctnetlink */ + if (NFNL_SUBSYS_ID(ntohs(nlh->nlmsg_type)) != NFNL_SUBSYS_CTNETLINK) + return -1; + + nfhdr = NLMSG_DATA(nlh); + + /* only AF_INET and AF_INET6 are supported */ + if (nfhdr->nfgen_family != AF_INET && + nfhdr->nfgen_family != AF_INET6) + return -1; + + /* only process message coming from nfnetlink v0 */ + if (nfhdr->version != NFNETLINK_V0) + return -1; + + if (nlh_network2host(nlh) == -1) + return -1; + + return ret; +} + +int mcast_track_seq(u_int32_t seq, u_int32_t *exp_seq) +{ + static int seq_set = 0; + int ret = 1; + + /* netlink sequence tracking initialization */ + if (!seq_set) { + seq_set = 1; + goto out; + } + + /* fast path: we received the correct sequence */ + if (seq == STATE_SYNC(last_seq_recv)+1) + goto out; + + /* out of sequence: some messages got lost */ + if (seq > STATE_SYNC(last_seq_recv)+1) { + STATE_SYNC(packets_lost) += seq-STATE_SYNC(last_seq_recv)+1; + ret = 0; + goto out; + } + + /* out of sequence: replayed or sequence wrapped around issues */ + if (seq < STATE_SYNC(last_seq_recv)+1) { + /* + * Check if the sequence has wrapped around. + * Perhaps it can be a replayed packet. + */ + if (STATE_SYNC(last_seq_recv)+1-seq > ~0U/2) { + /* + * Indeed, it is a wrapped around + */ + STATE_SYNC(packets_lost) += + ~0U-STATE_SYNC(last_seq_recv)+1+seq; + } else { + /* + * It is a delayed packet + */ + dlog(STATE(log), "delayed packet? exp=%u rcv=%u", + STATE_SYNC(last_seq_recv)+1, seq); + } + ret = 0; + } + +out: + *exp_seq = STATE_SYNC(last_seq_recv)+1; + /* update expected sequence */ + STATE_SYNC(last_seq_recv) = seq; + + return ret; +} + +int build_network_msg(const int msg_type, + struct nfnl_subsys_handle *ssh, + struct nf_conntrack *ct, + void *buffer, + unsigned int size) +{ + memset(buffer, 0, size); + buffer += sizeof(struct nlnetwork); + return nfct_build_query(ssh, msg_type, ct, buffer, size); +} + +unsigned int parse_network_msg(struct nf_conntrack *ct, + const struct nlmsghdr *nlh) +{ + /* + * The parsing of netlink messages going through network is + * similar to the one that is done for messages coming from + * kernel, therefore do not replicate more code and use the + * function provided in the libraries. + * + * Yup, this is a hack 8) + */ + return nfct_parse_conntrack(NFCT_T_ALL, nlh, ct); +} + diff --git a/daemon/src/proxy.c b/daemon/src/proxy.c new file mode 100644 index 0000000..b9bb04e --- /dev/null +++ b/daemon/src/proxy.c @@ -0,0 +1,124 @@ +/* + * (C) 2006 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include + +#if 0 +#define dprintf printf +#else +#define dprintf +#endif + +int nlh_payload_host2network(struct nfattr *nfa, int len) +{ + struct nfattr *__nfa; + + while (NFA_OK(nfa, len)) { + + dprintf("type=%d nfalen=%d len=%d [%s]\n", + nfa->nfa_type & 0x7fff, + nfa->nfa_len, len, + nfa->nfa_type & NFNL_NFA_NEST ? "NEST":""); + + if (nfa->nfa_type & NFNL_NFA_NEST) { + if (NFA_PAYLOAD(nfa) > len) + return -1; + + if (nlh_payload_host2network(NFA_DATA(nfa), + NFA_PAYLOAD(nfa)) == -1) + return -1; + } + + __nfa = NFA_NEXT(nfa, len); + + nfa->nfa_type = htons(nfa->nfa_type); + nfa->nfa_len = htons(nfa->nfa_len); + + nfa = __nfa; + } + return 0; +} + +int nlh_host2network(struct nlmsghdr *nlh) +{ + struct nfgenmsg *nfhdr = NLMSG_DATA(nlh); + struct nfattr *cda[CTA_MAX]; + unsigned int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg)); + unsigned int len = nlh->nlmsg_len - NLMSG_ALIGN(min_len); + + nlh->nlmsg_len = htonl(nlh->nlmsg_len); + nlh->nlmsg_type = htons(nlh->nlmsg_type); + nlh->nlmsg_flags = htons(nlh->nlmsg_flags); + nlh->nlmsg_seq = htonl(nlh->nlmsg_seq); + nlh->nlmsg_pid = htonl(nlh->nlmsg_pid); + + nfhdr->res_id = htons(nfhdr->res_id); + + return nlh_payload_host2network(NFM_NFA(NLMSG_DATA(nlh)), len); +} + +int nlh_payload_network2host(struct nfattr *nfa, int len) +{ + nfa->nfa_type = ntohs(nfa->nfa_type); + nfa->nfa_len = ntohs(nfa->nfa_len); + + while(NFA_OK(nfa, len)) { + + dprintf("type=%d nfalen=%d len=%d [%s]\n", + nfa->nfa_type & 0x7fff, + nfa->nfa_len, len, + nfa->nfa_type & NFNL_NFA_NEST ? "NEST":""); + + if (nfa->nfa_type & NFNL_NFA_NEST) { + if (NFA_PAYLOAD(nfa) > len) + return -1; + + if (nlh_payload_network2host(NFA_DATA(nfa), + NFA_PAYLOAD(nfa)) == -1) + return -1; + } + + nfa = NFA_NEXT(nfa,len); + + if (len < NFA_LENGTH(0)) + break; + + nfa->nfa_type = ntohs(nfa->nfa_type); + nfa->nfa_len = ntohs(nfa->nfa_len); + } + return 0; +} + +int nlh_network2host(struct nlmsghdr *nlh) +{ + struct nfgenmsg *nfhdr = NLMSG_DATA(nlh); + struct nfattr *cda[CTA_MAX]; + unsigned int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg)); + unsigned int len = ntohl(nlh->nlmsg_len) - NLMSG_ALIGN(min_len); + + nlh->nlmsg_len = ntohl(nlh->nlmsg_len); + nlh->nlmsg_type = ntohs(nlh->nlmsg_type); + nlh->nlmsg_flags = ntohs(nlh->nlmsg_flags); + nlh->nlmsg_seq = ntohl(nlh->nlmsg_seq); + nlh->nlmsg_pid = ntohl(nlh->nlmsg_pid); + + nfhdr->res_id = ntohs(nfhdr->res_id); + + return nlh_payload_network2host(NFM_NFA(NLMSG_DATA(nlh)), len); +} diff --git a/daemon/src/read_config_lex.l b/daemon/src/read_config_lex.l new file mode 100644 index 0000000..dee90c9 --- /dev/null +++ b/daemon/src/read_config_lex.l @@ -0,0 +1,125 @@ +%{ +/* + * (C) 2006 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Description: configuration file syntax + */ + +#include "read_config_yy.h" +#include "conntrackd.h" +%} + +%option yylineno +%option nounput + +ws [ \t]+ +comment #.*$ +nl [\n\r] + +is_on [o|O][n|N] +is_off [o|O][f|F][f|F] +integer [0-9]+ +path \/[^\"\n ]* +ip4_end [0-9]*[0-9]+ +ip4_part [0-2]*{ip4_end} +ip4 {ip4_part}\.{ip4_part}\.{ip4_part}\.{ip4_part} +hex_255 [0-9a-fA-F]{1,4} +ip6_part {hex_255}":"? +ip6_form1 {ip6_part}{0,16}"::"{ip6_part}{0,16} +ip6_form2 ({hex_255}":"){16}{hex_255} +ip6 {ip6_form1}|{ip6_form2} +string [a-zA-Z]* +persistent [P|p][E|e][R|r][S|s][I|i][S|s][T|t][E|e][N|n][T|T] +nack [N|n][A|a][C|c][K|k] + +%% +"UNIX" { return T_UNIX; } +"IPv4_address" { return T_IPV4_ADDR; } +"IPv6_address" { return T_IPV6_ADDR; } +"IPv4_interface" { return T_IPV4_IFACE; } +"IPv6_interface" { return T_IPV6_IFACE; } +"Port" { return T_PORT; } +"Multicast" { return T_MULTICAST; } +"HashSize" { return T_HASHSIZE; } +"RefreshTime" { return T_REFRESH; } +"CacheTimeout" { return T_EXPIRE; } +"CommitTimeout" { return T_TIMEOUT; } +"DelayDestroyMessages" { return T_DELAY; } +"HashLimit" { return T_HASHLIMIT; } +"Path" { return T_PATH; } +"IgnoreProtocol" { return T_IGNORE_PROTOCOL; } +"UDP" { return T_UDP; } +"ICMP" { return T_ICMP; } +"VRRP" { return T_VRRP; } +"IGMP" { return T_IGMP; } +"TCP" { return T_TCP; } +"IgnoreTrafficFor" { return T_IGNORE_TRAFFIC; } +"StripNAT" { return T_STRIP_NAT; } +"Backlog" { return T_BACKLOG; } +"Group" { return T_GROUP; } +"LogFile" { return T_LOG; } +"LockFile" { return T_LOCK; } +"General" { return T_GENERAL; } +"Sync" { return T_SYNC; } +"Stats" { return T_STATS; } +"RelaxTransitions" { return T_RELAX_TRANSITIONS; } +"SocketBufferSize" { return T_BUFFER_SIZE; } +"SocketBufferSizeMaxGrown" { return T_BUFFER_SIZE_MAX_GROWN; } +"SocketBufferSizeMaxGrowth" { return T_BUFFER_SIZE_MAX_GROWN; } +"Mode" { return T_SYNC_MODE; } +"ListenTo" { return T_LISTEN_TO; } +"Family" { return T_FAMILY; } +"ResendBufferSize" { return T_RESEND_BUFFER_SIZE; } +"Checksum" { return T_CHECKSUM; } +"ACKWindowSize" { return T_WINDOWSIZE; } +"Replicate" { return T_REPLICATE; } +"for" { return T_FOR; } +"SYN_SENT" { return T_SYN_SENT; } +"SYN_RECV" { return T_SYN_RECV; } +"ESTABLISHED" { return T_ESTABLISHED; } +"FIN_WAIT" { return T_FIN_WAIT; } +"CLOSE_WAIT" { return T_CLOSE_WAIT; } +"LAST_ACK" { return T_LAST_ACK; } +"TIME_WAIT" { return T_TIME_WAIT; } +"CLOSE" { return T_CLOSE; } +"LISTEN" { return T_LISTEN; } + +{is_on} { return T_ON; } +{is_off} { return T_OFF; } +{integer} { yylval.val = atoi(yytext); return T_NUMBER; } +{ip4} { yylval.string = strdup(yytext); return T_IP; } +{ip6} { yylval.string = strdup(yytext); return T_IP; } +{path} { yylval.string = strdup(yytext); return T_PATH_VAL; } +{persistent} { return T_PERSISTENT; } +{nack} { return T_NACK; } +{string} { yylval.string = strdup(yytext); return T_STRING; } + +{comment} ; +{ws} ; +{nl} ; + +<> { yyterminate(); } + +. { return yytext[0]; } + +%% + +int +yywrap() +{ + return 1; +} diff --git a/daemon/src/read_config_yy.y b/daemon/src/read_config_yy.y new file mode 100644 index 0000000..1668919 --- /dev/null +++ b/daemon/src/read_config_yy.y @@ -0,0 +1,550 @@ +%{ +/* + * (C) 2006 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Description: configuration file abstract grammar + */ + +#include +#include +#include +#include +#include "conntrackd.h" +#include "ignore.h" + +extern char *yytext; +extern int yylineno; + +struct ct_conf conf; +%} + +%union { + int val; + char *string; +} + +%token T_IPV4_ADDR T_IPV4_IFACE T_PORT T_HASHSIZE T_HASHLIMIT T_MULTICAST +%token T_PATH T_UNIX T_REFRESH T_IPV6_ADDR T_IPV6_IFACE +%token T_IGNORE_UDP T_IGNORE_ICMP T_IGNORE_TRAFFIC T_BACKLOG T_GROUP +%token T_LOG T_UDP T_ICMP T_IGMP T_VRRP T_TCP T_IGNORE_PROTOCOL +%token T_LOCK T_STRIP_NAT T_BUFFER_SIZE_MAX_GROWN T_EXPIRE T_TIMEOUT +%token T_GENERAL T_SYNC T_STATS T_RELAX_TRANSITIONS T_BUFFER_SIZE T_DELAY +%token T_SYNC_MODE T_LISTEN_TO T_FAMILY T_RESEND_BUFFER_SIZE +%token T_PERSISTENT T_NACK T_CHECKSUM T_WINDOWSIZE T_ON T_OFF +%token T_REPLICATE T_FOR +%token T_ESTABLISHED T_SYN_SENT T_SYN_RECV T_FIN_WAIT +%token T_CLOSE_WAIT T_LAST_ACK T_TIME_WAIT T_CLOSE T_LISTEN + + +%token T_IP T_PATH_VAL +%token T_NUMBER +%token T_STRING + +%% + +configfile : + | lines + ; + +lines : line + | lines line + ; + +line : ignore_protocol + | ignore_traffic + | strip_nat + | general + | sync + | stats + ; + +log : T_LOG T_PATH_VAL +{ + strncpy(conf.logfile, $2, FILENAME_MAXLEN); +}; + +lock : T_LOCK T_PATH_VAL +{ + strncpy(conf.lockfile, $2, FILENAME_MAXLEN); +}; + +strip_nat: T_STRIP_NAT +{ + conf.flags |= STRIP_NAT; +}; + +refreshtime : T_REFRESH T_NUMBER +{ + conf.refresh = $2; +}; + +expiretime: T_EXPIRE T_NUMBER +{ + conf.cache_timeout = $2; +}; + +timeout: T_TIMEOUT T_NUMBER +{ + conf.commit_timeout = $2; +}; + +checksum: T_CHECKSUM T_ON +{ +}; + +checksum: T_CHECKSUM T_OFF +{ + conf.flags |= DONT_CHECKSUM; +}; + +ignore_traffic : T_IGNORE_TRAFFIC '{' ignore_traffic_options '}'; + +ignore_traffic_options : + | ignore_traffic_options ignore_traffic_option; + +ignore_traffic_option : T_IPV4_ADDR T_IP +{ + union inet_address ip; + int family = 0; + + memset(&ip, 0, sizeof(union inet_address)); + + if (inet_aton($2, &ip.ipv4)) + family = AF_INET; +#ifdef HAVE_INET_PTON_IPV6 + else if (inet_pton(AF_INET6, $2, &ip.ipv6) > 0) + family = AF_INET6; +#endif + + if (!family) { + fprintf(stdout, "%s is not a valid IP, ignoring", $2); + return; + } + + if (!STATE(ignore_pool)) { + STATE(ignore_pool) = ignore_pool_create(family); + if (!STATE(ignore_pool)) { + fprintf(stdout, "Can't create ignore pool!\n"); + exit(EXIT_FAILURE); + } + } + + if (!ignore_pool_add(STATE(ignore_pool), &ip)) { + if (errno == EEXIST) + fprintf(stdout, "IP %s is repeated " + "in the ignore pool\n", $2); + if (errno == ENOSPC) + fprintf(stdout, "Too many IP in the ignore pool!\n"); + } +}; + +multicast_line : T_MULTICAST '{' multicast_options '}'; + +multicast_options : + | multicast_options multicast_option; + +multicast_option : T_IPV4_ADDR T_IP +{ + if (!inet_aton($2, &conf.mcast.in)) { + fprintf(stderr, "%s is not a valid IPv4 address\n"); + return; + } + + if (conf.mcast.ipproto == AF_INET6) { + fprintf(stderr, "Your multicast address is IPv4 but " + "is binded to an IPv6 interface? Surely " + "this is not what you want\n"); + return; + } + + conf.mcast.ipproto = AF_INET; +}; + +multicast_option : T_IPV6_ADDR T_IP +{ +#ifdef HAVE_INET_PTON_IPV6 + if (inet_pton(AF_INET6, $2, &conf.mcast.in) <= 0) + fprintf(stderr, "%s is not a valid IPv6 address\n", $2); +#endif + + if (conf.mcast.ipproto == AF_INET) { + fprintf(stderr, "Your multicast address is IPv6 but " + "is binded to an IPv4 interface? Surely " + "this is not what you want\n"); + return; + } + + conf.mcast.ipproto = AF_INET6; +}; + +multicast_option : T_IPV4_IFACE T_IP +{ + if (!inet_aton($2, &conf.mcast.ifa)) { + fprintf(stderr, "%s is not a valid IPv4 address\n"); + return; + } + + if (conf.mcast.ipproto == AF_INET6) { + fprintf(stderr, "Your multicast interface is IPv4 but " + "is binded to an IPv6 interface? Surely " + "this is not what you want\n"); + return; + } + + conf.mcast.ipproto = AF_INET; +}; + +multicast_option : T_IPV6_IFACE T_IP +{ +#ifdef HAVE_INET_PTON_IPV6 + if (inet_pton(AF_INET6, $2, &conf.mcast.ifa) <= 0) + fprintf(stderr, "%s is not a valid IPv6 address\n", $2); +#endif + + if (conf.mcast.ipproto == AF_INET) { + fprintf(stderr, "Your multicast interface is IPv6 but " + "is binded to an IPv4 interface? Surely " + "this is not what you want\n"); + return; + } + + conf.mcast.ipproto = AF_INET6; +}; + +multicast_option : T_BACKLOG T_NUMBER +{ + conf.mcast.backlog = $2; +}; + +multicast_option : T_GROUP T_NUMBER +{ + conf.mcast.port = $2; +}; + +hashsize : T_HASHSIZE T_NUMBER +{ + conf.hashsize = $2; +}; + +hashlimit: T_HASHLIMIT T_NUMBER +{ + conf.limit = $2; +}; + +unix_line: T_UNIX '{' unix_options '}'; + +unix_options: + | unix_options unix_option + ; + +unix_option : T_PATH T_PATH_VAL +{ + strcpy(conf.local.path, $2); +}; + +unix_option : T_BACKLOG T_NUMBER +{ + conf.local.backlog = $2; +}; + +ignore_protocol: T_IGNORE_PROTOCOL '{' ignore_proto_list '}'; + +ignore_proto_list: + | ignore_proto_list ignore_proto + ; + +ignore_proto: T_NUMBER +{ + if ($1 < IPPROTO_MAX) + conf.ignore_protocol[$1] = 1; + else + fprintf(stdout, "Protocol number `%d' is freak\n", $1); +}; + +ignore_proto: T_UDP +{ + conf.ignore_protocol[IPPROTO_UDP] = 1; +}; + +ignore_proto: T_ICMP +{ + conf.ignore_protocol[IPPROTO_ICMP] = 1; +}; + +ignore_proto: T_VRRP +{ + conf.ignore_protocol[IPPROTO_VRRP] = 1; +}; + +ignore_proto: T_IGMP +{ + conf.ignore_protocol[IPPROTO_IGMP] = 1; +}; + +sync: T_SYNC '{' sync_list '}'; + +sync_list: + | sync_list sync_line; + +sync_line: refreshtime + | expiretime + | timeout + | checksum + | multicast_line + | relax_transitions + | delay_destroy_msgs + | sync_mode_persistent + | sync_mode_nack + | listen_to + | state_replication + ; + +sync_mode_persistent: T_SYNC_MODE T_PERSISTENT '{' sync_mode_persistent_list '}' +{ + conf.flags |= SYNC_MODE_PERSISTENT; +}; + +sync_mode_nack: T_SYNC_MODE T_NACK '{' sync_mode_nack_list '}' +{ + conf.flags |= SYNC_MODE_NACK; +}; + +sync_mode_persistent_list: + | sync_mode_persistent_list sync_mode_persistent_line; + +sync_mode_persistent_line: refreshtime + | expiretime + | timeout + | relax_transitions + | delay_destroy_msgs + ; + +sync_mode_nack_list: + | sync_mode_nack_list sync_mode_nack_line; + +sync_mode_nack_line: resend_buffer_size + | timeout + | window_size + ; + +resend_buffer_size: T_RESEND_BUFFER_SIZE T_NUMBER +{ + conf.resend_buffer_size = $2; +}; + +window_size: T_WINDOWSIZE T_NUMBER +{ + conf.window_size = $2; +}; + +relax_transitions: T_RELAX_TRANSITIONS +{ + conf.flags |= RELAX_TRANSITIONS; +}; + +delay_destroy_msgs: T_DELAY +{ + conf.flags |= DELAY_DESTROY_MSG; +}; + +listen_to: T_LISTEN_TO T_IP +{ + union inet_address addr; + +#ifdef HAVE_INET_PTON_IPV6 + if (inet_pton(AF_INET6, $2, &addr.ipv6) <= 0) +#endif + if (inet_aton($2, &addr.ipv4) <= 0) { + fprintf(stderr, "%s is not a valid IP address\n", $2); + exit(EXIT_FAILURE); + } + + if (CONFIG(listen_to_len) == 0 || CONFIG(listen_to_len) % 16) { + CONFIG(listen_to) = realloc(CONFIG(listen_to), + sizeof(union inet_address) * + (CONFIG(listen_to_len) + 16)); + if (CONFIG(listen_to) == NULL) { + fprintf(stderr, "cannot init listen_to array\n"); + exit(EXIT_FAILURE); + } + + memset(CONFIG(listen_to) + + (CONFIG(listen_to_len) * sizeof(union inet_address)), + 0, sizeof(union inet_address) * 16); + + } +}; + +state_replication: T_REPLICATE states T_FOR state_proto; + +states: + | states state; + +state_proto: T_TCP; +state: tcp_state; + +tcp_state: T_SYN_SENT +{ + extern struct state_replication_helper tcp_state_helper; + state_helper_register(&tcp_state_helper, TCP_CONNTRACK_SYN_SENT); +}; +tcp_state: T_SYN_RECV +{ + extern struct state_replication_helper tcp_state_helper; + state_helper_register(&tcp_state_helper, TCP_CONNTRACK_SYN_RECV); +}; +tcp_state: T_ESTABLISHED +{ + extern struct state_replication_helper tcp_state_helper; + state_helper_register(&tcp_state_helper, TCP_CONNTRACK_ESTABLISHED); +}; +tcp_state: T_FIN_WAIT +{ + extern struct state_replication_helper tcp_state_helper; + state_helper_register(&tcp_state_helper, TCP_CONNTRACK_FIN_WAIT); +}; +tcp_state: T_CLOSE_WAIT +{ + extern struct state_replication_helper tcp_state_helper; + state_helper_register(&tcp_state_helper, TCP_CONNTRACK_CLOSE_WAIT); +}; +tcp_state: T_LAST_ACK +{ + extern struct state_replication_helper tcp_state_helper; + state_helper_register(&tcp_state_helper, TCP_CONNTRACK_LAST_ACK); +}; +tcp_state: T_TIME_WAIT +{ + extern struct state_replication_helper tcp_state_helper; + state_helper_register(&tcp_state_helper, TCP_CONNTRACK_TIME_WAIT); +}; +tcp_state: T_CLOSE +{ + extern struct state_replication_helper tcp_state_helper; + state_helper_register(&tcp_state_helper, TCP_CONNTRACK_CLOSE); +}; +tcp_state: T_LISTEN +{ + extern struct state_replication_helper tcp_state_helper; + state_helper_register(&tcp_state_helper, TCP_CONNTRACK_LISTEN); +}; + +general: T_GENERAL '{' general_list '}'; + +general_list: + | general_list general_line + ; + +general_line: hashsize + | hashlimit + | log + | lock + | unix_line + | netlink_buffer_size + | netlink_buffer_size_max_grown + | family + ; + +netlink_buffer_size: T_BUFFER_SIZE T_NUMBER +{ + conf.netlink_buffer_size = $2; +}; + +netlink_buffer_size_max_grown : T_BUFFER_SIZE_MAX_GROWN T_NUMBER +{ + conf.netlink_buffer_size_max_grown = $2; +}; + +family : T_FAMILY T_STRING +{ + if (strncmp($2, "IPv6", strlen("IPv6")) == 0) + conf.family = AF_INET6; + else + conf.family = AF_INET; +}; + +stats: T_SYNC '{' stats_list '}'; + +stats_list: + | stats_list stat_line + ; + +stat_line: + | + ; + +%% + +int +yyerror(char *msg) +{ + printf("Error parsing config file: "); + printf("line (%d), symbol '%s': %s\n", yylineno, yytext, msg); + exit(EXIT_FAILURE); +} + +int +init_config(char *filename) +{ + FILE *fp; + + fp = fopen(filename, "r"); + if (!fp) + return -1; + + yyrestart(fp); + yyparse(); + fclose(fp); + + /* default to IPv4 */ + if (CONFIG(family) == 0) + CONFIG(family) = AF_INET; + + /* set to default is not specified */ + if (strcmp(CONFIG(lockfile), "") == 0) + strncpy(CONFIG(lockfile), DEFAULT_LOCKFILE, FILENAME_MAXLEN); + + /* default to 180 seconds of expiration time: cache entries */ + if (CONFIG(cache_timeout) == 0) + CONFIG(cache_timeout) = 180; + + /* default to 180 seconds: committed entries */ + if (CONFIG(commit_timeout) == 0) + CONFIG(commit_timeout) = 180; + + /* default to 60 seconds of refresh time */ + if (CONFIG(refresh) == 0) + CONFIG(refresh) = 60; + + if (CONFIG(resend_buffer_size) == 0) + CONFIG(resend_buffer_size) = 262144; + + /* create empty pool */ + if (!STATE(ignore_pool)) { + STATE(ignore_pool) = ignore_pool_create(CONFIG(family)); + if (!STATE(ignore_pool)) { + fprintf(stdout, "Can't create ignore pool!\n"); + exit(EXIT_FAILURE); + } + } + + /* default to a window size of 20 packets */ + if (CONFIG(window_size) == 0) + CONFIG(window_size) = 20; + + return 0; +} diff --git a/daemon/src/run.c b/daemon/src/run.c new file mode 100644 index 0000000..67437d8 --- /dev/null +++ b/daemon/src/run.c @@ -0,0 +1,227 @@ +/* + * (C) 2006-2007 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Description: run and init functions + */ + +#include "conntrackd.h" +#include +#include +#include "us-conntrack.h" +#include +#include + +void killer(int foo) +{ + /* no signals while handling signals */ + sigprocmask(SIG_BLOCK, &STATE(block), NULL); + + nfnl_subsys_close(STATE(subsys_event)); + nfnl_subsys_close(STATE(subsys_dump)); + nfnl_subsys_close(STATE(subsys_sync)); + nfnl_close(STATE(event)); + nfnl_close(STATE(dump)); + nfnl_close(STATE(sync)); + + ignore_pool_destroy(STATE(ignore_pool)); + local_server_destroy(STATE(local)); + STATE(mode)->kill(); + unlink(CONFIG(lockfile)); + dlog(STATE(log), "------- shutdown received ----"); + close_log(STATE(log)); + + sigprocmask(SIG_UNBLOCK, &STATE(block), NULL); + + exit(0); +} + +void local_handler(int fd, void *data) +{ + int ret; + int type; + + ret = read(fd, &type, sizeof(type)); + if (ret == -1) { + dlog(STATE(log), "can't read from unix socket\n"); + return; + } + if (ret == 0) { + debug("nothing to process\n"); + return; + } + + switch(type) { + case FLUSH_MASTER: + dlog(STATE(log), "[REQ] flushing master table"); + nl_flush_master_conntrack_table(); + return; + case RESYNC_MASTER: + dlog(STATE(log), "[REQ] resync with master table"); + nl_dump_conntrack_table(STATE(dump), STATE(subsys_dump)); + return; + } + + if (!STATE(mode)->local(fd, type, data)) + dlog(STATE(log), "[FAIL] unknown local request %d", type); +} + +int init(int mode) +{ + switch(mode) { + case STATS_MODE: + STATE(mode) = &stats_mode; + break; + case SYNC_MODE: + STATE(mode) = &sync_mode; + break; + default: + fprintf(stderr, "Unknown running mode! default " + "to synchronization mode\n"); + STATE(mode) = &sync_mode; + break; + } + + /* Initialization */ + if (STATE(mode)->init() == -1) { + dlog(STATE(log), "[FAIL] initialization failed"); + return -1; + } + + /* local UNIX socket */ + STATE(local) = local_server_create(&CONFIG(local)); + if (!STATE(local)) { + dlog(STATE(log), "[FAIL] can't open unix socket!"); + return -1; + } + + if (nl_init_event_handler() == -1) { + dlog(STATE(log), "[FAIL] can't open netlink handler! " + "no ctnetlink kernel support?"); + return -1; + } + + if (nl_init_dump_handler() == -1) { + dlog(STATE(log), "[FAIL] can't open netlink handler! " + "no ctnetlink kernel support?"); + return -1; + } + + if (nl_init_overrun_handler() == -1) { + dlog(STATE(log), "[FAIL] can't open netlink handler! " + "no ctnetlink kernel support?"); + return -1; + } + + /* Signals handling */ + sigemptyset(&STATE(block)); + sigaddset(&STATE(block), SIGTERM); + sigaddset(&STATE(block), SIGINT); + + if (signal(SIGINT, killer) == SIG_ERR) + return -1; + + if (signal(SIGTERM, killer) == SIG_ERR) + return -1; + + /* ignore connection reset by peer */ + if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) + return -1; + + dlog(STATE(log), "[OK] initialization completed"); + + return 0; +} + +#define POLL_NSECS 1 + +static void __run(void) +{ + int max, ret; + fd_set readfds; + struct timeval tv = { + .tv_sec = POLL_NSECS, + .tv_usec = 0 + }; + + FD_ZERO(&readfds); + FD_SET(STATE(local), &readfds); + FD_SET(nfnl_fd(STATE(event)), &readfds); + + max = MAX(STATE(local), nfnl_fd(STATE(event))); + + if (STATE(mode)->add_fds_to_set) + max = MAX(max, STATE(mode)->add_fds_to_set(&readfds)); + + ret = select(max+1, &readfds, NULL, NULL, &tv); + if (ret == -1) { + /* interrupted syscall, retry */ + if (errno == EINTR) + return; + + dlog(STATE(log), "select() failed: %s", strerror(errno)); + return; + } + + /* signals are racy */ + sigprocmask(SIG_BLOCK, &STATE(block), NULL); + + /* order received via UNIX socket */ + if (FD_ISSET(STATE(local), &readfds)) + do_local_server_step(STATE(local), NULL, local_handler); + + /* conntrack event has happened */ + if (FD_ISSET(nfnl_fd(STATE(event)), &readfds)) { + ret = nfnl_catch(STATE(event)); + if (ret == -1) { + switch(errno) { + case ENOBUFS: + /* + * It seems that ctnetlink can't back off, + * it's likely that we're losing events. + * Solution: duplicate the socket buffer + * size and resync with master conntrack table. + */ + nl_resize_socket_buffer(STATE(event)); + nl_dump_conntrack_table(STATE(sync), + STATE(subsys_sync)); + break; + case ENOENT: + /* + * We received a message from another + * netfilter subsystem that we are not + * interested in. Just ignore it. + */ + break; + default: + dlog(STATE(log), "event catch says: %s", + strerror(errno)); + break; + } + } + } + + if (STATE(mode)->step) + STATE(mode)->step(&readfds); + + sigprocmask(SIG_UNBLOCK, &STATE(block), NULL); +} + +void run(void) +{ + while(1) + __run(); +} diff --git a/daemon/src/state_helper.c b/daemon/src/state_helper.c new file mode 100644 index 0000000..81b0d09 --- /dev/null +++ b/daemon/src/state_helper.c @@ -0,0 +1,44 @@ +/* + * (C) 2006-2007 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "conntrackd.h" +#include "state_helper.h" + +static struct state_replication_helper *helper[IPPROTO_MAX]; + +int state_helper_verdict(int type, struct nf_conntrack *ct) +{ + u_int8_t l4proto; + + if (type == NFCT_T_DESTROY) + return ST_H_REPLICATE; + + l4proto = nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO); + if (helper[l4proto]) + return helper[l4proto]->verdict(helper[l4proto], ct); + + return ST_H_REPLICATE; +} + +void state_helper_register(struct state_replication_helper *h, int state) +{ + if (helper[h->proto] == NULL) + helper[h->proto] = h; + + helper[h->proto]->state |= (1 << state); +} diff --git a/daemon/src/state_helper_tcp.c b/daemon/src/state_helper_tcp.c new file mode 100644 index 0000000..af714dc --- /dev/null +++ b/daemon/src/state_helper_tcp.c @@ -0,0 +1,35 @@ +/* + * (C) 2006-2007 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "conntrackd.h" +#include "state_helper.h" + +static int tcp_verdict(const struct state_replication_helper *h, + const struct nf_conntrack *ct) +{ + u_int8_t state = nfct_get_attr_u8(ct, ATTR_TCP_STATE); + if (h->state & (1 << state)) + return ST_H_REPLICATE; + + return ST_H_SKIP; +} + +struct state_replication_helper tcp_state_helper = { + .proto = IPPROTO_TCP, + .verdict = tcp_verdict, +}; diff --git a/daemon/src/stats-mode.c b/daemon/src/stats-mode.c new file mode 100644 index 0000000..9647bbf --- /dev/null +++ b/daemon/src/stats-mode.c @@ -0,0 +1,151 @@ +/* + * (C) 2006 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include "cache.h" +#include "conntrackd.h" +#include +#include +#include +#include "us-conntrack.h" +#include +#include + +static int init_stats(void) +{ + int ret; + + state.stats = malloc(sizeof(struct ct_stats_state)); + if (!state.stats) { + dlog(STATE(log), "[FAIL] can't allocate memory for stats sync"); + return -1; + } + memset(state.stats, 0, sizeof(struct ct_stats_state)); + + STATE_STATS(cache) = cache_create("stats", + LIFETIME, + CONFIG(family), + NULL); + if (!STATE_STATS(cache)) { + dlog(STATE(log), "[FAIL] can't allocate memory for the " + "external cache"); + return -1; + } + + return 0; +} + +static void kill_stats() +{ + cache_destroy(STATE_STATS(cache)); +} + +/* handler for requests coming via UNIX socket */ +static int local_handler_stats(int fd, int type, void *data) +{ + int ret = 1; + + switch(type) { + case DUMP_INTERNAL: + cache_dump(STATE_STATS(cache), fd, NFCT_O_PLAIN); + break; + case DUMP_INT_XML: + cache_dump(STATE_SYNC(internal), fd, NFCT_O_XML); + break; + case FLUSH_CACHE: + dlog(STATE(log), "[REQ] flushing caches"); + cache_flush(STATE_STATS(cache)); + break; + case KILL: + killer(); + break; + case STATS: + cache_stats(STATE_STATS(cache), fd); + dump_traffic_stats(fd); + break; + default: + ret = 0; + break; + } + + return ret; +} + +static void dump_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh) +{ + if (cache_update_force(STATE_STATS(cache), ct)) + debug_ct(ct, "resync entry"); +} + +static void event_new_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh) +{ + debug_ct(ct, "debug event"); + if (cache_add(STATE_STATS(cache), ct)) { + debug_ct(ct, "cache new"); + } else { + dlog(STATE(log), "can't add to cache cache: " + "%s\n", strerror(errno)); + debug_ct(ct, "can't add"); + } +} + +static void event_update_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh) +{ + debug_ct(ct, "update"); + + if (!cache_update(STATE_STATS(cache), ct)) { + /* + * Perhaps we are losing events. If we are working + * in relax mode then add a new entry to the cache. + * + * FIXME: relax transitions not implemented yet + */ + if ((CONFIG(flags) & RELAX_TRANSITIONS) + && cache_add(STATE_STATS(cache), ct)) { + debug_ct(ct, "forcing cache update"); + } else { + debug_ct(ct, "can't update"); + return; + } + } + debug_ct(ct, "update"); +} + +static int event_destroy_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh) +{ + if (cache_del(STATE_STATS(cache), ct)) { + debug_ct(ct, "cache destroy"); + return 1; + } else { + debug_ct(ct, "can't destroy!"); + return 0; + } +} + +struct ct_mode stats_mode = { + .init = init_stats, + .add_fds_to_set = NULL, + .step = NULL, + .local = local_handler_stats, + .kill = kill_stats, + .dump = dump_stats, + .overrun = dump_stats, + .event_new = event_new_stats, + .event_upd = event_update_stats, + .event_dst = event_destroy_stats +}; diff --git a/daemon/src/sync-mode.c b/daemon/src/sync-mode.c new file mode 100644 index 0000000..b32bef7 --- /dev/null +++ b/daemon/src/sync-mode.c @@ -0,0 +1,416 @@ +/* + * (C) 2006 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include "cache.h" +#include "conntrackd.h" +#include +#include +#include +#include "us-conntrack.h" +#include +#include +#include "sync.h" +#include "network.h" + +/* handler for multicast messages received */ +static void mcast_handler() +{ + int ret; + char buf[4096], tmp[256]; + struct mcast_sock *m = STATE_SYNC(mcast_server); + unsigned int type; + struct nlnetwork *net = (struct nlnetwork *) buf; + unsigned int size = sizeof(struct nlnetwork); + struct nlmsghdr *nlh = (struct nlmsghdr *) (buf + size); + struct nf_conntrack *ct = (struct nf_conntrack *) tmp; + struct us_conntrack *u = NULL; + + memset(tmp, 0, sizeof(tmp)); + + ret = mcast_recv_netmsg(m, buf, sizeof(buf)); + if (ret <= 0) { + STATE(malformed)++; + return; + } + + if (STATE_SYNC(mcast_sync)->pre_recv(net)) + return; + + if ((type = parse_network_msg(ct, nlh)) == NFCT_T_ERROR) { + STATE(malformed)++; + return; + } + + nfct_attr_unset(ct, ATTR_TIMEOUT); + nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES); + nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS); + nfct_attr_unset(ct, ATTR_REPL_COUNTER_BYTES); + nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); + + switch(type) { + case NFCT_T_NEW: +retry: + if ((u = cache_add(STATE_SYNC(external), ct))) { + debug_ct(u->ct, "external new"); + } else { + /* + * One certain connection A arrives to the cache but + * another existing connection B in the cache has + * the same configuration, therefore B clashes with A. + */ + if (errno == EEXIST) { + cache_del(STATE_SYNC(external), ct); + goto retry; + } + debug_ct(ct, "can't add"); + } + break; + case NFCT_T_UPDATE: + if ((u = cache_update_force(STATE_SYNC(external), ct))) { + debug_ct(u->ct, "external update"); + } else + debug_ct(ct, "can't update"); + break; + case NFCT_T_DESTROY: + if (cache_del(STATE_SYNC(external), ct)) + debug_ct(ct, "external destroy"); + else + debug_ct(ct, "can't destroy"); + break; + default: + debug("unknown type %d\n", type); + break; + } +} + +static int init_sync(void) +{ + int ret; + + state.sync = malloc(sizeof(struct ct_sync_state)); + if (!state.sync) { + dlog(STATE(log), "[FAIL] can't allocate memory for state sync"); + return -1; + } + memset(state.sync, 0, sizeof(struct ct_sync_state)); + + if (CONFIG(flags) & SYNC_MODE_NACK) + STATE_SYNC(mcast_sync) = &nack; + else + /* default to persistent mode */ + STATE_SYNC(mcast_sync) = ¬rack; + + if (STATE_SYNC(mcast_sync)->init) + STATE_SYNC(mcast_sync)->init(); + + STATE_SYNC(internal) = + cache_create("internal", + STATE_SYNC(mcast_sync)->internal_cache_flags, + CONFIG(family), + STATE_SYNC(mcast_sync)->internal_cache_extra); + + if (!STATE_SYNC(internal)) { + dlog(STATE(log), "[FAIL] can't allocate memory for " + "the internal cache"); + return -1; + } + + STATE_SYNC(external) = + cache_create("external", + STATE_SYNC(mcast_sync)->external_cache_flags, + CONFIG(family), + NULL); + + if (!STATE_SYNC(external)) { + dlog(STATE(log), "[FAIL] can't allocate memory for the " + "external cache"); + return -1; + } + + /* multicast server to receive events from the wire */ + STATE_SYNC(mcast_server) = mcast_server_create(&CONFIG(mcast)); + if (STATE_SYNC(mcast_server) == NULL) { + dlog(STATE(log), "[FAIL] can't open multicast server!"); + return -1; + } + + /* multicast client to send events on the wire */ + STATE_SYNC(mcast_client) = mcast_client_create(&CONFIG(mcast)); + if (STATE_SYNC(mcast_client) == NULL) { + dlog(STATE(log), "[FAIL] can't open client multicast socket!"); + return -1; + } + + /* initialization of multicast sequence generation */ + STATE_SYNC(last_seq_sent) = time(NULL); + + if (create_alarm_thread() == -1) { + dlog(STATE(log), "[FAIL] can't initialize alarm thread"); + return -1; + } + + return 0; +} + +static int add_fds_to_set_sync(fd_set *readfds) +{ + FD_SET(STATE_SYNC(mcast_server->fd), readfds); + + return STATE_SYNC(mcast_server->fd); +} + +static void step_sync(fd_set *readfds) +{ + /* multicast packet has been received */ + if (FD_ISSET(STATE_SYNC(mcast_server->fd), readfds)) + mcast_handler(); +} + +static void kill_sync() +{ + cache_destroy(STATE_SYNC(internal)); + cache_destroy(STATE_SYNC(external)); + + mcast_server_destroy(STATE_SYNC(mcast_server)); + mcast_client_destroy(STATE_SYNC(mcast_client)); + + destroy_alarm_thread(); + + if (STATE_SYNC(mcast_sync)->kill) + STATE_SYNC(mcast_sync)->kill(); +} + +static dump_stats_sync(int fd) +{ + char buf[512]; + int size; + + size = sprintf(buf, "multicast sequence tracking:\n" + "%20llu Pckts mfrm " + "%20llu Pckts lost\n\n", + STATE(malformed), + STATE_SYNC(packets_lost)); + + send(fd, buf, size, 0); +} + +/* handler for requests coming via UNIX socket */ +static int local_handler_sync(int fd, int type, void *data) +{ + int ret = 1; + + switch(type) { + case DUMP_INTERNAL: + cache_dump(STATE_SYNC(internal), fd, NFCT_O_PLAIN); + break; + case DUMP_EXTERNAL: + cache_dump(STATE_SYNC(external), fd, NFCT_O_PLAIN); + break; + case DUMP_INT_XML: + cache_dump(STATE_SYNC(internal), fd, NFCT_O_XML); + break; + case DUMP_EXT_XML: + cache_dump(STATE_SYNC(external), fd, NFCT_O_XML); + break; + case COMMIT: + dlog(STATE(log), "[REQ] commit external cache to master table"); + cache_commit(STATE_SYNC(external)); + break; + case FLUSH_CACHE: + dlog(STATE(log), "[REQ] flushing caches"); + cache_flush(STATE_SYNC(internal)); + cache_flush(STATE_SYNC(external)); + break; + case KILL: + killer(); + break; + case STATS: + cache_stats(STATE_SYNC(internal), fd); + cache_stats(STATE_SYNC(external), fd); + dump_traffic_stats(fd); + mcast_dump_stats(fd, STATE_SYNC(mcast_client), + STATE_SYNC(mcast_server)); + dump_stats_sync(fd); + break; + case SEND_BULK: + dlog(STATE(log), "[REQ] sending bulk update"); + cache_bulk(STATE_SYNC(internal)); + break; + default: + if (STATE_SYNC(mcast_sync)->local) + ret = STATE_SYNC(mcast_sync)->local(fd, type, data); + break; + } + + return ret; +} + +static void dump_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) +{ + /* This is required by kernels < 2.6.20 */ + nfct_attr_unset(ct, ATTR_TIMEOUT); + nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES); + nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS); + nfct_attr_unset(ct, ATTR_REPL_COUNTER_BYTES); + nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); + nfct_attr_unset(ct, ATTR_USE); + + if (cache_update_force(STATE_SYNC(internal), ct)) + debug_ct(ct, "resync"); +} + +static void mcast_send_sync(struct nlmsghdr *nlh, + struct us_conntrack *u, + struct nf_conntrack *ct, + int type) +{ + char buf[4096]; + struct nlnetwork *net = (struct nlnetwork *) buf; + int mangled = 0; + + memset(buf, 0, sizeof(buf)); + + if (!state_helper_verdict(type, ct)) + return; + + if (!mangled) + memcpy(buf + sizeof(struct nlnetwork), nlh, nlh->nlmsg_len); + + mcast_send_netmsg(STATE_SYNC(mcast_client), net); + STATE_SYNC(mcast_sync)->post_send(net, u); +} + +static void overrun_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) +{ + struct us_conntrack *u; + + /* This is required by kernels < 2.6.20 */ + nfct_attr_unset(ct, ATTR_TIMEOUT); + nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES); + nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS); + nfct_attr_unset(ct, ATTR_REPL_COUNTER_BYTES); + nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); + nfct_attr_unset(ct, ATTR_USE); + + if (!cache_test(STATE_SYNC(internal), ct)) { + if ((u = cache_update_force(STATE_SYNC(internal), ct))) { + debug_ct(ct, "overrun resync"); + mcast_send_sync(nlh, u, ct, NFCT_T_UPDATE); + } + } +} + +static void event_new_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) +{ + struct us_conntrack *u; + + /* required by linux kernel <= 2.6.20 */ + nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES); + nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS); + nfct_attr_unset(ct, ATTR_REPL_COUNTER_BYTES); + nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); + nfct_attr_unset(ct, ATTR_TIMEOUT); +retry: + if ((u = cache_add(STATE_SYNC(internal), ct))) { + mcast_send_sync(nlh, u, ct, NFCT_T_NEW); + debug_ct(u->ct, "internal new"); + } else { + if (errno == EEXIST) { + char buf[4096]; + struct nlmsghdr *nlh = (struct nlmsghdr *) buf; + + int ret = build_network_msg(NFCT_Q_DESTROY, + STATE(subsys_event), + ct, + buf, + sizeof(buf)); + if (ret == -1) + return; + + cache_del(STATE_SYNC(internal), ct); + mcast_send_sync(nlh, NULL, ct, NFCT_T_NEW); + goto retry; + } + dlog(STATE(log), "can't add to internal cache: " + "%s\n", strerror(errno)); + debug_ct(ct, "can't add"); + } +} + +static void event_update_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) +{ + struct us_conntrack *u; + + nfct_attr_unset(ct, ATTR_TIMEOUT); + + if ((u = cache_update(STATE_SYNC(internal), ct)) == NULL) { + /* + * Perhaps we are losing events. If we are working + * in relax mode then add a new entry to the cache. + * + * FIXME: relax transitions not implemented yet + */ + if ((CONFIG(flags) & RELAX_TRANSITIONS) + && (u = cache_add(STATE_SYNC(internal), ct))) { + debug_ct(u->ct, "forcing internal update"); + } else { + debug_ct(ct, "can't update"); + return; + } + } + debug_ct(u->ct, "internal update"); + mcast_send_sync(nlh, u, ct, NFCT_T_UPDATE); +} + +static int event_destroy_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) +{ + nfct_attr_unset(ct, ATTR_TIMEOUT); + + if (CONFIG(flags) & DELAY_DESTROY_MSG) { + + nfct_set_attr_u32(ct, ATTR_STATUS, IPS_DYING); + + if (cache_update(STATE_SYNC(internal), ct)) { + debug_ct(ct, "delay internal destroy"); + return 1; + } else { + debug_ct(ct, "can't delay destroy!"); + return 0; + } + } else { + if (cache_del(STATE_SYNC(internal), ct)) { + mcast_send_sync(nlh, NULL, ct, NFCT_T_DESTROY); + debug_ct(ct, "internal destroy"); + } else + debug_ct(ct, "can't destroy"); + } +} + +struct ct_mode sync_mode = { + .init = init_sync, + .add_fds_to_set = add_fds_to_set_sync, + .step = step_sync, + .local = local_handler_sync, + .kill = kill_sync, + .dump = dump_sync, + .overrun = overrun_sync, + .event_new = event_new_sync, + .event_upd = event_update_sync, + .event_dst = event_destroy_sync +}; diff --git a/daemon/src/sync-nack.c b/daemon/src/sync-nack.c new file mode 100644 index 0000000..288dba4 --- /dev/null +++ b/daemon/src/sync-nack.c @@ -0,0 +1,309 @@ +/* + * (C) 2006-2007 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include "conntrackd.h" +#include "sync.h" +#include "linux_list.h" +#include "us-conntrack.h" +#include "buffer.h" +#include "debug.h" +#include "network.h" +#include +#include + +#if 0 +#define dp printf +#else +#define dp +#endif + +static LIST_HEAD(queue); + +struct cache_nack { + struct list_head head; + u_int32_t seq; +}; + +static void cache_nack_add(struct us_conntrack *u, void *data) +{ + struct cache_nack *cn = data; + + INIT_LIST_HEAD(&cn->head); + list_add(&cn->head, &queue); +} + +static void cache_nack_update(struct us_conntrack *u, void *data) +{ + struct cache_nack *cn = data; + + if (cn->head.next != LIST_POISON1 && + cn->head.prev != LIST_POISON2) + list_del(&cn->head); + + INIT_LIST_HEAD(&cn->head); + list_add(&cn->head, &queue); +} + +static void cache_nack_destroy(struct us_conntrack *u, void *data) +{ + struct cache_nack *cn = data; + + if (cn->head.next != LIST_POISON1 && + cn->head.prev != LIST_POISON2) + list_del(&cn->head); +} + +static struct cache_extra cache_nack_extra = { + .size = sizeof(struct cache_nack), + .add = cache_nack_add, + .update = cache_nack_update, + .destroy = cache_nack_destroy +}; + +static int nack_init() +{ + STATE_SYNC(buffer) = buffer_create(CONFIG(resend_buffer_size)); + if (STATE_SYNC(buffer) == NULL) + return -1; + + return 0; +} + +static void nack_kill() +{ + buffer_destroy(STATE_SYNC(buffer)); +} + +static void mcast_send_nack(u_int32_t expt_seq, u_int32_t recv_seq) +{ + struct nlnetwork_ack nack = { + .flags = NET_NACK, + .from = expt_seq, + .to = recv_seq, + }; + + mcast_send_error(STATE_SYNC(mcast_client), &nack); + buffer_add(STATE_SYNC(buffer), &nack, sizeof(struct nlnetwork_ack)); +} + +static void mcast_send_ack(u_int32_t from, u_int32_t to) +{ + struct nlnetwork_ack ack = { + .flags = NET_ACK, + .from = from, + .to = to, + }; + + mcast_send_error(STATE_SYNC(mcast_client), &ack); + buffer_add(STATE_SYNC(buffer), &ack, sizeof(struct nlnetwork_ack)); +} + +static void mcast_send_resync() +{ + struct nlnetwork net = { + .flags = NET_RESYNC, + }; + + mcast_send_error(STATE_SYNC(mcast_client), &net); + buffer_add(STATE_SYNC(buffer), &net, sizeof(struct nlnetwork)); +} + +int nack_local(int fd, int type, void *data) +{ + int ret = 1; + + switch(type) { + case REQUEST_DUMP: + mcast_send_resync(); + dlog(STATE(log), "[REQ] request resync"); + break; + default: + ret = 0; + break; + } + + return ret; +} + +static int buffer_compare(void *data1, void *data2) +{ + struct nlnetwork *net = data1; + struct nlnetwork_ack *nack = data2; + struct nlmsghdr *nlh = data1 + sizeof(struct nlnetwork); + + unsigned old_seq = ntohl(net->seq); + + if (ntohl(net->seq) >= nack->from && ntohl(net->seq) <= nack->to) { + if (mcast_resend_netmsg(STATE_SYNC(mcast_client), net)) + dp("resend destroy (old seq=%u) (seq=%u)\n", + old_seq, ntohl(net->seq)); + } + return 0; +} + +static int buffer_remove(void *data1, void *data2) +{ + struct nlnetwork *net = data1; + struct nlnetwork_ack *h = data2; + + if (ntohl(net->seq) >= h->from && ntohl(net->seq) <= h->to) { + dp("remove from buffer (seq=%u)\n", ntohl(net->seq)); + __buffer_del(STATE_SYNC(buffer), data1); + } + return 0; +} + +static void queue_resend(struct cache *c, unsigned int from, unsigned int to) +{ + struct list_head *n; + struct us_conntrack *u; + unsigned int *seq; + + lock(); + list_for_each(n, &queue) { + struct cache_nack *cn = (struct cache_nack *) n; + struct us_conntrack *u; + + u = cache_get_conntrack(STATE_SYNC(internal), cn); + + if (cn->seq >= from && cn->seq <= to) { + debug_ct(u->ct, "resend nack"); + dp("resending nack'ed (oldseq=%u) ", cn->seq); + + char buf[4096]; + struct nlnetwork *net = (struct nlnetwork *) buf; + + int ret = build_network_msg(NFCT_Q_UPDATE, + STATE(subsys_event), + u->ct, + buf, + sizeof(buf)); + if (ret == -1) { + unlock(); + break; + } + + mcast_send_netmsg(STATE_SYNC(mcast_client), buf); + STATE_SYNC(mcast_sync)->post_send(net, u); + dp("(newseq=%u)\n", *seq); + } + } + unlock(); +} + +static void queue_empty(struct cache *c, unsigned int from, unsigned int to) +{ + struct list_head *n, *tmp; + struct us_conntrack *u; + unsigned int *seq; + + lock(); + dp("ACK from %u to %u\n", from, to); + list_for_each_safe(n, tmp, &queue) { + struct cache_nack *cn = (struct cache_nack *) n; + + u = cache_get_conntrack(STATE_SYNC(internal), cn); + if (cn->seq >= from && cn->seq <= to) { + dp("remove %u\n", cn->seq); + debug_ct(u->ct, "ack received: empty queue"); + dp("queue: deleting from queue (seq=%u)\n", cn->seq); + list_del(&cn->head); + } + } + unlock(); +} + +static int nack_pre_recv(const struct nlnetwork *net) +{ + static unsigned int window = 0; + unsigned int exp_seq; + + if (window == 0) + window = CONFIG(window_size); + + if (!mcast_track_seq(net->seq, &exp_seq)) { + dp("OOS: sending nack (seq=%u)\n", exp_seq); + mcast_send_nack(exp_seq, net->seq - 1); + window = CONFIG(window_size); + } else { + /* received a window, send an acknowledgement */ + if (--window == 0) { + dp("sending ack (seq=%u)\n", net->seq); + mcast_send_ack(net->seq-CONFIG(window_size), net->seq); + } + } + + if (net->flags & NET_NACK) { + struct nlnetwork_ack *nack = (struct nlnetwork_ack *) net; + + dp("NACK: from seq=%u to seq=%u\n", nack->from, nack->to); + queue_resend(STATE_SYNC(internal), nack->from, nack->to); + buffer_iterate(STATE_SYNC(buffer), nack, buffer_compare); + return 1; + } else if (net->flags & NET_RESYNC) { + dp("RESYNC ALL\n"); + cache_bulk(STATE_SYNC(internal)); + return 1; + } else if (net->flags & NET_ACK) { + struct nlnetwork_ack *h = (struct nlnetwork_ack *) net; + + dp("ACK: from seq=%u to seq=%u\n", h->from, h->to); + queue_empty(STATE_SYNC(internal), h->from, h->to); + buffer_iterate(STATE_SYNC(buffer), h, buffer_remove); + return 1; + } + + return 0; +} + +static void nack_post_send(const struct nlnetwork *net, struct us_conntrack *u) +{ + unsigned int size = sizeof(struct nlnetwork); + struct nlmsghdr *nlh = (struct nlmsghdr *) ((void *) net + size); + + if (NFNL_MSG_TYPE(ntohs(nlh->nlmsg_type)) == IPCTNL_MSG_CT_DELETE) { + buffer_add(STATE_SYNC(buffer), net, + ntohl(nlh->nlmsg_len) + size); + } else if (u != NULL) { + unsigned int *seq; + struct list_head *n; + struct cache_nack *cn; + + cn = (struct cache_nack *) + cache_get_extra(STATE_SYNC(internal), u); + cn->seq = ntohl(net->seq); + if (cn->head.next != LIST_POISON1 && + cn->head.prev != LIST_POISON2) + list_del(&cn->head); + + INIT_LIST_HEAD(&cn->head); + list_add(&cn->head, &queue); + } +} + +struct sync_mode nack = { + .internal_cache_flags = LIFETIME, + .external_cache_flags = LIFETIME, + .internal_cache_extra = &cache_nack_extra, + .init = nack_init, + .kill = nack_kill, + .local = nack_local, + .pre_recv = nack_pre_recv, + .post_send = nack_post_send, +}; diff --git a/daemon/src/sync-notrack.c b/daemon/src/sync-notrack.c new file mode 100644 index 0000000..2b5ae38 --- /dev/null +++ b/daemon/src/sync-notrack.c @@ -0,0 +1,127 @@ +/* + * (C) 2006-2007 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "conntrackd.h" +#include "sync.h" +#include "network.h" +#include "us-conntrack.h" +#include "alarm.h" + +static void refresher(struct alarm_list *a, void *data) +{ + struct us_conntrack *u = data; + char buf[8192]; + int size; + + if (nfct_get_attr_u32(u->ct, ATTR_STATUS) & IPS_DYING) { + + debug_ct(u->ct, "persistence destroy"); + + size = build_network_msg(NFCT_Q_DESTROY, + STATE(subsys_event), + u->ct, + buf, + sizeof(buf)); + + __cache_del(u->cache, u->ct); + mcast_send_netmsg(STATE_SYNC(mcast_client), buf); + } else { + + debug_ct(u->ct, "persistence update"); + + a->expires = random() % CONFIG(refresh) + 1; + size = build_network_msg(NFCT_Q_UPDATE, + STATE(subsys_event), + u->ct, + buf, + sizeof(buf)); + mcast_send_netmsg(STATE_SYNC(mcast_client), buf); + } +} + +static void cache_notrack_add(struct us_conntrack *u, void *data) +{ + struct alarm_list *alarm = data; + + init_alarm(alarm); + set_alarm_expiration(alarm, (random() % conf.refresh) + 1); + set_alarm_data(alarm, u); + set_alarm_function(alarm, refresher); + add_alarm(alarm); +} + +static void cache_notrack_update(struct us_conntrack *u, void *data) +{ + struct alarm_list *alarm = data; + mod_alarm(alarm, (random() % conf.refresh) + 1); +} + +static void cache_notrack_destroy(struct us_conntrack *u, void *data) +{ + struct alarm_list *alarm = data; + del_alarm(alarm); +} + +static struct cache_extra cache_notrack_extra = { + .size = sizeof(struct alarm_list), + .add = cache_notrack_add, + .update = cache_notrack_update, + .destroy = cache_notrack_destroy +}; + +static int notrack_pre_recv(const struct nlnetwork *net) +{ + unsigned int exp_seq; + + /* + * Ignore error messages: Although this message type is not ever + * generated in notrack mode, we don't want to crash the daemon + * if someone nuts mixes nack and notrack. + */ + if (net->flags & (NET_RESYNC | NET_NACK)) + return 1; + + /* + * Multicast sequence tracking: we keep track of multicast messages + * although we don't do any explicit message recovery. So, why do + * we do sequence tracking? Just to let know the sysadmin. + * + * Let t be 1 < t < RefreshTime. To ensure consistency, conntrackd + * retransmit every t seconds a message with the state of a certain + * entry even if such entry did not change. This mechanism also + * provides passive resynchronization, in other words, there is + * no facility to request a full synchronization from new nodes that + * just joined the cluster, instead they just get resynchronized in + * RefreshTime seconds at worst case. + */ + mcast_track_seq(net->seq, &exp_seq); + + return 0; +} + +static void notrack_post_send(const struct nlnetwork *n, struct us_conntrack *u) +{ +} + +struct sync_mode notrack = { + .internal_cache_flags = LIFETIME, + .external_cache_flags = TIMER | LIFETIME, + .internal_cache_extra = &cache_notrack_extra, + .pre_recv = notrack_pre_recv, + .post_send = notrack_post_send, +}; diff --git a/daemon/src/traffic_stats.c b/daemon/src/traffic_stats.c new file mode 100644 index 0000000..b510b77 --- /dev/null +++ b/daemon/src/traffic_stats.c @@ -0,0 +1,54 @@ +/* + * (C) 2006 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "cache.h" +#include "hash.h" +#include "conntrackd.h" +#include +#include +#include +#include "us-conntrack.h" +#include + +void update_traffic_stats(struct nf_conntrack *ct) +{ + STATE(bytes)[NFCT_DIR_ORIGINAL] += + nfct_get_attr_u32(ct, ATTR_ORIG_COUNTER_BYTES); + STATE(bytes)[NFCT_DIR_REPLY] += + nfct_get_attr_u32(ct, ATTR_REPL_COUNTER_BYTES); + STATE(packets)[NFCT_DIR_ORIGINAL] += + nfct_get_attr_u32(ct, ATTR_ORIG_COUNTER_PACKETS); + STATE(packets)[NFCT_DIR_REPLY] += + nfct_get_attr_u32(ct, ATTR_REPL_COUNTER_PACKETS); +} + +void dump_traffic_stats(int fd) +{ + char buf[512]; + int size; + u_int64_t bytes = STATE(bytes)[NFCT_DIR_ORIGINAL] + + STATE(bytes)[NFCT_DIR_REPLY]; + u_int64_t packets = STATE(packets)[NFCT_DIR_ORIGINAL] + + STATE(packets)[NFCT_DIR_REPLY]; + + size = sprintf(buf, "traffic processed:\n"); + size += sprintf(buf+size, "%20llu Bytes ", bytes); + size += sprintf(buf+size, "%20llu Pckts\n\n", packets); + + send(fd, buf, size, 0); +} diff --git a/extensions/Makefile.am b/extensions/Makefile.am deleted file mode 100644 index 5366ee3..0000000 --- a/extensions/Makefile.am +++ /dev/null @@ -1,16 +0,0 @@ -include $(top_srcdir)/Make_global.am - -AM_CFLAGS=-fPIC -Wall -LIBS= - -pkglib_LTLIBRARIES = ct_proto_tcp.la ct_proto_udp.la \ - ct_proto_icmp.la ct_proto_sctp.la - -ct_proto_tcp_la_SOURCES = libct_proto_tcp.c -ct_proto_tcp_la_LDFLAGS = -module -avoid-version -ct_proto_udp_la_SOURCES = libct_proto_udp.c -ct_proto_udp_la_LDFLAGS = -module -avoid-version -ct_proto_icmp_la_SOURCES = libct_proto_icmp.c -ct_proto_icmp_la_LDFLAGS = -module -avoid-version -ct_proto_sctp_la_SOURCES = libct_proto_sctp.c -ct_proto_sctp_la_LDFLAGS = -module -avoid-version diff --git a/extensions/libct_proto_icmp.c b/extensions/libct_proto_icmp.c deleted file mode 100644 index e7cb04d..0000000 --- a/extensions/libct_proto_icmp.c +++ /dev/null @@ -1,108 +0,0 @@ -/* - * (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 /* For htons */ -#include -#include -#include -#include "conntrack.h" - -static struct option opts[] = { - {"icmp-type", 1, 0, '1'}, - {"icmp-code", 1, 0, '2'}, - {"icmp-id", 1, 0, '3'}, - {0, 0, 0, 0} -}; - -static void help() -{ - fprintf(stdout, "--icmp-type icmp type\n"); - fprintf(stdout, "--icmp-code icmp code\n"); - fprintf(stdout, "--icmp-id icmp id\n"); -} - -/* Add 1; spaces filled with 0. */ -static u_int8_t invmap[] - = { [ICMP_ECHO] = ICMP_ECHOREPLY + 1, - [ICMP_ECHOREPLY] = ICMP_ECHO + 1, - [ICMP_TIMESTAMP] = ICMP_TIMESTAMPREPLY + 1, - [ICMP_TIMESTAMPREPLY] = ICMP_TIMESTAMP + 1, - [ICMP_INFO_REQUEST] = ICMP_INFO_REPLY + 1, - [ICMP_INFO_REPLY] = ICMP_INFO_REQUEST + 1, - [ICMP_ADDRESS] = ICMP_ADDRESSREPLY + 1, - [ICMP_ADDRESSREPLY] = ICMP_ADDRESS + 1}; - -static int parse(char c, char *argv[], - struct nfct_tuple *orig, - struct nfct_tuple *reply, - struct nfct_tuple *exptuple, - struct nfct_tuple *mask, - union nfct_protoinfo *proto, - unsigned int *flags) -{ - switch(c) { - case '1': - if (optarg) { - orig->l4dst.icmp.type = atoi(optarg); - reply->l4dst.icmp.type = - invmap[orig->l4dst.icmp.type] - 1; - *flags |= ICMP_TYPE; - } - break; - case '2': - if (optarg) { - orig->l4dst.icmp.code = atoi(optarg); - reply->l4dst.icmp.code = 0; - *flags |= ICMP_CODE; - } - break; - case '3': - if (optarg) { - orig->l4src.icmp.id = htons(atoi(optarg)); - reply->l4dst.icmp.id = 0; - *flags |= ICMP_ID; - } - break; - } - return 1; -} - -static int final_check(unsigned int flags, - unsigned int command, - struct nfct_tuple *orig, - struct nfct_tuple *reply) -{ - if (!(flags & ICMP_TYPE)) - return 0; - else if (!(flags & ICMP_CODE)) - return 0; - - return 1; -} - -static struct ctproto_handler icmp = { - .name = "icmp", - .protonum = IPPROTO_ICMP, - .parse_opts = parse, - .final_check = final_check, - .help = help, - .opts = opts, - .version = VERSION, -}; - -static void __attribute__ ((constructor)) init(void); - -static void init(void) -{ - register_proto(&icmp); -} diff --git a/extensions/libct_proto_icmp.man b/extensions/libct_proto_icmp.man deleted file mode 100644 index 3b860d0..0000000 --- a/extensions/libct_proto_icmp.man +++ /dev/null @@ -1,10 +0,0 @@ -This module matches on ICMP-specific fields. -.TP -.BI "--icmp-type " "TYPE" -ICMP Type. Has to be specified numerically. -.TP -.BI "--icmp-code " "CODE" -ICMP Code. Has to be specified numerically. -.TP -.BI "--icmp-id " "ID" -ICMP Id. Has to be specified numerically. diff --git a/extensions/libct_proto_sctp.c b/extensions/libct_proto_sctp.c deleted file mode 100644 index 1c8f0d1..0000000 --- a/extensions/libct_proto_sctp.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - * (C) 2005 by Harald Welte - * 2006 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 -#include -#include -#include -#include /* For htons */ -#include "conntrack.h" -#include -#include - -static struct option opts[] = { - {"orig-port-src", 1, 0, '1'}, - {"orig-port-dst", 1, 0, '2'}, - {"reply-port-src", 1, 0, '3'}, - {"reply-port-dst", 1, 0, '4'}, - {"state", 1, 0, '5'}, - {"tuple-port-src", 1, 0, '6'}, - {"tuple-port-dst", 1, 0, '7'}, - {0, 0, 0, 0} -}; - -static const char *states[] = { - "NONE", - "CLOSED", - "COOKIE_WAIT", - "COOKIE_ECHOED", - "ESTABLISHED", - "SHUTDOWN_SENT", - "SHUTDOWN_RECV", - "SHUTDOWN_ACK_SENT", -}; - -static void help() -{ - fprintf(stdout, "--orig-port-src original source port\n"); - fprintf(stdout, "--orig-port-dst original destination port\n"); - fprintf(stdout, "--reply-port-src reply source port\n"); - fprintf(stdout, "--reply-port-dst reply destination port\n"); - fprintf(stdout, "--state SCTP state, fe. ESTABLISHED\n"); - fprintf(stdout, "--tuple-port-src expectation tuple src port\n"); - fprintf(stdout, "--tuple-port-src expectation tuple dst port\n"); -} - -static int parse_options(char c, char *argv[], - struct nfct_tuple *orig, - struct nfct_tuple *reply, - struct nfct_tuple *exptuple, - struct nfct_tuple *mask, - union nfct_protoinfo *proto, - unsigned int *flags) -{ - switch(c) { - case '1': - if (optarg) { - orig->l4src.sctp.port = htons(atoi(optarg)); - *flags |= SCTP_ORIG_SPORT; - } - break; - case '2': - if (optarg) { - orig->l4dst.sctp.port = htons(atoi(optarg)); - *flags |= SCTP_ORIG_DPORT; - } - break; - case '3': - if (optarg) { - reply->l4src.sctp.port = htons(atoi(optarg)); - *flags |= SCTP_REPL_SPORT; - } - break; - case '4': - if (optarg) { - reply->l4dst.sctp.port = htons(atoi(optarg)); - *flags |= SCTP_REPL_DPORT; - } - break; - case '5': - if (optarg) { - int i; - for (i=0; i<10; i++) { - if (strcmp(optarg, states[i]) == 0) { - /* FIXME: Add state to - * nfct_protoinfo - proto->sctp.state = i; */ - break; - } - } - if (i == 10) { - printf("doh?\n"); - return 0; - } - *flags |= SCTP_STATE; - } - break; - case '6': - if (optarg) { - exptuple->l4src.sctp.port = htons(atoi(optarg)); - *flags |= SCTP_EXPTUPLE_SPORT; - } - break; - case '7': - if (optarg) { - exptuple->l4dst.sctp.port = htons(atoi(optarg)); - *flags |= SCTP_EXPTUPLE_DPORT; - } - - } - return 1; -} - -static int final_check(unsigned int flags, - unsigned int command, - struct nfct_tuple *orig, - struct nfct_tuple *reply) -{ - int ret = 0; - - if ((flags & (SCTP_ORIG_SPORT|SCTP_ORIG_DPORT)) - && !(flags & (SCTP_REPL_SPORT|SCTP_REPL_DPORT))) { - reply->l4src.sctp.port = orig->l4dst.sctp.port; - reply->l4dst.sctp.port = orig->l4src.sctp.port; - ret = 1; - } else if (!(flags & (SCTP_ORIG_SPORT|SCTP_ORIG_DPORT)) - && (flags & (SCTP_REPL_SPORT|SCTP_REPL_DPORT))) { - orig->l4src.sctp.port = reply->l4dst.sctp.port; - orig->l4dst.sctp.port = reply->l4src.sctp.port; - ret = 1; - } - if ((flags & (SCTP_ORIG_SPORT|SCTP_ORIG_DPORT)) - && ((flags & (SCTP_REPL_SPORT|SCTP_REPL_DPORT)))) - ret = 1; - - /* --state is missing and we are trying to create a conntrack */ - if (ret && (command & CT_CREATE) && (!(flags & SCTP_STATE))) - ret = 0; - - return ret; -} - -static struct ctproto_handler sctp = { - .name = "sctp", - .protonum = IPPROTO_SCTP, - .parse_opts = parse_options, - .final_check = final_check, - .help = help, - .opts = opts, - .version = VERSION, -}; - -static void __attribute__ ((constructor)) init(void); - -static void init(void) -{ - register_proto(&sctp); -} diff --git a/extensions/libct_proto_tcp.c b/extensions/libct_proto_tcp.c deleted file mode 100644 index ee24206..0000000 --- a/extensions/libct_proto_tcp.c +++ /dev/null @@ -1,180 +0,0 @@ -/* - * (C) 2005 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 -#include -#include -#include -#include /* For htons */ -#include -#include - -#include "conntrack.h" - -static struct option opts[] = { - {"orig-port-src", 1, 0, '1'}, - {"orig-port-dst", 1, 0, '2'}, - {"reply-port-src", 1, 0, '3'}, - {"reply-port-dst", 1, 0, '4'}, - {"mask-port-src", 1, 0, '5'}, - {"mask-port-dst", 1, 0, '6'}, - {"state", 1, 0, '7'}, - {"tuple-port-src", 1, 0, '8'}, - {"tuple-port-dst", 1, 0, '9'}, - {0, 0, 0, 0} -}; - -static const char *states[] = { - "NONE", - "SYN_SENT", - "SYN_RECV", - "ESTABLISHED", - "FIN_WAIT", - "CLOSE_WAIT", - "LAST_ACK", - "TIME_WAIT", - "CLOSE", - "LISTEN" -}; - -static void help() -{ - fprintf(stdout, "--orig-port-src original source port\n"); - fprintf(stdout, "--orig-port-dst original destination port\n"); - fprintf(stdout, "--reply-port-src reply source port\n"); - fprintf(stdout, "--reply-port-dst reply destination port\n"); - fprintf(stdout, "--mask-port-src mask source port\n"); - fprintf(stdout, "--mask-port-dst mask destination port\n"); - fprintf(stdout, "--tuple-port-src expectation tuple src port\n"); - fprintf(stdout, "--tuple-port-src expectation tuple dst port\n"); - fprintf(stdout, "--state TCP state, fe. ESTABLISHED\n"); -} - -static int parse_options(char c, char *argv[], - struct nfct_tuple *orig, - struct nfct_tuple *reply, - struct nfct_tuple *exptuple, - struct nfct_tuple *mask, - union nfct_protoinfo *proto, - unsigned int *flags) -{ - switch(c) { - case '1': - if (optarg) { - orig->l4src.tcp.port = htons(atoi(optarg)); - *flags |= TCP_ORIG_SPORT; - } - break; - case '2': - if (optarg) { - orig->l4dst.tcp.port = htons(atoi(optarg)); - *flags |= TCP_ORIG_DPORT; - } - break; - case '3': - if (optarg) { - reply->l4src.tcp.port = htons(atoi(optarg)); - *flags |= TCP_REPL_SPORT; - } - break; - case '4': - if (optarg) { - reply->l4dst.tcp.port = htons(atoi(optarg)); - *flags |= TCP_REPL_DPORT; - } - break; - case '5': - if (optarg) { - mask->l4src.tcp.port = htons(atoi(optarg)); - *flags |= TCP_MASK_SPORT; - } - break; - case '6': - if (optarg) { - mask->l4dst.tcp.port = htons(atoi(optarg)); - *flags |= TCP_MASK_DPORT; - } - break; - case '7': - if (optarg) { - int i; - for (i=0; i<10; i++) { - if (strcmp(optarg, states[i]) == 0) { - proto->tcp.state = i; - break; - } - } - if (i == 10) { - printf("doh?\n"); - return 0; - } - *flags |= TCP_STATE; - } - break; - case '8': - if (optarg) { - exptuple->l4src.tcp.port = htons(atoi(optarg)); - *flags |= TCP_EXPTUPLE_SPORT; - } - break; - case '9': - if (optarg) { - exptuple->l4dst.tcp.port = htons(atoi(optarg)); - *flags |= TCP_EXPTUPLE_DPORT; - } - break; - } - return 1; -} - -static int final_check(unsigned int flags, - unsigned int command, - struct nfct_tuple *orig, - struct nfct_tuple *reply) -{ - int ret = 0; - - if ((flags & (TCP_ORIG_SPORT|TCP_ORIG_DPORT)) - && !(flags & (TCP_REPL_SPORT|TCP_REPL_DPORT))) { - reply->l4src.tcp.port = orig->l4dst.tcp.port; - reply->l4dst.tcp.port = orig->l4src.tcp.port; - ret = 1; - } else if (!(flags & (TCP_ORIG_SPORT|TCP_ORIG_DPORT)) - && (flags & (TCP_REPL_SPORT|TCP_REPL_DPORT))) { - orig->l4src.tcp.port = reply->l4dst.tcp.port; - orig->l4dst.tcp.port = reply->l4src.tcp.port; - ret = 1; - } - if ((flags & (TCP_ORIG_SPORT|TCP_ORIG_DPORT)) - && ((flags & (TCP_REPL_SPORT|TCP_REPL_DPORT)))) - ret = 1; - - /* --state is missing and we are trying to create a conntrack */ - if (ret && (command & CT_CREATE) && (!(flags & TCP_STATE))) - ret = 0; - - return ret; -} - -static struct ctproto_handler tcp = { - .name = "tcp", - .protonum = IPPROTO_TCP, - .parse_opts = parse_options, - .final_check = final_check, - .help = help, - .opts = opts, - .version = VERSION, -}; - -static void __attribute__ ((constructor)) init(void); - -static void init(void) -{ - register_proto(&tcp); -} diff --git a/extensions/libct_proto_tcp.man b/extensions/libct_proto_tcp.man deleted file mode 100644 index 41783f8..0000000 --- a/extensions/libct_proto_tcp.man +++ /dev/null @@ -1,16 +0,0 @@ -This module matches on TCP-specific fields. -.TP -.BI "--orig-port-src " "PORT" -Source port in original direction -.TP -.BI "--orig-port-dst " "PORT" -Destination port in original direction -.TP -.BI "--reply-port-src " "PORT" -Source port in reply direction -.TP -.BI "--reply-port-dst " "PORT" -Destination port in reply direction -.TP -.BI "--state " "[NONE|SYN_SENT|SYN_RECV|ESTABLISHED|FIN_WAIT|CLOSE_WAIT|LAST_ACK|TIME_WAIT|CLOSE|LISTEN]" -TCP state diff --git a/extensions/libct_proto_udp.c b/extensions/libct_proto_udp.c deleted file mode 100644 index 48079e0..0000000 --- a/extensions/libct_proto_udp.c +++ /dev/null @@ -1,141 +0,0 @@ -/* - * (C) 2005 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 -#include -#include -#include /* For htons */ -#include "conntrack.h" -#include -#include - -static struct option opts[] = { - {"orig-port-src", 1, 0, '1'}, - {"orig-port-dst", 1, 0, '2'}, - {"reply-port-src", 1, 0, '3'}, - {"reply-port-dst", 1, 0, '4'}, - {"mask-port-src", 1, 0, '5'}, - {"mask-port-dst", 1, 0, '6'}, - {"tuple-port-src", 1, 0, '7'}, - {"tuple-port-dst", 1, 0, '8'}, - {0, 0, 0, 0} -}; - -static void help() -{ - fprintf(stdout, "--orig-port-src original source port\n"); - fprintf(stdout, "--orig-port-dst original destination port\n"); - fprintf(stdout, "--reply-port-src reply source port\n"); - fprintf(stdout, "--reply-port-dst reply destination port\n"); - fprintf(stdout, "--mask-port-src mask source port\n"); - fprintf(stdout, "--mask-port-dst mask destination port\n"); - fprintf(stdout, "--tuple-port-src expectation tuple src port\n"); - fprintf(stdout, "--tuple-port-src expectation tuple dst port\n"); -} - -static int parse_options(char c, char *argv[], - struct nfct_tuple *orig, - struct nfct_tuple *reply, - struct nfct_tuple *exptuple, - struct nfct_tuple *mask, - union nfct_protoinfo *proto, - unsigned int *flags) -{ - switch(c) { - case '1': - if (optarg) { - orig->l4src.udp.port = htons(atoi(optarg)); - *flags |= UDP_ORIG_SPORT; - } - break; - case '2': - if (optarg) { - orig->l4dst.udp.port = htons(atoi(optarg)); - *flags |= UDP_ORIG_DPORT; - } - break; - case '3': - if (optarg) { - reply->l4src.udp.port = htons(atoi(optarg)); - *flags |= UDP_REPL_SPORT; - } - break; - case '4': - if (optarg) { - reply->l4dst.udp.port = htons(atoi(optarg)); - *flags |= UDP_REPL_DPORT; - } - break; - case '5': - if (optarg) { - mask->l4src.udp.port = htons(atoi(optarg)); - *flags |= UDP_MASK_SPORT; - } - break; - case '6': - if (optarg) { - mask->l4dst.udp.port = htons(atoi(optarg)); - *flags |= UDP_MASK_DPORT; - } - break; - case '7': - if (optarg) { - exptuple->l4src.udp.port = htons(atoi(optarg)); - *flags |= UDP_EXPTUPLE_SPORT; - } - break; - case '8': - if (optarg) { - exptuple->l4dst.udp.port = htons(atoi(optarg)); - *flags |= UDP_EXPTUPLE_DPORT; - } - - } - return 1; -} - -static int final_check(unsigned int flags, - unsigned int command, - struct nfct_tuple *orig, - struct nfct_tuple *reply) -{ - if ((flags & (UDP_ORIG_SPORT|UDP_ORIG_DPORT)) - && !(flags & (UDP_REPL_SPORT|UDP_REPL_DPORT))) { - reply->l4src.udp.port = orig->l4dst.udp.port; - reply->l4dst.udp.port = orig->l4src.udp.port; - return 1; - } else if (!(flags & (UDP_ORIG_SPORT|UDP_ORIG_DPORT)) - && (flags & (UDP_REPL_SPORT|UDP_REPL_DPORT))) { - orig->l4src.udp.port = reply->l4dst.udp.port; - orig->l4dst.udp.port = reply->l4src.udp.port; - return 1; - } - if ((flags & (UDP_ORIG_SPORT|UDP_ORIG_DPORT)) - && ((flags & (UDP_REPL_SPORT|UDP_REPL_DPORT)))) - return 1; - - return 0; -} - -static struct ctproto_handler udp = { - .name = "udp", - .protonum = IPPROTO_UDP, - .parse_opts = parse_options, - .final_check = final_check, - .help = help, - .opts = opts, - .version = VERSION, -}; - -static void __attribute__ ((constructor)) init(void); - -static void init(void) -{ - register_proto(&udp); -} diff --git a/extensions/libct_proto_udp.man b/extensions/libct_proto_udp.man deleted file mode 100644 index c67fedf..0000000 --- a/extensions/libct_proto_udp.man +++ /dev/null @@ -1,13 +0,0 @@ -This module matches on UDP-specific fields. -.TP -.BI "--orig-port-src " "PORT" -Source port in original direction -.TP -.BI "--orig-port-dst " "PORT" -Destination port in original direction -.TP -.BI "--reply-port-src " "PORT" -Source port in reply direction -.TP -.BI "--reply-port-dst " "PORT" -Destination port in reply direction diff --git a/include/Makefile.am b/include/Makefile.am deleted file mode 100644 index ef7ce45..0000000 --- a/include/Makefile.am +++ /dev/null @@ -1,2 +0,0 @@ - -noinst_HEADERS = conntrack.h linux_list.h diff --git a/include/conntrack.h b/include/conntrack.h deleted file mode 100644 index fb3b9b6..0000000 --- a/include/conntrack.h +++ /dev/null @@ -1,160 +0,0 @@ -#ifndef _CONNTRACK_H -#define _CONNTRACK_H - -#ifdef HAVE_CONFIG_H -#include "../config.h" -#endif - -#include "linux_list.h" -#include -#include - -#define PROGNAME "conntrack" - -#include -#ifndef IPPROTO_SCTP -#define IPPROTO_SCTP 132 -#endif - -enum action { - CT_NONE = 0, - - CT_LIST_BIT = 0, - CT_LIST = (1 << CT_LIST_BIT), - - CT_CREATE_BIT = 1, - CT_CREATE = (1 << CT_CREATE_BIT), - - CT_UPDATE_BIT = 2, - CT_UPDATE = (1 << CT_UPDATE_BIT), - - CT_DELETE_BIT = 3, - CT_DELETE = (1 << CT_DELETE_BIT), - - CT_GET_BIT = 4, - CT_GET = (1 << CT_GET_BIT), - - CT_FLUSH_BIT = 5, - CT_FLUSH = (1 << CT_FLUSH_BIT), - - CT_EVENT_BIT = 6, - CT_EVENT = (1 << CT_EVENT_BIT), - - CT_VERSION_BIT = 7, - CT_VERSION = (1 << CT_VERSION_BIT), - - CT_HELP_BIT = 8, - CT_HELP = (1 << CT_HELP_BIT), - - EXP_LIST_BIT = 9, - EXP_LIST = (1 << EXP_LIST_BIT), - - EXP_CREATE_BIT = 10, - EXP_CREATE = (1 << EXP_CREATE_BIT), - - EXP_DELETE_BIT = 11, - EXP_DELETE = (1 << EXP_DELETE_BIT), - - EXP_GET_BIT = 12, - EXP_GET = (1 << EXP_GET_BIT), - - EXP_FLUSH_BIT = 13, - EXP_FLUSH = (1 << EXP_FLUSH_BIT), - - EXP_EVENT_BIT = 14, - EXP_EVENT = (1 << EXP_EVENT_BIT), -}; -#define NUMBER_OF_CMD 15 - -enum options { - CT_OPT_ORIG_SRC_BIT = 0, - CT_OPT_ORIG_SRC = (1 << CT_OPT_ORIG_SRC_BIT), - - CT_OPT_ORIG_DST_BIT = 1, - CT_OPT_ORIG_DST = (1 << CT_OPT_ORIG_DST_BIT), - - CT_OPT_ORIG = (CT_OPT_ORIG_SRC | CT_OPT_ORIG_DST), - - CT_OPT_REPL_SRC_BIT = 2, - CT_OPT_REPL_SRC = (1 << CT_OPT_REPL_SRC_BIT), - - CT_OPT_REPL_DST_BIT = 3, - CT_OPT_REPL_DST = (1 << CT_OPT_REPL_DST_BIT), - - CT_OPT_REPL = (CT_OPT_REPL_SRC | CT_OPT_REPL_DST), - - CT_OPT_PROTO_BIT = 4, - CT_OPT_PROTO = (1 << CT_OPT_PROTO_BIT), - - CT_OPT_TIMEOUT_BIT = 5, - CT_OPT_TIMEOUT = (1 << CT_OPT_TIMEOUT_BIT), - - CT_OPT_STATUS_BIT = 6, - CT_OPT_STATUS = (1 << CT_OPT_STATUS_BIT), - - CT_OPT_ZERO_BIT = 7, - CT_OPT_ZERO = (1 << CT_OPT_ZERO_BIT), - - CT_OPT_EVENT_MASK_BIT = 8, - CT_OPT_EVENT_MASK = (1 << CT_OPT_EVENT_MASK_BIT), - - CT_OPT_EXP_SRC_BIT = 9, - CT_OPT_EXP_SRC = (1 << CT_OPT_EXP_SRC_BIT), - - CT_OPT_EXP_DST_BIT = 10, - CT_OPT_EXP_DST = (1 << CT_OPT_EXP_DST_BIT), - - CT_OPT_MASK_SRC_BIT = 11, - CT_OPT_MASK_SRC = (1 << CT_OPT_MASK_SRC_BIT), - - CT_OPT_MASK_DST_BIT = 12, - CT_OPT_MASK_DST = (1 << CT_OPT_MASK_DST_BIT), - - CT_OPT_NATRANGE_BIT = 13, - CT_OPT_NATRANGE = (1 << CT_OPT_NATRANGE_BIT), - - CT_OPT_MARK_BIT = 14, - CT_OPT_MARK = (1 << CT_OPT_MARK_BIT), - - CT_OPT_ID_BIT = 15, - CT_OPT_ID = (1 << CT_OPT_ID_BIT), - - CT_OPT_FAMILY_BIT = 16, - CT_OPT_FAMILY = (1 << CT_OPT_FAMILY_BIT), - - CT_OPT_MAX_BIT = CT_OPT_FAMILY_BIT -}; -#define NUMBER_OF_OPT CT_OPT_MAX_BIT+1 - -struct ctproto_handler { - struct list_head head; - - char *name; - u_int16_t protonum; - char *version; - - enum ctattr_protoinfo protoinfo_attr; - - int (*parse_opts)(char c, char *argv[], - struct nfct_tuple *orig, - struct nfct_tuple *reply, - struct nfct_tuple *exptuple, - struct nfct_tuple *mask, - union nfct_protoinfo *proto, - unsigned int *flags); - - int (*final_check)(unsigned int flags, - unsigned int command, - struct nfct_tuple *orig, - struct nfct_tuple *reply); - - void (*help)(); - - struct option *opts; - - unsigned int option_offset; -}; - -extern void register_proto(struct ctproto_handler *h); - -#endif diff --git a/include/linux_list.h b/include/linux_list.h deleted file mode 100644 index 57b56d7..0000000 --- a/include/linux_list.h +++ /dev/null @@ -1,725 +0,0 @@ -#ifndef _LINUX_LIST_H -#define _LINUX_LIST_H - -#undef offsetof -#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) - -/** - * container_of - cast a member of a structure out to the containing structure - * - * @ptr: the pointer to the member. - * @type: the type of the container struct this is embedded in. - * @member: the name of the member within the struct. - * - */ -#define container_of(ptr, type, member) ({ \ - const typeof( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) );}) - -/* - * Check at compile time that something is of a particular type. - * Always evaluates to 1 so you may use it easily in comparisons. - */ -#define typecheck(type,x) \ -({ type __dummy; \ - typeof(x) __dummy2; \ - (void)(&__dummy == &__dummy2); \ - 1; \ -}) - -#define prefetch(x) 1 - -/* empty define to make this work in userspace -HW */ -#ifndef smp_wmb -#define smp_wmb() -#endif - -/* - * These are non-NULL pointers that will result in page faults - * under normal circumstances, used to verify that nobody uses - * non-initialized list entries. - */ -#define LIST_POISON1 ((void *) 0x00100100) -#define LIST_POISON2 ((void *) 0x00200200) - -/* - * Simple doubly linked list implementation. - * - * Some of the internal functions ("__xxx") are useful when - * manipulating whole lists rather than single entries, as - * sometimes we already know the next/prev entries and we can - * generate better code by using them directly rather than - * using the generic single-entry routines. - */ - -struct list_head { - struct list_head *next, *prev; -}; - -#define LIST_HEAD_INIT(name) { &(name), &(name) } - -#define LIST_HEAD(name) \ - struct list_head name = LIST_HEAD_INIT(name) - -#define INIT_LIST_HEAD(ptr) do { \ - (ptr)->next = (ptr); (ptr)->prev = (ptr); \ -} while (0) - -/* - * Insert a new entry between two known consecutive entries. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -static inline void __list_add(struct list_head *new, - struct list_head *prev, - struct list_head *next) -{ - next->prev = new; - new->next = next; - new->prev = prev; - prev->next = new; -} - -/** - * list_add - add a new entry - * @new: new entry to be added - * @head: list head to add it after - * - * Insert a new entry after the specified head. - * This is good for implementing stacks. - */ -static inline void list_add(struct list_head *new, struct list_head *head) -{ - __list_add(new, head, head->next); -} - -/** - * list_add_tail - add a new entry - * @new: new entry to be added - * @head: list head to add it before - * - * Insert a new entry before the specified head. - * This is useful for implementing queues. - */ -static inline void list_add_tail(struct list_head *new, struct list_head *head) -{ - __list_add(new, head->prev, head); -} - -/* - * Insert a new entry between two known consecutive entries. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -static inline void __list_add_rcu(struct list_head * new, - struct list_head * prev, struct list_head * next) -{ - new->next = next; - new->prev = prev; - smp_wmb(); - next->prev = new; - prev->next = new; -} - -/** - * list_add_rcu - add a new entry to rcu-protected list - * @new: new entry to be added - * @head: list head to add it after - * - * Insert a new entry after the specified head. - * This is good for implementing stacks. - * - * The caller must take whatever precautions are necessary - * (such as holding appropriate locks) to avoid racing - * with another list-mutation primitive, such as list_add_rcu() - * or list_del_rcu(), running on this same list. - * However, it is perfectly legal to run concurrently with - * the _rcu list-traversal primitives, such as - * list_for_each_entry_rcu(). - */ -static inline void list_add_rcu(struct list_head *new, struct list_head *head) -{ - __list_add_rcu(new, head, head->next); -} - -/** - * list_add_tail_rcu - add a new entry to rcu-protected list - * @new: new entry to be added - * @head: list head to add it before - * - * Insert a new entry before the specified head. - * This is useful for implementing queues. - * - * The caller must take whatever precautions are necessary - * (such as holding appropriate locks) to avoid racing - * with another list-mutation primitive, such as list_add_tail_rcu() - * or list_del_rcu(), running on this same list. - * However, it is perfectly legal to run concurrently with - * the _rcu list-traversal primitives, such as - * list_for_each_entry_rcu(). - */ -static inline void list_add_tail_rcu(struct list_head *new, - struct list_head *head) -{ - __list_add_rcu(new, head->prev, head); -} - -/* - * Delete a list entry by making the prev/next entries - * point to each other. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -static inline void __list_del(struct list_head * prev, struct list_head * next) -{ - next->prev = prev; - prev->next = next; -} - -/** - * list_del - deletes entry from list. - * @entry: the element to delete from the list. - * Note: list_empty on entry does not return true after this, the entry is - * in an undefined state. - */ -static inline void list_del(struct list_head *entry) -{ - __list_del(entry->prev, entry->next); - entry->next = LIST_POISON1; - entry->prev = LIST_POISON2; -} - -/** - * list_del_rcu - deletes entry from list without re-initialization - * @entry: the element to delete from the list. - * - * Note: list_empty on entry does not return true after this, - * the entry is in an undefined state. It is useful for RCU based - * lockfree traversal. - * - * In particular, it means that we can not poison the forward - * pointers that may still be used for walking the list. - * - * The caller must take whatever precautions are necessary - * (such as holding appropriate locks) to avoid racing - * with another list-mutation primitive, such as list_del_rcu() - * or list_add_rcu(), running on this same list. - * However, it is perfectly legal to run concurrently with - * the _rcu list-traversal primitives, such as - * list_for_each_entry_rcu(). - * - * Note that the caller is not permitted to immediately free - * the newly deleted entry. Instead, either synchronize_kernel() - * or call_rcu() must be used to defer freeing until an RCU - * grace period has elapsed. - */ -static inline void list_del_rcu(struct list_head *entry) -{ - __list_del(entry->prev, entry->next); - entry->prev = LIST_POISON2; -} - -/** - * list_del_init - deletes entry from list and reinitialize it. - * @entry: the element to delete from the list. - */ -static inline void list_del_init(struct list_head *entry) -{ - __list_del(entry->prev, entry->next); - INIT_LIST_HEAD(entry); -} - -/** - * list_move - delete from one list and add as another's head - * @list: the entry to move - * @head: the head that will precede our entry - */ -static inline void list_move(struct list_head *list, struct list_head *head) -{ - __list_del(list->prev, list->next); - list_add(list, head); -} - -/** - * list_move_tail - delete from one list and add as another's tail - * @list: the entry to move - * @head: the head that will follow our entry - */ -static inline void list_move_tail(struct list_head *list, - struct list_head *head) -{ - __list_del(list->prev, list->next); - list_add_tail(list, head); -} - -/** - * list_empty - tests whether a list is empty - * @head: the list to test. - */ -static inline int list_empty(const struct list_head *head) -{ - return head->next == head; -} - -/** - * list_empty_careful - tests whether a list is - * empty _and_ checks that no other CPU might be - * in the process of still modifying either member - * - * NOTE: using list_empty_careful() without synchronization - * can only be safe if the only activity that can happen - * to the list entry is list_del_init(). Eg. it cannot be used - * if another CPU could re-list_add() it. - * - * @head: the list to test. - */ -static inline int list_empty_careful(const struct list_head *head) -{ - struct list_head *next = head->next; - return (next == head) && (next == head->prev); -} - -static inline void __list_splice(struct list_head *list, - struct list_head *head) -{ - struct list_head *first = list->next; - struct list_head *last = list->prev; - struct list_head *at = head->next; - - first->prev = head; - head->next = first; - - last->next = at; - at->prev = last; -} - -/** - * list_splice - join two lists - * @list: the new list to add. - * @head: the place to add it in the first list. - */ -static inline void list_splice(struct list_head *list, struct list_head *head) -{ - if (!list_empty(list)) - __list_splice(list, head); -} - -/** - * list_splice_init - join two lists and reinitialise the emptied list. - * @list: the new list to add. - * @head: the place to add it in the first list. - * - * The list at @list is reinitialised - */ -static inline void list_splice_init(struct list_head *list, - struct list_head *head) -{ - if (!list_empty(list)) { - __list_splice(list, head); - INIT_LIST_HEAD(list); - } -} - -/** - * list_entry - get the struct for this entry - * @ptr: the &struct list_head pointer. - * @type: the type of the struct this is embedded in. - * @member: the name of the list_struct within the struct. - */ -#define list_entry(ptr, type, member) \ - container_of(ptr, type, member) - -/** - * list_for_each - iterate over a list - * @pos: the &struct list_head to use as a loop counter. - * @head: the head for your list. - */ -#define list_for_each(pos, head) \ - for (pos = (head)->next, prefetch(pos->next); pos != (head); \ - pos = pos->next, prefetch(pos->next)) - -/** - * __list_for_each - iterate over a list - * @pos: the &struct list_head to use as a loop counter. - * @head: the head for your list. - * - * This variant differs from list_for_each() in that it's the - * simplest possible list iteration code, no prefetching is done. - * Use this for code that knows the list to be very short (empty - * or 1 entry) most of the time. - */ -#define __list_for_each(pos, head) \ - for (pos = (head)->next; pos != (head); pos = pos->next) - -/** - * list_for_each_prev - iterate over a list backwards - * @pos: the &struct list_head to use as a loop counter. - * @head: the head for your list. - */ -#define list_for_each_prev(pos, head) \ - for (pos = (head)->prev, prefetch(pos->prev); pos != (head); \ - pos = pos->prev, prefetch(pos->prev)) - -/** - * list_for_each_safe - iterate over a list safe against removal of list entry - * @pos: the &struct list_head to use as a loop counter. - * @n: another &struct list_head to use as temporary storage - * @head: the head for your list. - */ -#define list_for_each_safe(pos, n, head) \ - for (pos = (head)->next, n = pos->next; pos != (head); \ - pos = n, n = pos->next) - -/** - * list_for_each_entry - iterate over list of given type - * @pos: the type * to use as a loop counter. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry(pos, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member), \ - prefetch(pos->member.next); \ - &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member), \ - prefetch(pos->member.next)) - -/** - * list_for_each_entry_reverse - iterate backwards over list of given type. - * @pos: the type * to use as a loop counter. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry_reverse(pos, head, member) \ - for (pos = list_entry((head)->prev, typeof(*pos), member), \ - prefetch(pos->member.prev); \ - &pos->member != (head); \ - pos = list_entry(pos->member.prev, typeof(*pos), member), \ - prefetch(pos->member.prev)) - -/** - * list_prepare_entry - prepare a pos entry for use as a start point in - * list_for_each_entry_continue - * @pos: the type * to use as a start point - * @head: the head of the list - * @member: the name of the list_struct within the struct. - */ -#define list_prepare_entry(pos, head, member) \ - ((pos) ? : list_entry(head, typeof(*pos), member)) - -/** - * list_for_each_entry_continue - iterate over list of given type - * continuing after existing point - * @pos: the type * to use as a loop counter. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry_continue(pos, head, member) \ - for (pos = list_entry(pos->member.next, typeof(*pos), member), \ - prefetch(pos->member.next); \ - &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member), \ - prefetch(pos->member.next)) - -/** - * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry - * @pos: the type * to use as a loop counter. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry_safe(pos, n, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member), \ - n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -/** - * list_for_each_rcu - iterate over an rcu-protected list - * @pos: the &struct list_head to use as a loop counter. - * @head: the head for your list. - * - * This list-traversal primitive may safely run concurrently with - * the _rcu list-mutation primitives such as list_add_rcu() - * as long as the traversal is guarded by rcu_read_lock(). - */ -#define list_for_each_rcu(pos, head) \ - for (pos = (head)->next, prefetch(pos->next); pos != (head); \ - pos = pos->next, ({ smp_read_barrier_depends(); 0;}), prefetch(pos->next)) - -#define __list_for_each_rcu(pos, head) \ - for (pos = (head)->next; pos != (head); \ - pos = pos->next, ({ smp_read_barrier_depends(); 0;})) - -/** - * list_for_each_safe_rcu - iterate over an rcu-protected list safe - * against removal of list entry - * @pos: the &struct list_head to use as a loop counter. - * @n: another &struct list_head to use as temporary storage - * @head: the head for your list. - * - * This list-traversal primitive may safely run concurrently with - * the _rcu list-mutation primitives such as list_add_rcu() - * as long as the traversal is guarded by rcu_read_lock(). - */ -#define list_for_each_safe_rcu(pos, n, head) \ - for (pos = (head)->next, n = pos->next; pos != (head); \ - pos = n, ({ smp_read_barrier_depends(); 0;}), n = pos->next) - -/** - * list_for_each_entry_rcu - iterate over rcu list of given type - * @pos: the type * to use as a loop counter. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * This list-traversal primitive may safely run concurrently with - * the _rcu list-mutation primitives such as list_add_rcu() - * as long as the traversal is guarded by rcu_read_lock(). - */ -#define list_for_each_entry_rcu(pos, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member), \ - prefetch(pos->member.next); \ - &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member), \ - ({ smp_read_barrier_depends(); 0;}), \ - prefetch(pos->member.next)) - - -/** - * list_for_each_continue_rcu - iterate over an rcu-protected list - * continuing after existing point. - * @pos: the &struct list_head to use as a loop counter. - * @head: the head for your list. - * - * This list-traversal primitive may safely run concurrently with - * the _rcu list-mutation primitives such as list_add_rcu() - * as long as the traversal is guarded by rcu_read_lock(). - */ -#define list_for_each_continue_rcu(pos, head) \ - for ((pos) = (pos)->next, prefetch((pos)->next); (pos) != (head); \ - (pos) = (pos)->next, ({ smp_read_barrier_depends(); 0;}), prefetch((pos)->next)) - -/* - * Double linked lists with a single pointer list head. - * Mostly useful for hash tables where the two pointer list head is - * too wasteful. - * You lose the ability to access the tail in O(1). - */ - -struct hlist_head { - struct hlist_node *first; -}; - -struct hlist_node { - struct hlist_node *next, **pprev; -}; - -#define HLIST_HEAD_INIT { .first = NULL } -#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL } -#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) -#define INIT_HLIST_NODE(ptr) ((ptr)->next = NULL, (ptr)->pprev = NULL) - -static inline int hlist_unhashed(const struct hlist_node *h) -{ - return !h->pprev; -} - -static inline int hlist_empty(const struct hlist_head *h) -{ - return !h->first; -} - -static inline void __hlist_del(struct hlist_node *n) -{ - struct hlist_node *next = n->next; - struct hlist_node **pprev = n->pprev; - *pprev = next; - if (next) - next->pprev = pprev; -} - -static inline void hlist_del(struct hlist_node *n) -{ - __hlist_del(n); - n->next = LIST_POISON1; - n->pprev = LIST_POISON2; -} - -/** - * hlist_del_rcu - deletes entry from hash list without re-initialization - * @n: the element to delete from the hash list. - * - * Note: list_unhashed() on entry does not return true after this, - * the entry is in an undefined state. It is useful for RCU based - * lockfree traversal. - * - * In particular, it means that we can not poison the forward - * pointers that may still be used for walking the hash list. - * - * The caller must take whatever precautions are necessary - * (such as holding appropriate locks) to avoid racing - * with another list-mutation primitive, such as hlist_add_head_rcu() - * or hlist_del_rcu(), running on this same list. - * However, it is perfectly legal to run concurrently with - * the _rcu list-traversal primitives, such as - * hlist_for_each_entry(). - */ -static inline void hlist_del_rcu(struct hlist_node *n) -{ - __hlist_del(n); - n->pprev = LIST_POISON2; -} - -static inline void hlist_del_init(struct hlist_node *n) -{ - if (n->pprev) { - __hlist_del(n); - INIT_HLIST_NODE(n); - } -} - -#define hlist_del_rcu_init hlist_del_init - -static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) -{ - struct hlist_node *first = h->first; - n->next = first; - if (first) - first->pprev = &n->next; - h->first = n; - n->pprev = &h->first; -} - - -/** - * hlist_add_head_rcu - adds the specified element to the specified hlist, - * while permitting racing traversals. - * @n: the element to add to the hash list. - * @h: the list to add to. - * - * The caller must take whatever precautions are necessary - * (such as holding appropriate locks) to avoid racing - * with another list-mutation primitive, such as hlist_add_head_rcu() - * or hlist_del_rcu(), running on this same list. - * However, it is perfectly legal to run concurrently with - * the _rcu list-traversal primitives, such as - * hlist_for_each_entry(), but only if smp_read_barrier_depends() - * is used to prevent memory-consistency problems on Alpha CPUs. - * Regardless of the type of CPU, the list-traversal primitive - * must be guarded by rcu_read_lock(). - * - * OK, so why don't we have an hlist_for_each_entry_rcu()??? - */ -static inline void hlist_add_head_rcu(struct hlist_node *n, - struct hlist_head *h) -{ - struct hlist_node *first = h->first; - n->next = first; - n->pprev = &h->first; - smp_wmb(); - if (first) - first->pprev = &n->next; - h->first = n; -} - -/* next must be != NULL */ -static inline void hlist_add_before(struct hlist_node *n, - struct hlist_node *next) -{ - n->pprev = next->pprev; - n->next = next; - next->pprev = &n->next; - *(n->pprev) = n; -} - -static inline void hlist_add_after(struct hlist_node *n, - struct hlist_node *next) -{ - next->next = n->next; - n->next = next; - next->pprev = &n->next; - - if(next->next) - next->next->pprev = &next->next; -} - -#define hlist_entry(ptr, type, member) container_of(ptr,type,member) - -#define hlist_for_each(pos, head) \ - for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \ - pos = pos->next) - -#define hlist_for_each_safe(pos, n, head) \ - for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \ - pos = n) - -/** - * hlist_for_each_entry - iterate over list of given type - * @tpos: the type * to use as a loop counter. - * @pos: the &struct hlist_node to use as a loop counter. - * @head: the head for your list. - * @member: the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry(tpos, pos, head, member) \ - for (pos = (head)->first; \ - pos && ({ prefetch(pos->next); 1;}) && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ - pos = pos->next) - -/** - * hlist_for_each_entry_continue - iterate over a hlist continuing after existing point - * @tpos: the type * to use as a loop counter. - * @pos: the &struct hlist_node to use as a loop counter. - * @member: the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry_continue(tpos, pos, member) \ - for (pos = (pos)->next; \ - pos && ({ prefetch(pos->next); 1;}) && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ - pos = pos->next) - -/** - * hlist_for_each_entry_from - iterate over a hlist continuing from existing point - * @tpos: the type * to use as a loop counter. - * @pos: the &struct hlist_node to use as a loop counter. - * @member: the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry_from(tpos, pos, member) \ - for (; pos && ({ prefetch(pos->next); 1;}) && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ - pos = pos->next) - -/** - * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry - * @tpos: the type * to use as a loop counter. - * @pos: the &struct hlist_node to use as a loop counter. - * @n: another &struct hlist_node to use as temporary storage - * @head: the head for your list. - * @member: the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ - for (pos = (head)->first; \ - pos && ({ n = pos->next; 1; }) && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ - pos = n) - -/** - * hlist_for_each_entry_rcu - iterate over rcu list of given type - * @pos: the type * to use as a loop counter. - * @pos: the &struct hlist_node to use as a loop counter. - * @head: the head for your list. - * @member: the name of the hlist_node within the struct. - * - * This list-traversal primitive may safely run concurrently with - * the _rcu list-mutation primitives such as hlist_add_rcu() - * as long as the traversal is guarded by rcu_read_lock(). - */ -#define hlist_for_each_entry_rcu(tpos, pos, head, member) \ - for (pos = (head)->first; \ - pos && ({ prefetch(pos->next); 1;}) && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ - pos = pos->next, ({ smp_read_barrier_depends(); 0; }) ) - -#endif diff --git a/src/Makefile.am b/src/Makefile.am deleted file mode 100644 index 83cad99..0000000 --- a/src/Makefile.am +++ /dev/null @@ -1,7 +0,0 @@ -include $(top_srcdir)/Make_global.am -LIBS = @CONNTRACK_LIBS@ - -sbin_PROGRAMS = conntrack -conntrack_SOURCES = conntrack.c -conntrack_LDFLAGS = -rdynamic - diff --git a/src/conntrack.c b/src/conntrack.c deleted file mode 100644 index 30fbf69..0000000 --- a/src/conntrack.c +++ /dev/null @@ -1,1131 +0,0 @@ -/* - * (C) 2005 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Note: - * Yes, portions of this code has been stolen from iptables ;) - * Special thanks to the the Netfilter Core Team. - * Thanks to Javier de Miguel Rodriguez - * for introducing me to advanced firewalling stuff. - * - * --pablo 13/04/2005 - * - * 2005-04-16 Harald Welte : - * Add support for conntrack accounting and conntrack mark - * 2005-06-23 Harald Welte : - * Add support for expect creation - * 2005-09-24 Harald Welte : - * Remove remaints of "-A" - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef HAVE_ARPA_INET_H -#include -#endif -#include -#include -#include -#include -#include "linux_list.h" -#include "conntrack.h" -#include -#include -#include - -static const char cmdflags[NUMBER_OF_CMD] -= {'L','I','U','D','G','F','E','V','h','L','I','D','G','F','E'}; - -static const char cmd_need_param[NUMBER_OF_CMD] -= { 2, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, 0, 2, 2 }; - -static const char optflags[NUMBER_OF_OPT] -= {'s','d','r','q','p','t','u','z','e','[',']','{','}','a','m','i','f'}; - -static struct option original_opts[] = { - {"dump", 2, 0, 'L'}, - {"create", 1, 0, 'I'}, - {"delete", 1, 0, 'D'}, - {"update", 1, 0, 'U'}, - {"get", 1, 0, 'G'}, - {"flush", 1, 0, 'F'}, - {"event", 1, 0, 'E'}, - {"version", 0, 0, 'V'}, - {"help", 0, 0, 'h'}, - {"orig-src", 1, 0, 's'}, - {"orig-dst", 1, 0, 'd'}, - {"reply-src", 1, 0, 'r'}, - {"reply-dst", 1, 0, 'q'}, - {"protonum", 1, 0, 'p'}, - {"timeout", 1, 0, 't'}, - {"status", 1, 0, 'u'}, - {"zero", 0, 0, 'z'}, - {"event-mask", 1, 0, 'e'}, - {"tuple-src", 1, 0, '['}, - {"tuple-dst", 1, 0, ']'}, - {"mask-src", 1, 0, '{'}, - {"mask-dst", 1, 0, '}'}, - {"nat-range", 1, 0, 'a'}, - {"mark", 1, 0, 'm'}, - {"id", 2, 0, 'i'}, - {"family", 1, 0, 'f'}, - {0, 0, 0, 0} -}; - -#define OPTION_OFFSET 256 - -static struct nfct_handle *cth; -static struct option *opts = original_opts; -static unsigned int global_option_offset = 0; - -/* Table of legal combinations of commands and options. If any of the - * given commands make an option legal, that option is legal (applies to - * CMD_LIST and CMD_ZERO only). - * Key: - * 0 illegal - * 1 compulsory - * 2 optional - */ - -static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = -/* Well, it's better than "Re: Linux vs FreeBSD" */ -{ - /* s d r q p t u z e x y k l a m i f*/ -/*CT_LIST*/ {2,2,2,2,2,0,0,2,0,0,0,0,0,0,2,2,2}, -/*CT_CREATE*/ {2,2,2,2,1,1,1,0,0,0,0,0,0,2,2,0,0}, -/*CT_UPDATE*/ {2,2,2,2,1,2,2,0,0,0,0,0,0,0,2,2,0}, -/*CT_DELETE*/ {2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,2,0}, -/*CT_GET*/ {2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,2,0}, -/*CT_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*CT_EVENT*/ {2,2,2,2,2,0,0,0,2,0,0,0,0,0,2,0,0}, -/*VERSION*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*HELP*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*EXP_LIST*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2}, -/*EXP_CREATE*/{1,1,2,2,1,1,2,0,0,1,1,1,1,0,0,0,0}, -/*EXP_DELETE*/{1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0}, -/*EXP_GET*/ {1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0}, -/*EXP_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*EXP_EVENT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -}; - -static char *lib_dir = CONNTRACK_LIB_DIR; - -static LIST_HEAD(proto_list); - -void register_proto(struct ctproto_handler *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); -} - -static struct ctproto_handler *findproto(char *name) -{ - struct list_head *i; - struct ctproto_handler *cur = NULL, *handler = NULL; - - if (!name) - return handler; - - lib_dir = getenv("CONNTRACK_LIB_DIR"); - if (!lib_dir) - lib_dir = CONNTRACK_LIB_DIR; - - list_for_each(i, &proto_list) { - cur = (struct ctproto_handler *) i; - if (strcmp(cur->name, name) == 0) { - handler = cur; - break; - } - } - - if (!handler) { - char path[sizeof("ct_proto_.so") - + strlen(name) + strlen(lib_dir)]; - sprintf(path, "%s/ct_proto_%s.so", lib_dir, name); - if (dlopen(path, RTLD_NOW)) - handler = findproto(name); - else - fprintf(stderr, "%s\n", dlerror()); - } - - return handler; -} - -enum exittype { - OTHER_PROBLEM = 1, - PARAMETER_PROBLEM, - VERSION_PROBLEM -}; - -void extension_help(struct ctproto_handler *h) -{ - fprintf(stdout, "\n"); - fprintf(stdout, "Proto `%s' help:\n", h->name); - h->help(); -} - -void -exit_tryhelp(int status) -{ - fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n", - PROGNAME, PROGNAME); - exit(status); -} - -static void -exit_error(enum exittype status, char *msg, ...) -{ - va_list args; - - /* On error paths, make sure that we don't leak the memory - * reserved during options merging */ - if (opts != original_opts) { - free(opts); - opts = original_opts; - global_option_offset = 0; - } - va_start(args, msg); - fprintf(stderr,"%s v%s: ", PROGNAME, VERSION); - vfprintf(stderr, msg, args); - va_end(args); - fprintf(stderr, "\n"); - if (status == PARAMETER_PROBLEM) - exit_tryhelp(status); - exit(status); -} - -static void -generic_cmd_check(int command, int options) -{ - int i; - - for (i = 0; i < NUMBER_OF_CMD; i++) { - if (!(command & (1< illegal, 1 => legal, 0 => undecided. */ - - for (j = 0; j < NUMBER_OF_CMD; j++) { - if (!(command & (1<size; i++) - if (strncasecmp(str, p->parameter[i], strlen) == 0) { - *value |= p->value[i]; - ret = 1; - break; - } - - return ret; -} - -static void -parse_parameter(const char *arg, unsigned int *status, int parse_type) -{ - const char *comma; - - while ((comma = strchr(arg, ',')) != NULL) { - if (comma == arg - || !do_parse_parameter(arg, comma-arg, status, parse_type)) - exit_error(PARAMETER_PROBLEM,"Bad parameter `%s'", arg); - arg = comma+1; - } - - if (strlen(arg) == 0 - || !do_parse_parameter(arg, strlen(arg), status, parse_type)) - exit_error(PARAMETER_PROBLEM, "Bad parameter `%s'", arg); -} - -static void -add_command(unsigned int *cmd, const int newcmd, const int othercmds) -{ - if (*cmd & (~othercmds)) - exit_error(PARAMETER_PROBLEM, "Invalid commands combination\n"); - *cmd |= newcmd; -} - -unsigned int check_type(int argc, char *argv[]) -{ - char *table = NULL; - - /* Nasty bug or feature in getopt_long ? - * It seems that it behaves badly with optional arguments. - * Fortunately, I just stole the fix from iptables ;) */ - if (optarg) - return 0; - else if (optind < argc && argv[optind][0] != '-' - && argv[optind][0] != '!') - table = argv[optind++]; - - if (!table) - return 0; - - if (strncmp("expect", table, 6) == 0) - return 1; - else if (strncmp("conntrack", table, 9) == 0) - return 0; - else - exit_error(PARAMETER_PROBLEM, "unknown type `%s'\n", table); - - return 0; -} - -static void set_family(int *family, int new) -{ - if (*family == AF_UNSPEC) - *family = new; - else if (*family != new) - exit_error(PARAMETER_PROBLEM, "mismatched address family\n"); -} - -struct addr_parse { - struct in_addr addr; - struct in6_addr addr6; - unsigned int family; -}; - -int __parse_inetaddr(const char *cp, struct addr_parse *parse) -{ - if (inet_aton(cp, &parse->addr)) - return AF_INET; -#ifdef HAVE_INET_PTON_IPV6 - else if (inet_pton(AF_INET6, cp, &parse->addr6) > 0) - return AF_INET6; -#endif - - exit_error(PARAMETER_PROBLEM, "Invalid IP address `%s'.", cp); -} - -int parse_inetaddr(const char *cp, union nfct_address *address) -{ - struct addr_parse parse; - int ret; - - if ((ret = __parse_inetaddr(cp, &parse)) == AF_INET) - address->v4 = parse.addr.s_addr; - else if (ret == AF_INET6) - memcpy(address->v6, &parse.addr6, sizeof(parse.addr6)); - - return ret; -} - -/* Shamelessly stolen from libipt_DNAT ;). Ranges expected in network order. */ -static void -nat_parse(char *arg, int portok, struct nfct_nat *range) -{ - char *colon, *dash, *error; - struct addr_parse parse; - - memset(range, 0, sizeof(range)); - colon = strchr(arg, ':'); - - if (colon) { - int port; - - if (!portok) - exit_error(PARAMETER_PROBLEM, - "Need TCP or UDP with port specification"); - - port = atoi(colon+1); - if (port == 0 || port > 65535) - exit_error(PARAMETER_PROBLEM, - "Port `%s' not valid\n", colon+1); - - error = strchr(colon+1, ':'); - if (error) - exit_error(PARAMETER_PROBLEM, - "Invalid port:port syntax - use dash\n"); - - dash = strchr(colon, '-'); - if (!dash) { - range->l4min.tcp.port - = range->l4max.tcp.port - = htons(port); - } else { - int maxport; - - maxport = atoi(dash + 1); - if (maxport == 0 || maxport > 65535) - exit_error(PARAMETER_PROBLEM, - "Port `%s' not valid\n", dash+1); - if (maxport < port) - /* People are stupid. */ - exit_error(PARAMETER_PROBLEM, - "Port range `%s' funky\n", colon+1); - range->l4min.tcp.port = htons(port); - range->l4max.tcp.port = htons(maxport); - } - /* Starts with a colon? No IP info... */ - if (colon == arg) - return; - *colon = '\0'; - } - - dash = strchr(arg, '-'); - if (colon && dash && dash > colon) - dash = NULL; - - if (dash) - *dash = '\0'; - - if (__parse_inetaddr(arg, &parse) != AF_INET) - return; - - range->min_ip = parse.addr.s_addr; - if (dash) { - if (__parse_inetaddr(dash+1, &parse) != AF_INET) - return; - range->max_ip = parse.addr.s_addr; - } else - range->max_ip = parse.addr.s_addr; -} - -static void event_sighandler(int s) -{ - fprintf(stdout, "Now closing conntrack event dumping...\n"); - nfct_close(cth); - exit(0); -} - -static const char usage_commands[] = - "Commands:\n" - " -L [table] [options]\t\tList conntrack or expectation table\n" - " -G [table] parameters\t\tGet conntrack or expectation\n" - " -D [table] parameters\t\tDelete conntrack or expectation\n" - " -I [table] parameters\t\tCreate a conntrack or expectation\n" - " -U [table] parameters\t\tUpdate a conntrack\n" - " -E [table] [options]\t\tShow events\n" - " -F [table]\t\t\tFlush table\n"; - -static const char usage_tables[] = - "Tables: conntrack, expect\n"; - -static const char usage_conntrack_parameters[] = - "Conntrack parameters and options:\n" - " -a, --nat-range min_ip[-max_ip]\tNAT ip range\n" - " -m, --mark mark\t\t\tSet mark\n" - " -e, --event-mask eventmask\t\tEvent mask, eg. NEW,DESTROY\n" - " -z, --zero \t\t\t\tZero counters while listing\n" - ; - -static const char usage_expectation_parameters[] = - "Expectation parameters and options:\n" - " --tuple-src ip\tSource address in expect tuple\n" - " --tuple-dst ip\tDestination address in expect tuple\n" - " --mask-src ip\t\tSource mask address\n" - " --mask-dst ip\t\tDestination mask address\n"; - -static const char usage_parameters[] = - "Common parameters and options:\n" - " -s, --orig-src ip\t\tSource address from original direction\n" - " -d, --orig-dst ip\t\tDestination address from original direction\n" - " -r, --reply-src ip\t\tSource addres from reply direction\n" - " -q, --reply-dst ip\t\tDestination address from reply direction\n" - " -p, --protonum proto\t\tLayer 4 Protocol, eg. 'tcp'\n" - " -f, --family proto\t\tLayer 3 Protocol, eg. 'ipv6'\n" - " -t, --timeout timeout\t\tSet timeout\n" - " -u, --status status\t\tSet status, eg. ASSURED\n" - " -i, --id [id]\t\t\tShow or set conntrack ID\n" - ; - - -void usage(char *prog) { - fprintf(stdout, "Tool to manipulate conntrack and expectations. Version %s\n", VERSION); - fprintf(stdout, "Usage: %s [commands] [options]\n", prog); - - fprintf(stdout, "\n%s", usage_commands); - fprintf(stdout, "\n%s", usage_tables); - fprintf(stdout, "\n%s", usage_conntrack_parameters); - fprintf(stdout, "\n%s", usage_expectation_parameters); - fprintf(stdout, "\n%s", usage_parameters); -} - -#define CT_COMPARISON (CT_OPT_PROTO | CT_OPT_ORIG | CT_OPT_REPL | CT_OPT_MARK) - -static struct nfct_tuple orig, reply, mask; -static struct nfct_tuple exptuple; -static struct ctproto_handler *h; -static union nfct_protoinfo proto; -static struct nfct_nat range; -static struct nfct_conntrack *ct; -static struct nfct_expect *exp; -static unsigned long timeout; -static unsigned int status; -static unsigned int mark; -static unsigned int id = NFCT_ANY_ID; -static struct nfct_conntrack_compare cmp; - -int main(int argc, char *argv[]) -{ - int c; - unsigned int command = 0, options = 0; - unsigned int type = 0, event_mask = 0; - unsigned int l3flags = 0, l4flags = 0, metaflags = 0; - int res = 0; - int family = AF_UNSPEC; - struct nfct_conntrack_compare *pcmp; - - while ((c = getopt_long(argc, argv, - "L::I::U::D::G::E::F::hVs:d:r:q:p:t:u:e:a:z[:]:{:}:m:i::f:", - opts, NULL)) != -1) { - switch(c) { - case 'L': - type = check_type(argc, argv); - if (type == 0) - add_command(&command, CT_LIST, CT_NONE); - else if (type == 1) - add_command(&command, EXP_LIST, CT_NONE); - break; - case 'I': - type = check_type(argc, argv); - if (type == 0) - add_command(&command, CT_CREATE, CT_NONE); - else if (type == 1) - add_command(&command, EXP_CREATE, CT_NONE); - break; - case 'U': - type = check_type(argc, argv); - if (type == 0) - add_command(&command, CT_UPDATE, CT_NONE); - else - exit_error(PARAMETER_PROBLEM, "Can't update " - "expectations"); - break; - case 'D': - type = check_type(argc, argv); - if (type == 0) - add_command(&command, CT_DELETE, CT_NONE); - else if (type == 1) - add_command(&command, EXP_DELETE, CT_NONE); - break; - case 'G': - type = check_type(argc, argv); - if (type == 0) - add_command(&command, CT_GET, CT_NONE); - else if (type == 1) - add_command(&command, EXP_GET, CT_NONE); - break; - case 'F': - type = check_type(argc, argv); - if (type == 0) - add_command(&command, CT_FLUSH, CT_NONE); - else if (type == 1) - add_command(&command, EXP_FLUSH, CT_NONE); - break; - case 'E': - type = check_type(argc, argv); - if (type == 0) - add_command(&command, CT_EVENT, CT_NONE); - else if (type == 1) - add_command(&command, EXP_EVENT, CT_NONE); - break; - case 'V': - add_command(&command, CT_VERSION, CT_NONE); - break; - case 'h': - add_command(&command, CT_HELP, CT_NONE); - break; - case 's': - options |= CT_OPT_ORIG_SRC; - if (optarg) { - orig.l3protonum = - parse_inetaddr(optarg, &orig.src); - set_family(&family, orig.l3protonum); - if (orig.l3protonum == AF_INET) - l3flags |= IPV4_ORIG_SRC; - else if (orig.l3protonum == AF_INET6) - l3flags |= IPV6_ORIG_SRC; - } - break; - case 'd': - options |= CT_OPT_ORIG_DST; - if (optarg) { - orig.l3protonum = - parse_inetaddr(optarg, &orig.dst); - set_family(&family, orig.l3protonum); - if (orig.l3protonum == AF_INET) - l3flags |= IPV4_ORIG_DST; - else if (orig.l3protonum == AF_INET6) - l3flags |= IPV6_ORIG_DST; - } - break; - case 'r': - options |= CT_OPT_REPL_SRC; - if (optarg) { - reply.l3protonum = - parse_inetaddr(optarg, &reply.src); - set_family(&family, reply.l3protonum); - if (orig.l3protonum == AF_INET) - l3flags |= IPV4_REPL_SRC; - else if (orig.l3protonum == AF_INET6) - l3flags |= IPV6_REPL_SRC; - } - break; - case 'q': - options |= CT_OPT_REPL_DST; - if (optarg) { - reply.l3protonum = - parse_inetaddr(optarg, &reply.dst); - set_family(&family, reply.l3protonum); - if (orig.l3protonum == AF_INET) - l3flags |= IPV4_REPL_DST; - else if (orig.l3protonum == AF_INET6) - l3flags |= IPV6_REPL_DST; - } - break; - case 'p': - options |= CT_OPT_PROTO; - h = findproto(optarg); - if (!h) - exit_error(PARAMETER_PROBLEM, "proto needed\n"); - orig.protonum = h->protonum; - reply.protonum = h->protonum; - exptuple.protonum = h->protonum; - mask.protonum = h->protonum; - opts = merge_options(opts, h->opts, - &h->option_offset); - break; - case 't': - options |= CT_OPT_TIMEOUT; - if (optarg) - timeout = atol(optarg); - break; - case 'u': { - if (!optarg) - continue; - - options |= CT_OPT_STATUS; - parse_parameter(optarg, &status, PARSE_STATUS); - break; - } - case 'e': - options |= CT_OPT_EVENT_MASK; - parse_parameter(optarg, &event_mask, PARSE_EVENT); - break; - case 'z': - options |= CT_OPT_ZERO; - break; - case '{': - options |= CT_OPT_MASK_SRC; - if (optarg) { - mask.l3protonum = - parse_inetaddr(optarg, &mask.src); - set_family(&family, mask.l3protonum); - } - break; - case '}': - options |= CT_OPT_MASK_DST; - if (optarg) { - mask.l3protonum = - parse_inetaddr(optarg, &mask.dst); - set_family(&family, mask.l3protonum); - } - break; - case '[': - options |= CT_OPT_EXP_SRC; - if (optarg) { - exptuple.l3protonum = - parse_inetaddr(optarg, &exptuple.src); - set_family(&family, exptuple.l3protonum); - } - break; - case ']': - options |= CT_OPT_EXP_DST; - if (optarg) { - exptuple.l3protonum = - parse_inetaddr(optarg, &exptuple.dst); - set_family(&family, exptuple.l3protonum); - } - break; - case 'a': - options |= CT_OPT_NATRANGE; - set_family(&family, AF_INET); - nat_parse(optarg, 1, &range); - break; - case 'm': - options |= CT_OPT_MARK; - mark = atol(optarg); - metaflags |= NFCT_MARK; - break; - case 'i': { - char *s = NULL; - options |= CT_OPT_ID; - if (optarg) - break; - else if (optind < argc && argv[optind][0] != '-' - && argv[optind][0] != '!') - s = argv[optind++]; - - if (s) - id = atol(s); - break; - } - case 'f': - options |= CT_OPT_FAMILY; - if (strncmp(optarg, "ipv4", strlen("ipv4")) == 0) - set_family(&family, AF_INET); - else if (strncmp(optarg, "ipv6", strlen("ipv6")) == 0) - set_family(&family, AF_INET6); - else - exit_error(PARAMETER_PROBLEM, "Unknown " - "protocol family\n"); - break; - default: - if (h && h->parse_opts - &&!h->parse_opts(c - h->option_offset, argv, &orig, - &reply, &exptuple, &mask, &proto, - &l4flags)) - exit_error(PARAMETER_PROBLEM, "parse error\n"); - - /* Unknown argument... */ - if (!h) { - usage(argv[0]); - exit_error(PARAMETER_PROBLEM, "Missing " - "arguments...\n"); - } - break; - } - } - - /* default family */ - if (family == AF_UNSPEC) - family = AF_INET; - - generic_cmd_check(command, options); - generic_opt_check(command, options); - - if (!(command & CT_HELP) - && h && h->final_check - && !h->final_check(l4flags, command, &orig, &reply)) { - usage(argv[0]); - extension_help(h); - exit_error(PARAMETER_PROBLEM, "Missing protocol arguments!\n"); - } - - switch(command) { - - case CT_LIST: - cth = nfct_open(CONNTRACK, 0); - if (!cth) - exit_error(OTHER_PROBLEM, "Can't open handler"); - - if (options & CT_COMPARISON) { - - if (options & CT_OPT_ZERO) - exit_error(PARAMETER_PROBLEM, "Can't use -z " - "with filtering parameters"); - - ct = nfct_conntrack_alloc(&orig, &reply, timeout, - &proto, status, mark, id, - NULL); - if (!ct) - exit_error(OTHER_PROBLEM, "Not enough memory"); - - cmp.ct = ct; - cmp.flags = metaflags; - cmp.l3flags = l3flags; - cmp.l4flags = l4flags; - pcmp = &cmp; - } - - if (options & CT_OPT_ID) - nfct_register_callback(cth, - nfct_default_conntrack_display_id, - (void *) pcmp); - else - nfct_register_callback(cth, - nfct_default_conntrack_display, - (void *) pcmp); - - if (options & CT_OPT_ZERO) - res = - nfct_dump_conntrack_table_reset_counters(cth, family); - else - res = nfct_dump_conntrack_table(cth, family); - nfct_close(cth); - break; - - case EXP_LIST: - cth = nfct_open(EXPECT, 0); - if (!cth) - exit_error(OTHER_PROBLEM, "Can't open handler"); - if (options & CT_OPT_ID) - nfct_register_callback(cth, - nfct_default_expect_display_id, - NULL); - else - nfct_register_callback(cth, - nfct_default_expect_display, - NULL); - res = nfct_dump_expect_list(cth, family); - nfct_close(cth); - break; - - case CT_CREATE: - if ((options & CT_OPT_ORIG) - && !(options & CT_OPT_REPL)) { - reply.l3protonum = orig.l3protonum; - memcpy(&reply.src, &orig.dst, sizeof(reply.src)); - memcpy(&reply.dst, &orig.src, sizeof(reply.dst)); - } else if (!(options & CT_OPT_ORIG) - && (options & CT_OPT_REPL)) { - orig.l3protonum = reply.l3protonum; - memcpy(&orig.src, &reply.dst, sizeof(orig.src)); - memcpy(&orig.dst, &reply.src, sizeof(orig.dst)); - } - if (options & CT_OPT_NATRANGE) - ct = nfct_conntrack_alloc(&orig, &reply, timeout, - &proto, status, mark, id, - &range); - else - ct = nfct_conntrack_alloc(&orig, &reply, timeout, - &proto, status, mark, id, - NULL); - if (!ct) - exit_error(OTHER_PROBLEM, "Not Enough memory"); - - cth = nfct_open(CONNTRACK, 0); - if (!cth) { - nfct_conntrack_free(ct); - exit_error(OTHER_PROBLEM, "Can't open handler"); - } - res = nfct_create_conntrack(cth, ct); - nfct_close(cth); - nfct_conntrack_free(ct); - break; - - case EXP_CREATE: - if (options & CT_OPT_ORIG) - exp = nfct_expect_alloc(&orig, &exptuple, - &mask, timeout, id); - else if (options & CT_OPT_REPL) - exp = nfct_expect_alloc(&reply, &exptuple, - &mask, timeout, id); - if (!exp) - exit_error(OTHER_PROBLEM, "Not enough memory"); - - cth = nfct_open(EXPECT, 0); - if (!cth) { - nfct_expect_free(exp); - exit_error(OTHER_PROBLEM, "Can't open handler"); - } - res = nfct_create_expectation(cth, exp); - nfct_expect_free(exp); - nfct_close(cth); - break; - - case CT_UPDATE: - if ((options & CT_OPT_ORIG) - && !(options & CT_OPT_REPL)) { - reply.l3protonum = orig.l3protonum; - memcpy(&reply.src, &orig.dst, sizeof(reply.src)); - memcpy(&reply.dst, &orig.src, sizeof(reply.dst)); - } else if (!(options & CT_OPT_ORIG) - && (options & CT_OPT_REPL)) { - orig.l3protonum = reply.l3protonum; - memcpy(&orig.src, &reply.dst, sizeof(orig.src)); - memcpy(&orig.dst, &reply.src, sizeof(orig.dst)); - } - ct = nfct_conntrack_alloc(&orig, &reply, timeout, - &proto, status, mark, id, - NULL); - if (!ct) - exit_error(OTHER_PROBLEM, "Not enough memory"); - - cth = nfct_open(CONNTRACK, 0); - if (!cth) { - nfct_conntrack_free(ct); - exit_error(OTHER_PROBLEM, "Can't open handler"); - } - res = nfct_update_conntrack(cth, ct); - nfct_conntrack_free(ct); - nfct_close(cth); - break; - - case CT_DELETE: - if (!(options & CT_OPT_ORIG) && !(options & CT_OPT_REPL)) - exit_error(PARAMETER_PROBLEM, "Can't kill conntracks " - "just by its ID"); - cth = nfct_open(CONNTRACK, 0); - if (!cth) - exit_error(OTHER_PROBLEM, "Can't open handler"); - if (options & CT_OPT_ORIG) - res = nfct_delete_conntrack(cth, &orig, - NFCT_DIR_ORIGINAL, - id); - else if (options & CT_OPT_REPL) - res = nfct_delete_conntrack(cth, &reply, - NFCT_DIR_REPLY, - id); - nfct_close(cth); - break; - - case EXP_DELETE: - cth = nfct_open(EXPECT, 0); - if (!cth) - exit_error(OTHER_PROBLEM, "Can't open handler"); - if (options & CT_OPT_ORIG) - res = nfct_delete_expectation(cth, &orig, id); - else if (options & CT_OPT_REPL) - res = nfct_delete_expectation(cth, &reply, id); - nfct_close(cth); - break; - - case CT_GET: - cth = nfct_open(CONNTRACK, 0); - if (!cth) - exit_error(OTHER_PROBLEM, "Can't open handler"); - nfct_register_callback(cth, nfct_default_conntrack_display, - NULL); - if (options & CT_OPT_ORIG) - res = nfct_get_conntrack(cth, &orig, - NFCT_DIR_ORIGINAL, id); - else if (options & CT_OPT_REPL) - res = nfct_get_conntrack(cth, &reply, - NFCT_DIR_REPLY, id); - nfct_close(cth); - break; - - case EXP_GET: - cth = nfct_open(EXPECT, 0); - if (!cth) - exit_error(OTHER_PROBLEM, "Can't open handler"); - nfct_register_callback(cth, nfct_default_expect_display, - NULL); - if (options & CT_OPT_ORIG) - res = nfct_get_expectation(cth, &orig, id); - else if (options & CT_OPT_REPL) - res = nfct_get_expectation(cth, &reply, id); - nfct_close(cth); - break; - - case CT_FLUSH: - cth = nfct_open(CONNTRACK, 0); - if (!cth) - exit_error(OTHER_PROBLEM, "Can't open handler"); - res = nfct_flush_conntrack_table(cth, AF_INET); - nfct_close(cth); - break; - - case EXP_FLUSH: - cth = nfct_open(EXPECT, 0); - if (!cth) - exit_error(OTHER_PROBLEM, "Can't open handler"); - res = nfct_flush_expectation_table(cth, AF_INET); - nfct_close(cth); - break; - - case CT_EVENT: - if (options & CT_OPT_EVENT_MASK) - cth = nfct_open(CONNTRACK, event_mask); - else - cth = nfct_open(CONNTRACK, NFCT_ALL_CT_GROUPS); - - if (!cth) - exit_error(OTHER_PROBLEM, "Can't open handler"); - signal(SIGINT, event_sighandler); - - if (options & CT_COMPARISON) { - ct = nfct_conntrack_alloc(&orig, &reply, timeout, - &proto, status, mark, id, - NULL); - if (!ct) - exit_error(OTHER_PROBLEM, "Not enough memory"); - - cmp.ct = ct; - cmp.flags = metaflags; - cmp.l3flags = l3flags; - cmp.l4flags = l4flags; - pcmp = &cmp; - } - - nfct_register_callback(cth, - nfct_default_conntrack_event_display, - (void *) pcmp); - res = nfct_event_conntrack(cth); - nfct_close(cth); - break; - - case EXP_EVENT: - cth = nfct_open(EXPECT, NF_NETLINK_CONNTRACK_EXP_NEW); - if (!cth) - exit_error(OTHER_PROBLEM, "Can't open handler"); - signal(SIGINT, event_sighandler); - nfct_register_callback(cth, nfct_default_expect_display, - NULL); - res = nfct_event_expectation(cth); - nfct_close(cth); - break; - - case CT_VERSION: - fprintf(stdout, "%s v%s\n", PROGNAME, VERSION); - break; - case CT_HELP: - usage(argv[0]); - if (options & CT_OPT_PROTO) - extension_help(h); - break; - default: - usage(argv[0]); - break; - } - - if (opts != original_opts) { - free(opts); - opts = original_opts; - global_option_offset = 0; - } - - if (res < 0) { - fprintf(stderr, "Operation failed: %s\n", err2str(res, command)); - exit(OTHER_PROBLEM); - } - - return 0; -} diff --git a/test.sh b/test.sh deleted file mode 100644 index 4694236..0000000 --- a/test.sh +++ /dev/null @@ -1,110 +0,0 @@ -CONNTRACK=conntrack - -SRC=1.1.1.1 -DST=2.2.2.2 -SPORT=2005 -DPORT=21 - -case $1 in - dump) - echo "Dumping conntrack table" - $CONNTRACK -L - ;; - flush) - echo "Flushing conntrack table" - $CONNTRACK -F - ;; - new) - echo "creating a new conntrack" - $CONNTRACK -I --orig-src $SRC --orig-dst $DST \ - --reply-src $DST --reply-dst $SRC -p tcp \ - --orig-port-src $SPORT --orig-port-dst $DPORT \ - --reply-port-src $DPORT --reply-port-dst $SPORT \ - --state LISTEN -u SEEN_REPLY -t 50 - ;; - new-simple) - echo "creating a new conntrack (simplified)" - $CONNTRACK -I --orig-src $SRC --orig-dst $DST \ - -p tcp --orig-port-src $SPORT --orig-port-dst $DPORT \ - --state LISTEN -u SEEN_REPLY -t 50 - ;; - new-nat) - echo "creating a new conntrack (NAT)" - $CONNTRACK -I --orig-src $SRC --orig-dst $DST \ - -p tcp --orig-port-src $SPORT --orig-port-dst $DPORT \ - --state LISTEN -u SEEN_REPLY,SRC_NAT -t 50 -a 8.8.8.8 - ;; - get) - echo "getting a conntrack" - $CONNTRACK -G --orig-src $SRC --orig-dst $DST \ - -p tcp --orig-port-src $SPORT --orig-port-dst $DPORT \ - --reply-port-src $DPORT --reply-port-dst $SPORT - ;; - change) - echo "change a conntrack" - $CONNTRACK -U --orig-src $SRC --orig-dst $DST \ - --reply-src $DST --reply-dst $SRC -p tcp \ - --orig-port-src $SPORT --orig-port-dst $DPORT \ - --reply-port-src $DPORT --reply-port-dst $SPORT \ - --state TIME_WAIT -u ASSURED,SEEN_REPLY -t 500 - ;; - delete) - $CONNTRACK -D --orig-src $SRC --orig-dst $DST \ - -p tcp --orig-port-src $SPORT --orig-port-dst $DPORT - ;; - output) - proc=$(cat /proc/net/ip_conntrack | wc -l) - netl=$($CONNTRACK -L | wc -l) - count=$(cat /proc/sys/net/ipv4/netfilter/ip_conntrack_count) - if [ $proc -ne $netl ]; then - echo "proc is $proc and netl is $netl and count is $count" - else - if [ $proc -ne $count ]; then - echo "proc is $proc and netl is $netl and count is $count" - else - echo "now $proc" - fi - fi - ;; - dump-expect) - $CONNTRACK -L expect - ;; - flush-expect) - $CONNTRACK -F expect - ;; - create-expect) - # requires modprobe ip_conntrack_ftp - $CONNTRACK -I expect --orig-src $SRC --orig-dst $DST \ - --tuple-src 4.4.4.4 --tuple-dst 5.5.5.5 \ - --mask-src 255.255.255.0 --mask-dst 255.255.255.255 \ - -p tcp --orig-port-src $SPORT --orig-port-dst $DPORT \ - -t 200 --tuple-port-src 10 --tuple-port-dst 300 \ - --mask-port-src 10 --mask-port-dst 300 - ;; - get-expect) - $CONNTRACK -G expect --orig-src 4.4.4.4 --orig-dst 5.5.5.5 \ - --p tcp --orig-port-src 0 --orig-port-dst 0 \ - --mask-port-src 10 --mask-port-dst 11 - ;; - delete-expect) - $CONNTRACK -D expect --orig-src 4.4.4.4 \ - --orig-dst 5.5.5.5 -p tcp --orig-port-src 0 \ - --orig-port-dst 0 --mask-port-src 10 --mask-port-dst 11 - ;; - *) - echo "Usage: $0 [dump" - echo " |new" - echo " |new-simple" - echo " |new-nat" - echo " |get" - echo " |change" - echo " |delete" - echo " |output" - echo " |flush" - echo " |dump-expect" - echo " |flush-expect" - echo " |create-expect" - echo " |get-expect" - echo " |delete-expect]" - ;; -esac -- cgit v1.2.3 From 5eb3bc6d5594fccfff26329a26225f999e971652 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Mon, 16 Apr 2007 19:08:42 +0000 Subject: first step forward to merge conntrackd and conntrack into the same building chain --- AUTHORS | 1 + CHANGELOG | 184 ++++ CONTRIBUTORS | 3 + ChangeLog | 243 +++++ INSTALL | 199 ++++ Make_global.am | 1 + Makefile.am | 21 + TODO | 18 + autogen.sh | 18 + cli/ChangeLog | 243 ----- cli/conntrack.8 | 142 --- cli/extensions/Makefile.am | 16 - cli/extensions/libct_proto_icmp.c | 108 -- cli/extensions/libct_proto_icmp.man | 10 - cli/extensions/libct_proto_sctp.c | 164 --- cli/extensions/libct_proto_tcp.c | 180 ---- cli/extensions/libct_proto_tcp.man | 16 - cli/extensions/libct_proto_udp.c | 141 --- cli/extensions/libct_proto_udp.man | 13 - cli/include/conntrack.h | 160 --- cli/src/conntrack.c | 1131 -------------------- cli/test.sh | 110 -- configure.in | 106 ++ conntrack.8 | 142 +++ daemon/AUTHORS | 1 - daemon/CHANGELOG | 184 ---- daemon/CONTRIBUTORS | 3 - daemon/INSTALL | 199 ---- daemon/Make_global.am | 1 - daemon/Makefile.am | 21 - daemon/TODO | 18 - daemon/autogen.sh | 18 - daemon/configure.in | 106 -- daemon/examples/Makefile.am | 1 - daemon/examples/debian.conntrackd.init.d | 48 - daemon/examples/stats/Makefile.am | 1 - daemon/examples/stats/conntrackd.conf | 69 -- daemon/examples/sync/Makefile.am | 1 - daemon/examples/sync/nack/Makefile.am | 2 - daemon/examples/sync/nack/README | 1 - daemon/examples/sync/nack/node1/Makefile.am | 1 - daemon/examples/sync/nack/node1/conntrackd.conf | 125 --- daemon/examples/sync/nack/node1/keepalived.conf | 38 - daemon/examples/sync/nack/node2/Makefile.am | 1 - daemon/examples/sync/nack/node2/conntrackd.conf | 124 --- daemon/examples/sync/nack/node2/keepalived.conf | 38 - daemon/examples/sync/nack/script_backup.sh | 3 - daemon/examples/sync/nack/script_master.sh | 5 - daemon/examples/sync/persistent/Makefile.am | 2 - daemon/examples/sync/persistent/README | 1 - daemon/examples/sync/persistent/node1/Makefile.am | 1 - .../examples/sync/persistent/node1/conntrackd.conf | 130 --- .../examples/sync/persistent/node1/keepalived.conf | 38 - daemon/examples/sync/persistent/node2/Makefile.am | 1 - .../examples/sync/persistent/node2/conntrackd.conf | 130 --- .../examples/sync/persistent/node2/keepalived.conf | 38 - daemon/examples/sync/persistent/script_backup.sh | 3 - daemon/examples/sync/persistent/script_master.sh | 4 - daemon/include/Makefile.am | 5 - daemon/include/alarm.h | 13 - daemon/include/buffer.h | 32 - daemon/include/cache.h | 92 -- daemon/include/conntrackd.h | 174 --- daemon/include/debug.h | 53 - daemon/include/hash.h | 47 - daemon/include/ignore.h | 12 - daemon/include/jhash.h | 146 --- daemon/include/linux_list.h | 725 ------------- daemon/include/local.h | 29 - daemon/include/log.h | 10 - daemon/include/mcast.h | 48 - daemon/include/network.h | 34 - daemon/include/slist.h | 41 - daemon/include/state_helper.h | 20 - daemon/include/sync.h | 23 - daemon/include/us-conntrack.h | 13 - daemon/src/Makefile.am | 22 - daemon/src/alarm.c | 141 --- daemon/src/buffer.c | 136 --- daemon/src/cache.c | 446 -------- daemon/src/cache_iterators.c | 229 ---- daemon/src/cache_lifetime.c | 65 -- daemon/src/cache_timer.c | 72 -- daemon/src/checksum.c | 32 - daemon/src/hash.c | 199 ---- daemon/src/ignore_pool.c | 136 --- daemon/src/local.c | 159 --- daemon/src/lock.c | 32 - daemon/src/log.c | 57 - daemon/src/main.c | 302 ------ daemon/src/mcast.c | 287 ----- daemon/src/netlink.c | 326 ------ daemon/src/network.c | 282 ----- daemon/src/proxy.c | 124 --- daemon/src/read_config_lex.l | 125 --- daemon/src/read_config_yy.y | 550 ---------- daemon/src/run.c | 227 ---- daemon/src/state_helper.c | 44 - daemon/src/state_helper_tcp.c | 35 - daemon/src/stats-mode.c | 151 --- daemon/src/sync-mode.c | 416 ------- daemon/src/sync-nack.c | 309 ------ daemon/src/sync-notrack.c | 127 --- daemon/src/traffic_stats.c | 54 - examples/Makefile.am | 1 + examples/debian.conntrackd.init.d | 48 + examples/stats/Makefile.am | 1 + examples/stats/conntrackd.conf | 69 ++ examples/sync/Makefile.am | 1 + examples/sync/nack/Makefile.am | 2 + examples/sync/nack/README | 1 + examples/sync/nack/node1/Makefile.am | 1 + examples/sync/nack/node1/conntrackd.conf | 125 +++ examples/sync/nack/node1/keepalived.conf | 38 + examples/sync/nack/node2/Makefile.am | 1 + examples/sync/nack/node2/conntrackd.conf | 124 +++ examples/sync/nack/node2/keepalived.conf | 38 + examples/sync/nack/script_backup.sh | 3 + examples/sync/nack/script_master.sh | 5 + examples/sync/persistent/Makefile.am | 2 + examples/sync/persistent/README | 1 + examples/sync/persistent/node1/Makefile.am | 1 + examples/sync/persistent/node1/conntrackd.conf | 130 +++ examples/sync/persistent/node1/keepalived.conf | 38 + examples/sync/persistent/node2/Makefile.am | 1 + examples/sync/persistent/node2/conntrackd.conf | 130 +++ examples/sync/persistent/node2/keepalived.conf | 38 + examples/sync/persistent/script_backup.sh | 3 + examples/sync/persistent/script_master.sh | 4 + extensions/Makefile.am | 16 + extensions/libct_proto_icmp.c | 108 ++ extensions/libct_proto_icmp.man | 10 + extensions/libct_proto_sctp.c | 164 +++ extensions/libct_proto_tcp.c | 180 ++++ extensions/libct_proto_tcp.man | 16 + extensions/libct_proto_udp.c | 141 +++ extensions/libct_proto_udp.man | 13 + include/Makefile.am | 5 + include/alarm.h | 13 + include/buffer.h | 32 + include/cache.h | 92 ++ include/conntrack.h | 160 +++ include/conntrackd.h | 174 +++ include/debug.h | 53 + include/hash.h | 47 + include/ignore.h | 12 + include/jhash.h | 146 +++ include/linux_list.h | 725 +++++++++++++ include/local.h | 29 + include/log.h | 10 + include/mcast.h | 48 + include/network.h | 34 + include/slist.h | 41 + include/state_helper.h | 20 + include/sync.h | 23 + include/us-conntrack.h | 13 + src/Makefile.am | 26 + src/alarm.c | 141 +++ src/buffer.c | 136 +++ src/cache.c | 446 ++++++++ src/cache_iterators.c | 229 ++++ src/cache_lifetime.c | 65 ++ src/cache_timer.c | 72 ++ src/checksum.c | 32 + src/conntrack.c | 1131 ++++++++++++++++++++ src/hash.c | 199 ++++ src/ignore_pool.c | 136 +++ src/local.c | 159 +++ src/lock.c | 32 + src/log.c | 57 + src/main.c | 302 ++++++ src/mcast.c | 287 +++++ src/netlink.c | 326 ++++++ src/network.c | 282 +++++ src/proxy.c | 124 +++ src/read_config_lex.l | 125 +++ src/read_config_yy.y | 550 ++++++++++ src/run.c | 227 ++++ src/state_helper.c | 44 + src/state_helper_tcp.c | 35 + src/stats-mode.c | 151 +++ src/sync-mode.c | 416 +++++++ src/sync-nack.c | 309 ++++++ src/sync-notrack.c | 127 +++ src/traffic_stats.c | 54 + test.sh | 110 ++ 186 files changed, 10397 insertions(+), 10393 deletions(-) create mode 100644 AUTHORS create mode 100644 CHANGELOG create mode 100644 CONTRIBUTORS create mode 100644 ChangeLog create mode 100644 INSTALL create mode 100644 Make_global.am create mode 100644 Makefile.am create mode 100644 TODO create mode 100755 autogen.sh delete mode 100644 cli/ChangeLog delete mode 100644 cli/conntrack.8 delete mode 100644 cli/extensions/Makefile.am delete mode 100644 cli/extensions/libct_proto_icmp.c delete mode 100644 cli/extensions/libct_proto_icmp.man delete mode 100644 cli/extensions/libct_proto_sctp.c delete mode 100644 cli/extensions/libct_proto_tcp.c delete mode 100644 cli/extensions/libct_proto_tcp.man delete mode 100644 cli/extensions/libct_proto_udp.c delete mode 100644 cli/extensions/libct_proto_udp.man delete mode 100644 cli/include/conntrack.h delete mode 100644 cli/src/conntrack.c delete mode 100644 cli/test.sh create mode 100644 configure.in create mode 100644 conntrack.8 delete mode 100644 daemon/AUTHORS delete mode 100644 daemon/CHANGELOG delete mode 100644 daemon/CONTRIBUTORS delete mode 100644 daemon/INSTALL delete mode 100644 daemon/Make_global.am delete mode 100644 daemon/Makefile.am delete mode 100644 daemon/TODO delete mode 100755 daemon/autogen.sh delete mode 100644 daemon/configure.in delete mode 100644 daemon/examples/Makefile.am delete mode 100644 daemon/examples/debian.conntrackd.init.d delete mode 100644 daemon/examples/stats/Makefile.am delete mode 100644 daemon/examples/stats/conntrackd.conf delete mode 100644 daemon/examples/sync/Makefile.am delete mode 100644 daemon/examples/sync/nack/Makefile.am delete mode 100644 daemon/examples/sync/nack/README delete mode 100644 daemon/examples/sync/nack/node1/Makefile.am delete mode 100644 daemon/examples/sync/nack/node1/conntrackd.conf delete mode 100644 daemon/examples/sync/nack/node1/keepalived.conf delete mode 100644 daemon/examples/sync/nack/node2/Makefile.am delete mode 100644 daemon/examples/sync/nack/node2/conntrackd.conf delete mode 100644 daemon/examples/sync/nack/node2/keepalived.conf delete mode 100755 daemon/examples/sync/nack/script_backup.sh delete mode 100755 daemon/examples/sync/nack/script_master.sh delete mode 100644 daemon/examples/sync/persistent/Makefile.am delete mode 100644 daemon/examples/sync/persistent/README delete mode 100644 daemon/examples/sync/persistent/node1/Makefile.am delete mode 100644 daemon/examples/sync/persistent/node1/conntrackd.conf delete mode 100644 daemon/examples/sync/persistent/node1/keepalived.conf delete mode 100644 daemon/examples/sync/persistent/node2/Makefile.am delete mode 100644 daemon/examples/sync/persistent/node2/conntrackd.conf delete mode 100644 daemon/examples/sync/persistent/node2/keepalived.conf delete mode 100755 daemon/examples/sync/persistent/script_backup.sh delete mode 100755 daemon/examples/sync/persistent/script_master.sh delete mode 100644 daemon/include/Makefile.am delete mode 100644 daemon/include/alarm.h delete mode 100644 daemon/include/buffer.h delete mode 100644 daemon/include/cache.h delete mode 100644 daemon/include/conntrackd.h delete mode 100644 daemon/include/debug.h delete mode 100644 daemon/include/hash.h delete mode 100644 daemon/include/ignore.h delete mode 100644 daemon/include/jhash.h delete mode 100644 daemon/include/linux_list.h delete mode 100644 daemon/include/local.h delete mode 100644 daemon/include/log.h delete mode 100644 daemon/include/mcast.h delete mode 100644 daemon/include/network.h delete mode 100644 daemon/include/slist.h delete mode 100644 daemon/include/state_helper.h delete mode 100644 daemon/include/sync.h delete mode 100644 daemon/include/us-conntrack.h delete mode 100644 daemon/src/Makefile.am delete mode 100644 daemon/src/alarm.c delete mode 100644 daemon/src/buffer.c delete mode 100644 daemon/src/cache.c delete mode 100644 daemon/src/cache_iterators.c delete mode 100644 daemon/src/cache_lifetime.c delete mode 100644 daemon/src/cache_timer.c delete mode 100644 daemon/src/checksum.c delete mode 100644 daemon/src/hash.c delete mode 100644 daemon/src/ignore_pool.c delete mode 100644 daemon/src/local.c delete mode 100644 daemon/src/lock.c delete mode 100644 daemon/src/log.c delete mode 100644 daemon/src/main.c delete mode 100644 daemon/src/mcast.c delete mode 100644 daemon/src/netlink.c delete mode 100644 daemon/src/network.c delete mode 100644 daemon/src/proxy.c delete mode 100644 daemon/src/read_config_lex.l delete mode 100644 daemon/src/read_config_yy.y delete mode 100644 daemon/src/run.c delete mode 100644 daemon/src/state_helper.c delete mode 100644 daemon/src/state_helper_tcp.c delete mode 100644 daemon/src/stats-mode.c delete mode 100644 daemon/src/sync-mode.c delete mode 100644 daemon/src/sync-nack.c delete mode 100644 daemon/src/sync-notrack.c delete mode 100644 daemon/src/traffic_stats.c create mode 100644 examples/Makefile.am create mode 100644 examples/debian.conntrackd.init.d create mode 100644 examples/stats/Makefile.am create mode 100644 examples/stats/conntrackd.conf create mode 100644 examples/sync/Makefile.am create mode 100644 examples/sync/nack/Makefile.am create mode 100644 examples/sync/nack/README create mode 100644 examples/sync/nack/node1/Makefile.am create mode 100644 examples/sync/nack/node1/conntrackd.conf create mode 100644 examples/sync/nack/node1/keepalived.conf create mode 100644 examples/sync/nack/node2/Makefile.am create mode 100644 examples/sync/nack/node2/conntrackd.conf create mode 100644 examples/sync/nack/node2/keepalived.conf create mode 100755 examples/sync/nack/script_backup.sh create mode 100755 examples/sync/nack/script_master.sh create mode 100644 examples/sync/persistent/Makefile.am create mode 100644 examples/sync/persistent/README create mode 100644 examples/sync/persistent/node1/Makefile.am create mode 100644 examples/sync/persistent/node1/conntrackd.conf create mode 100644 examples/sync/persistent/node1/keepalived.conf create mode 100644 examples/sync/persistent/node2/Makefile.am create mode 100644 examples/sync/persistent/node2/conntrackd.conf create mode 100644 examples/sync/persistent/node2/keepalived.conf create mode 100755 examples/sync/persistent/script_backup.sh create mode 100755 examples/sync/persistent/script_master.sh create mode 100644 extensions/Makefile.am create mode 100644 extensions/libct_proto_icmp.c create mode 100644 extensions/libct_proto_icmp.man create mode 100644 extensions/libct_proto_sctp.c create mode 100644 extensions/libct_proto_tcp.c create mode 100644 extensions/libct_proto_tcp.man create mode 100644 extensions/libct_proto_udp.c create mode 100644 extensions/libct_proto_udp.man create mode 100644 include/Makefile.am create mode 100644 include/alarm.h create mode 100644 include/buffer.h create mode 100644 include/cache.h create mode 100644 include/conntrack.h create mode 100644 include/conntrackd.h create mode 100644 include/debug.h create mode 100644 include/hash.h create mode 100644 include/ignore.h create mode 100644 include/jhash.h create mode 100644 include/linux_list.h create mode 100644 include/local.h create mode 100644 include/log.h create mode 100644 include/mcast.h create mode 100644 include/network.h create mode 100644 include/slist.h create mode 100644 include/state_helper.h create mode 100644 include/sync.h create mode 100644 include/us-conntrack.h create mode 100644 src/Makefile.am create mode 100644 src/alarm.c create mode 100644 src/buffer.c create mode 100644 src/cache.c create mode 100644 src/cache_iterators.c create mode 100644 src/cache_lifetime.c create mode 100644 src/cache_timer.c create mode 100644 src/checksum.c create mode 100644 src/conntrack.c create mode 100644 src/hash.c create mode 100644 src/ignore_pool.c create mode 100644 src/local.c create mode 100644 src/lock.c create mode 100644 src/log.c create mode 100644 src/main.c create mode 100644 src/mcast.c create mode 100644 src/netlink.c create mode 100644 src/network.c create mode 100644 src/proxy.c create mode 100644 src/read_config_lex.l create mode 100644 src/read_config_yy.y create mode 100644 src/run.c create mode 100644 src/state_helper.c create mode 100644 src/state_helper_tcp.c create mode 100644 src/stats-mode.c create mode 100644 src/sync-mode.c create mode 100644 src/sync-nack.c create mode 100644 src/sync-notrack.c create mode 100644 src/traffic_stats.c create mode 100644 test.sh (limited to 'src') diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..e6c2f6b --- /dev/null +++ b/AUTHORS @@ -0,0 +1 @@ +Pablo Neira Ayuso diff --git a/CHANGELOG b/CHANGELOG new file mode 100644 index 0000000..afab61d --- /dev/null +++ b/CHANGELOG @@ -0,0 +1,184 @@ +version 0.9.3 (yet unreleased) +------------------------------ +o fix commit of confirmed expectations (reported by Nishit Shah) +o fix double increment of counters in cache_update_force() (Niko Tyni) +o nl_dump_handler must return NFCT_CB_CONTINUE (Niko Tyni) +o initialize buffer in nl_event_handler() and nl_dump_handler() (Niko Tyni) +o CacheCommit value can be set via conntrackd.conf for the NACK approach +o fix leaks in the hashtable/cache flush path (Niko Tyni) +o fix leak if a connection already exists in the cache (Niko Tyni) +o introduce a new header that encapsulates netlink messages +o remove all '_entry' tail from all functions in cache.c +o split cache.c: move cache iterators to file cache_iterators.c +o fix inconsistencies in the cache API related to counters +o cleanup 'usage' message +o fix typo in examples/sync/nack/node1/conntrackd.conf +o introduce message checksumming as described in RFC1071 (enabled by default) +o major cleanups in the synchronization code +o just warn once that the maximum netlink socket buffer has been reached +o fix ignore conntrack entries by IP and introduce ignore pool abstraction layer +o introduce netlink socket buffer overrun handler +o constification of hash, compare and hashtable_test functions in hash.c +o introduce ACKnowledgement mechanisms to reduce the size of the resend queue +o remove OK messages at startup since provide useless data +o fix compilation warning in mcast.c: recvfrom takes socklen_t not size_t +o add a lock per buffer: makes buffer code thread safe +o introduce 'Replicate' clause to explicitely set states to be replicated +o kill cache feature abuse: introduce nicer cache hooks for sync algorithms +o fix oversized buffer allocated in the stack in the cache functions +o add support to dump internal/external cache in XML format '-x' + +version 0.9.2 (2006/01/17) +-------------------------- +o remove spamming packet lost messages +o generalize network netlink sequence tracking +o fix bogus error message on resync `-R' +o fix endianess issues in the network netlink message +o introduce generic netlink multicast primitives to send and receive +o fix bogus replayed multicast message due to sequence numbering wraparound +o introduce counter for malformed netlink messages received +o introduce a new syntax for the `Sync' section in the configuration file +o several cleanups and remove unused variables +o add autostuff to include examples in the tarball (reported by Victor Lozano) +o use the new API available in libnetfilter_conntrack-0.0.50 +o implement a NACK based protocol for replication + +version 0.9.1 (2006/11/06) +-------------------------- +o conntrackd requires kernel >= 2.6.18 +o remove bogus TIMERS_MODE constant +o implement bulk mode '-B': first works to address the preemption issue +o fix minor reduction conflicts in the configfile grammar +o check for CAP_NET_ADMIN instead of requiring root privileges +o check that linux/capability.h exists +o fix formatting at dump statistics '-s' +o move dump traffic stats before multicast traffic stats +o move event and dump handler to a generic infrastructure: kill events.c file +o kill unused function inc_ct_stats +o kill file resync.h +o cleanup broadcast_sync: renamed to mcast_send_sync +o sed 's/perror/debug/g' local.c +o fix bogus increment of update_fail stats at dump stage +o display descriptive error if we can't connect to conntrackd via UNIX socket +o remove debugging message from alarm.c +o move dump_mcast_stats to mcast.c where it really belongs +o rename stats.c to traffic_stats.c +o check for replayed/lost multicast message: simple seq tracking w/o recovery +o reissue nfnl_catch on ENOENT error: a message for other subsystem +o remove test/ directory in tree +o improve cache commit stats +o kill last_commit and last_flush from cache statistics: use the logfile +o recover cache naming for dump stats `-s' +o display multicast sequence tracking statistics: packets lost and replayed +o zero ct_sync_state and ct_stats_state structures after allocation +o improve keepalived scripts: + - resync with conntrack table on transition to master + - send bulk on transition to backup +o implement alarm cascade of ten levels +o implement timer cache flavour: limited life of entries in the external cache +o implement a global lock that protects operation with conntrack entries +o remove debug checking in cache_del_entry +o set a reduced timeout for committed entries: 180 seconds by default +o update comments on the sync-mode code +o introduce delay destroy messages facility +o increase timer for external states from 60 to 180 seconds +o remove unused replicate/dont_replicated constants +o fix cache entry clashing issue (reported by Maik Hentsche) +o fix bogus increment of error stats in the external cache +o remove pollution generated by `[REQ] cache dump' message from logfile + +version 0.9.0 (2006/09/17) +-------------------------- +o implement initial for IPv6 (untested) +o implement generic extensible cache: kill the internal and external caches +o implement persistence cache feature +o implement lifetime cache feature +o modify UNIX facilities identification numbers: + separate master conntrack facilities and internal plugin facilities +o break backward compatibility of configuration file: + remove IgnoreLoopback, use IgnoreTrafficFor instead + remove IgnoreMulticastTraffic, use IgnoreTrafficFor instead +o merge event/event_subsys and sync/sync_subsys initialization to run.c +o improve control of the iteration process in the hashtables +o fix wrong locking in the alarm thread +o supersede AcceptNAT by StripNAT clause +o replace ignore traffic array by a hashtable +o move lockfile checking before daemonization +o on initialization error give a descriptive error +o introduce netlink socket size grown limitator +o introduce force resync with master conntrack table facility '-R' +o ignore SIGPIPE signal +o kill post_step since it is not used anymore + +version 0.8.3 (2006/09/03) +-------------------------- +Author: Maik Hentsche + +o Fix typo in conntrackd -h +o Disable debugging messages by default +o No signals while signals handlings +o Add extra checkings at forking +o Check maximum size for file passed via -C + +Author: Pablo Neira Ayuso + +o retry select() if EINTR is returned (Reported by Maik Hentsche) +o Fix bug in slist_for_each_entry (Reported by Maik Hetsche) +o Signal handler registration done after intialization +o Implement alarm thread (based on Maik Hentsche's patch) +o Fix segfault on conntrackd -k (Reported by Maik Hentsche) +o Fix bug on alarm removal (Reported by Maik Hentsche) +o configure stops if bison, flex or yacc are not installed + +version 0.8.2 (2006/07/05) +-------------------------- +o RelaxTransitions clause introduced in Sync mode +o multicast messages sequence tracking +o SocketBufferSize clause to set up the netlink socket buffer +o use new libnfnetlink API to solve limitations of nfnl_listen +o extra sanity checkings for netlink multicast messages +o improve statistics +o tons of cleanups 8) + +version 0.8.1 (2006/06/13) +-------------------------- +o -f now just flushes the internal and external caches +o -F flushes the master conntrack table +o fix segfault under heavy load and signal received +o added -S mode for statistics: still needs more thinking + +version 0.8.0 (2006/06/11) +-------------------------- +o more work to generalize the daemon: now it's ready to implement +modular support for adaptive timers and conntrack statistics, time +to implement them ;). This is *still* a work in progress. + +version 0.7.2 (2006/06/05) +-------------------------- +o stupid bug in normal and alarm caches initialization: flush unset +o fix racy signal handling + +version 0.7.1 (2006/06/05) +-------------------------- +o Bugfix for multicast sockets communication + +version 0.7 (2006/06/01) +------------------------ +o Major code re-structuration: internal and external cache abstraction +o sequence tracking for event messages +o expect more changes, I still dislike some stuff in its current status ;) + +version 0.6 (2006/05/31) +------------------------ +o Lock file support +o use new API nfct_conntrack_event_raw +o major code clean ups + +version 0.5 (2006/05/30) +------------------------- +o Fix multicast server binds to wrong interface +o Include clause `IgnoreProtocol', deprecates IgnoreUDP and IgnoreICMP + +version 0.4 (2006/05/29) +------------------------ +o Initial release diff --git a/CONTRIBUTORS b/CONTRIBUTORS new file mode 100644 index 0000000..c5e40b4 --- /dev/null +++ b/CONTRIBUTORS @@ -0,0 +1,3 @@ +Maik Hentsche : + - Feedback & Brainstorming + - Bug hunting diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..1524ef6 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,243 @@ +2006-03-20 + + o fix ICMP protocol extension parse callback + +2006-01-15 + + o Added missing parameters to set the ports of an expectation tuple + o Add support to filter dumped entries. + ie: conntrack -L -p tcp --orig-port-dst 993 + display all the connections to IMAPS servers + conntrack -L -m 2 + display all the connection marked with 2 + o Bumped version to 1.00beta2 + +2005-12-26 + + o add IPv6 support: main change + o removed dead code: iptables_insmod and get_modprobe + o compact the commands vs. options table + o move working vars from the stack to the BSS section + o update manpage + o Bumped version to 1.0beta1 + + o check address family mismatch + o fix incomplete copying IPv6 addresses + +2005-12-19 + + o We only support ipv4 at the moment: set l3protonum to AF_INET + o Minor changes to prepare upcoming ipv6 support + +2005-12-03 + + o Add support to filter events. ie: -p tcp --orig-port-dst 80 in + conjuction with -E to get all the requests to HTTP servers + o Update manpage + o Missing static function declaration in the protocol handlers + o Use protocol flags defined in libnetfilter_conntrack + o Bumped version to 0.991 + +2005-11-22 + + o Fix oversized number of options + +2005-11-11 + + o don't check for kernel header path in configure, since we don't use + kernel headers + o don't check for libnfnetlink, we don't use it directly + o move plugins into pkglibdir + o remove 'lib' prefix of plugins, they're not really libraries + o remove version information from plugin filenames + o Bumped version to 0.99 +2005-11-09 + + o set status to zero, libnetfilter_conntrack now activate + IPS_CONFIRMED since all conntrack in hash must be confirmed. + o Bumped version to 0.98 + +2005-11-08 + + o Fix warnings generated by gcc -Wall + o Fix conntrack exit value at error + o Replace obsolete inet_addr by inet_aton + +2005-11-05 + + o Improved conntrack -h output + o add htons for icmp id. + + o -t and -u are optional at update. + o Fixed versioning :( + o Bumped version to 0.97 + +2005-11-03 + + o Use extra 'data' argument of nfct_register_callback() function that + I've introduced in libetfilter_conntrack. + + o moves conntrack tool from bin to sbin directory since this + application is an administration utility and it requires uid==0 or + CAP_NET_ADMIN + + o check if --state missing when -p is passed + o command type is passed to final_check: checkings based on the + command can be done now. + o kill duplicated definition of IPS_* bits: Already present in + libnetfilter_conntrack. + o Move action and command enum to conntrack.h + o kill NIPQUAD macro + o make conntrack handler cth static. + o Bumped version to 0.96 + +2005-11-01 + + o Fix error message describing illegal option -E -i + o -D -i ID requires tuple information: Display an error message + o Use NFCT_ALL_CT_GROUPS flag instead of NFCT_ALL_GROUPS + o Event mask doesn't make sense for expectations, kill dead code + o Bumped version to 0.95 + + o Fix wrong formating in conntrack -h + +2005-10-30 + + Special thanks to Deti Fiegl from the Leibniz Supercomputing Centre in + Munich, Germany for providing the "fast" hardware to reproduce + spurious bugs ;) + + o Replace misleading message "Not enough memory" by "Can't open handler" + o New option -i for expectation dumping: conntrack -L expect [-i] + o sed 's/VERSION/CONNTRACK_VERSION/g' + o Fix nfct_open flags, now uses NFCT_ALL_GROUPS when needed + o Bumped version to 0.94 + +2005-10-28 + + o New option -i for dumping: conntrack -L [-i] + o Fixed warning in findproto due to a stupid wrong type definition + o sed 's/nfct_set_callback/nfct_register_callback/g' + o killed the 'retry' logic, *sigh* it is broken in some cases + o killed broken and unneeded protocol handler destructors (fini) + o killed unregister_proto + o Fixed code indentation in the command selector + o Bumped version to 0.93 + +2005-10-27 + + o Use conntrack VERSION instead of the old LIBCT_VERSION + o proto_list and lib_dir are now static + o kill dead code: function dump_tuple + o Bumped version to 0.92 + +2005-10-25 + + o Add missing autogen.sh file + +2005-10-24 + + o use NFCT_ANY_GROUP flag in nfct_open() + +2005-10-21 + + o Bumped version to 0.90 + o Add support for id and marks + +2005-10-20 + + o Kill some more files that generated by the autocrap + o Resync with the lastest libnetfilter_conntrack API changes + +2005-10-16 + + o Rename libct_proto.h to conntrack.h + o Remove config.h.in from svn, it's autogenerated by the autocrap :) + o Remove dead functions in the SCTP protocol helper + +2005-10-14 + + o Kill config.h.in, it's generated by the autocrap + o The conntrack tool now uses libnetfilter_conntrack :) + o libct.c has been killed, now it's in libnetfilter_conntrack + o Check if you're root or CAP_NET_ADMIN + o Bumped version number to 0.86 + +2005-10-07 + + o Fixed ICMP options + + o Multiple fixes for the ICMP protocol handler + o Fix ICMP output: wrong output. type and code were set to zero. + +2005-10-05 + + o Fix up counters + o Fix up compilation (IPS_* stuff missing), still need a proper fix + o Bumped version number to 0.82 + +2005-09-24 + + o Get rid of C++ style comments + o Remove remaining bits of "-A --action", group-mask and dump-mask + o Clean up #include's + o Fix double-free when exiting via signal handler (Ctrl+C) + o Add "version" member to plugins + o Fix some Endianness issues when printing CTA_STATUS + +2005-08-31 + + o Fix packet and bytes counters (use __be64_to_cpu) + o Fix ip_conntrack_netlink load-on-demand + +2005-07-12 + + o Use conntrack netlink attributes: Major change + o Kill action setting: Mask based dumping + o Fix ChangeLog + +2005-05-23 + + o Fixed syntax error (tab/space issue) in help message + o Fixed getopt handling on big endian machines + o Fixed possible future read-over-end-of-array in TCP extension + o Add manpage + o Add missing space at output of libct_proto_icmp.c + o Add status bits that were introduced in 2.6.11 + o Add SCTP extension + o Add support for expect creation + o Bump version number to 0.63 + +2005-05-17 + + o Added descriptive error messages. + o Fix wrong flags check in [tcp|udp] proto helpers. + +2005-05-16 + + o Implemented ICMP proto helper + o Added help() and final_check() functions for proto helpers. + +2005-05-01 + + o Created changelog file + o Deleted libctnetlink.h and libnfnetlink.h from the include/ dir. + o Added support for version (-V) and help (-h) + o Added event mask based support + o Added GPLv2 headers + o Use fprintf instead of printf + o Defined print_tuple and print_proto output interfaces + o ctnl_[get|del]_conntrack handles return value from kernel via msgerr + o Added support for conntrack table flushing + o Added test case file (test.sh) + o Improve dump output + + + o Autoconf stuff for conntrack + some pablo's modifications. + o Fixed packet counters formatting (use %llu instead of %lu) + +2005-04-25 + + o Added support for mask based event dumping + o Added support for mask based event notification + o On-demand autoload of ip_conntrack_netlink diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..0de8dc0 --- /dev/null +++ b/INSTALL @@ -0,0 +1,199 @@ +Copyright (C) 2006-2007 Pablo Neira Ayuso + +1.Basic Installation +==================== + + To compile and install 'conntrackd' just follow the classical steps: + + $ ./configure + $ make + # make install + # mkdir /etc/conntrackd/ + +2.1. Synchronization Mode +========================= + + Conntrackd can replicate the status of the connections that are currently + being processed by your stateful firewall based on Linux. This section + describes how to setup the daemon in synchronization mode: + +2.1.1. Requirements + + You have to install the following software in order to get conntrackd working, + make sure that you have installed them correctly before going forward: + + o linux kernel version >= 2.6.18 (http://www.kernel.org) with support for: + - connection tracking system (quite obvious ;) + - nfnetlink + - ctnetlink (ip_conntrack_netlink) + - connection tracking event notification API + + o libnfnetlink: the netfilter netlink library + + Since conntrackd version 0.9.2 you can used the official release availble at + http://www.netfilter.org/projects/libnfnetlink/files/ + + Up to conntrackd version 0.9.1 use the unofficial release available at the + download section + + o libnetfilter_conntrack: the netfilter conntrack library + + Since conntrackd version 0.9.2 you can used the official release availble at + http://www.netfilter.org/projects/libnetfilter_conntrack/files/ + + Up to conntrackd version 0.9.1 use the unnoficial release available at the + download section + + o Keepalived version 1.x (http://www.keepalived.org) + check if your distribution comes with a recent version + +2.1.2. Configuration + + 1) Setting up keepalived + + There is an example file available inside the conntrackd tarball: + + For node 1: conntrackd-x.x.x/examples/sync/node1/keepalived.conf + For node 2: conntrackd-x.x.x/examples/sync/node2/keepalived.conf + + These files can be used to set up a simple VRRP cluster composed of + two machines that hold the virtual IPs 192.168.0.100 on eth0 and + 192.168.1.100 on eth1. + + If you are not familiar with keepalived, please read the official + docs available at http://www.keepalived.org + + Please, make sure that keepalived is correctly working before passing + to step 2) + + 2) Setting up conntrackd + + To setup 'conntrackd' in synchronization mode, you have to put the + configuration file in the directory /etc/conntrackd. + + On node 1: + # cp examples/sync/_type_/node1/conntrackd.conf /etc/conntrackd.conf + + On node 2: + # cp examples/sync/_type_/node1/conntrackd.conf /etc/conntrackd.conf + + Where _type_ is the synchronization type selected, currently there are + two: the persistent mode and the NACK mode. The persistent mode consumes + more resources than the NACK mode, however the NACK mode is still + experimental + + Do not forget to edit the files in order to adapt them to the + setting that you are deploying. + + Note: If you don't want to put the config file under /etc/conntrackd, + just tell conntrackd where to find it passing the option -C + + 3) Running conntrackd + + Conntrackd can run in console mode, in that case just type 'conntrackd', + otherwise, if you want to run it in daemon mode the type 'conntrackd -d'. + + 4) Checking that conntrackd is working fine + + Conntrackd comes with several facilities to check its status: + + - Dump the cache of connections that are currently being processed by + this node (aka. internal cache): + + # conntrackd -i + + - Dump the cache of connections that has been transfered from + others active nodes in the network (aka. external cache) + + # conntrackd -e + + - Dump statistics collected by the replication daemon: + + # conntrackd -s + + 5) Setting up interaction with keepalived + + If keepalived detects the failure of the active node, then it designates + a candidate node that will replace the failing active. On such event, + the external cache, eg. the cache that contains the connections processed + by other nodes, must be commited. To commit the external cache, just type: + + # conntrackd -c + + See that keepalived provides a shell script interface to interact with + other programs, so we can automate the process of commiting the external + cache by introducing the following line in the keepalived file: + + notify_master /etc/conntrackd/script_master.sh + + The script 'script_master.sh' just the following: + + #!/bin/sh + /usr/sbin/conntrackd -c + + Therefore, on failure event, the candidate node takes over the virtual + IPs and the connections that the failing active was processing. Observe + that this file differs for the NACK mode. + + 6) Disable TCP window tracking + + Until the appropiate patches don't go into kernel mainline, you will have + to disable TCP window tracking, consider this as a temporary solution: + + # echo 1 > /proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_be_liberal + +2.2. Statistics mode +==================== + + Conntrackd can also run as statistics daemon, if you are not interested in + this mode, just skip it. It is not required in order to get the + synchronization mode working. This section details how to setup the daemon + in statistics mode: + +2.2.1. Requirements + + You have to install the following software in order to get conntrackd working, + make sure that you have them installed correctly before going forward: + + o linux kernel version >= 2.6.18 (http://www.kernel.org) with support for: + - connection tracking system + - nfnetlink + - ctnetlink (ip_conntrack_netlink) + - connection tracking event notification API + + o libnfnetlink: the netfilter netlink library + + Since conntrackd version 0.9.2 you can used the official release availble at + http://www.netfilter.org/projects/libnfnetlink/files/ + + Up to conntrackd version 0.9.1 use the unofficial release available at the + download section + + o libnetfilter_conntrack: the netfilter conntrack library + + Since conntrackd version 0.9.2 you can used the official release availble at + http://www.netfilter.org/projects/libnetfilter_conntrack/files/ + + Up to conntrackd version 0.9.1 use the unnoficial release available at the + download section + +2.2.2. Configuration + + Setting up conntrackd in statistics mode is rather easy. Just copy the + configuration file + + # cp examples/stats/conntrackd.conf /etc/conntrackd.conf + +2.2.3. Running conntrackd in statistics mode + + To run conntrackd in statistics mode: + + # conntrackd -S + + Alternatively, you can run conntrackd in daemon mode: + + # conntrackd -S -d + + In order to dump the statistics, just type: + + # conntrackd -s diff --git a/Make_global.am b/Make_global.am new file mode 100644 index 0000000..685add7 --- /dev/null +++ b/Make_global.am @@ -0,0 +1 @@ +INCLUDES=$(all_includes) -I$(top_srcdir)/include diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..8a4ce7c --- /dev/null +++ b/Makefile.am @@ -0,0 +1,21 @@ +include Make_global.am + +# not a GNU package. You can remove this line, if +# have all needed files, that a GNU package needs +AUTOMAKE_OPTIONS = foreign dist-bzip2 1.6 + +# man_MANS = "" +# EXTRA_DIST = $(man_MANS) Make_global.am debian +EXTRA_DIST = Make_global.am CHANGELOG TODO + +SUBDIRS = src extensions +DIST_SUBDIRS = include src extensions examples +LINKOPTS = -lnfnetlink -lnetfilter_conntrack -lpthread +AM_CFLAGS = -g + +$(OBJECTS): libtool +libtool: $(LIBTOOL_DEPS) + $(SHELL) ./config.status --recheck + +dist-hook: + rm -rf `find $(distdir)/debian -name .svn` diff --git a/TODO b/TODO new file mode 100644 index 0000000..130b1f8 --- /dev/null +++ b/TODO @@ -0,0 +1,18 @@ +There are several tasks that are pending to be done, I have classified them +by dificulty levels: + +Relatively easy +=============== + +- test ipv6 support +- improve shell scripts +- test NACK based protocol +- manpage for conntrackd + +Requires some work +================== + +- study better keepalived transitions +- implement support for TCP window tracking (patches are on the table) + - at the moment you have to disable it: + echo 1 > /proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_be_liberal diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..e76d3ef --- /dev/null +++ b/autogen.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +run () +{ + echo "running: $*" + eval $* + + if test $? != 0 ; then + echo "error: while running '$*'" + exit 1 + fi +} + +run aclocal +run libtoolize -f +#run autoheader +run automake -a +run autoconf diff --git a/cli/ChangeLog b/cli/ChangeLog deleted file mode 100644 index 1524ef6..0000000 --- a/cli/ChangeLog +++ /dev/null @@ -1,243 +0,0 @@ -2006-03-20 - - o fix ICMP protocol extension parse callback - -2006-01-15 - - o Added missing parameters to set the ports of an expectation tuple - o Add support to filter dumped entries. - ie: conntrack -L -p tcp --orig-port-dst 993 - display all the connections to IMAPS servers - conntrack -L -m 2 - display all the connection marked with 2 - o Bumped version to 1.00beta2 - -2005-12-26 - - o add IPv6 support: main change - o removed dead code: iptables_insmod and get_modprobe - o compact the commands vs. options table - o move working vars from the stack to the BSS section - o update manpage - o Bumped version to 1.0beta1 - - o check address family mismatch - o fix incomplete copying IPv6 addresses - -2005-12-19 - - o We only support ipv4 at the moment: set l3protonum to AF_INET - o Minor changes to prepare upcoming ipv6 support - -2005-12-03 - - o Add support to filter events. ie: -p tcp --orig-port-dst 80 in - conjuction with -E to get all the requests to HTTP servers - o Update manpage - o Missing static function declaration in the protocol handlers - o Use protocol flags defined in libnetfilter_conntrack - o Bumped version to 0.991 - -2005-11-22 - - o Fix oversized number of options - -2005-11-11 - - o don't check for kernel header path in configure, since we don't use - kernel headers - o don't check for libnfnetlink, we don't use it directly - o move plugins into pkglibdir - o remove 'lib' prefix of plugins, they're not really libraries - o remove version information from plugin filenames - o Bumped version to 0.99 -2005-11-09 - - o set status to zero, libnetfilter_conntrack now activate - IPS_CONFIRMED since all conntrack in hash must be confirmed. - o Bumped version to 0.98 - -2005-11-08 - - o Fix warnings generated by gcc -Wall - o Fix conntrack exit value at error - o Replace obsolete inet_addr by inet_aton - -2005-11-05 - - o Improved conntrack -h output - o add htons for icmp id. - - o -t and -u are optional at update. - o Fixed versioning :( - o Bumped version to 0.97 - -2005-11-03 - - o Use extra 'data' argument of nfct_register_callback() function that - I've introduced in libetfilter_conntrack. - - o moves conntrack tool from bin to sbin directory since this - application is an administration utility and it requires uid==0 or - CAP_NET_ADMIN - - o check if --state missing when -p is passed - o command type is passed to final_check: checkings based on the - command can be done now. - o kill duplicated definition of IPS_* bits: Already present in - libnetfilter_conntrack. - o Move action and command enum to conntrack.h - o kill NIPQUAD macro - o make conntrack handler cth static. - o Bumped version to 0.96 - -2005-11-01 - - o Fix error message describing illegal option -E -i - o -D -i ID requires tuple information: Display an error message - o Use NFCT_ALL_CT_GROUPS flag instead of NFCT_ALL_GROUPS - o Event mask doesn't make sense for expectations, kill dead code - o Bumped version to 0.95 - - o Fix wrong formating in conntrack -h - -2005-10-30 - - Special thanks to Deti Fiegl from the Leibniz Supercomputing Centre in - Munich, Germany for providing the "fast" hardware to reproduce - spurious bugs ;) - - o Replace misleading message "Not enough memory" by "Can't open handler" - o New option -i for expectation dumping: conntrack -L expect [-i] - o sed 's/VERSION/CONNTRACK_VERSION/g' - o Fix nfct_open flags, now uses NFCT_ALL_GROUPS when needed - o Bumped version to 0.94 - -2005-10-28 - - o New option -i for dumping: conntrack -L [-i] - o Fixed warning in findproto due to a stupid wrong type definition - o sed 's/nfct_set_callback/nfct_register_callback/g' - o killed the 'retry' logic, *sigh* it is broken in some cases - o killed broken and unneeded protocol handler destructors (fini) - o killed unregister_proto - o Fixed code indentation in the command selector - o Bumped version to 0.93 - -2005-10-27 - - o Use conntrack VERSION instead of the old LIBCT_VERSION - o proto_list and lib_dir are now static - o kill dead code: function dump_tuple - o Bumped version to 0.92 - -2005-10-25 - - o Add missing autogen.sh file - -2005-10-24 - - o use NFCT_ANY_GROUP flag in nfct_open() - -2005-10-21 - - o Bumped version to 0.90 - o Add support for id and marks - -2005-10-20 - - o Kill some more files that generated by the autocrap - o Resync with the lastest libnetfilter_conntrack API changes - -2005-10-16 - - o Rename libct_proto.h to conntrack.h - o Remove config.h.in from svn, it's autogenerated by the autocrap :) - o Remove dead functions in the SCTP protocol helper - -2005-10-14 - - o Kill config.h.in, it's generated by the autocrap - o The conntrack tool now uses libnetfilter_conntrack :) - o libct.c has been killed, now it's in libnetfilter_conntrack - o Check if you're root or CAP_NET_ADMIN - o Bumped version number to 0.86 - -2005-10-07 - - o Fixed ICMP options - - o Multiple fixes for the ICMP protocol handler - o Fix ICMP output: wrong output. type and code were set to zero. - -2005-10-05 - - o Fix up counters - o Fix up compilation (IPS_* stuff missing), still need a proper fix - o Bumped version number to 0.82 - -2005-09-24 - - o Get rid of C++ style comments - o Remove remaining bits of "-A --action", group-mask and dump-mask - o Clean up #include's - o Fix double-free when exiting via signal handler (Ctrl+C) - o Add "version" member to plugins - o Fix some Endianness issues when printing CTA_STATUS - -2005-08-31 - - o Fix packet and bytes counters (use __be64_to_cpu) - o Fix ip_conntrack_netlink load-on-demand - -2005-07-12 - - o Use conntrack netlink attributes: Major change - o Kill action setting: Mask based dumping - o Fix ChangeLog - -2005-05-23 - - o Fixed syntax error (tab/space issue) in help message - o Fixed getopt handling on big endian machines - o Fixed possible future read-over-end-of-array in TCP extension - o Add manpage - o Add missing space at output of libct_proto_icmp.c - o Add status bits that were introduced in 2.6.11 - o Add SCTP extension - o Add support for expect creation - o Bump version number to 0.63 - -2005-05-17 - - o Added descriptive error messages. - o Fix wrong flags check in [tcp|udp] proto helpers. - -2005-05-16 - - o Implemented ICMP proto helper - o Added help() and final_check() functions for proto helpers. - -2005-05-01 - - o Created changelog file - o Deleted libctnetlink.h and libnfnetlink.h from the include/ dir. - o Added support for version (-V) and help (-h) - o Added event mask based support - o Added GPLv2 headers - o Use fprintf instead of printf - o Defined print_tuple and print_proto output interfaces - o ctnl_[get|del]_conntrack handles return value from kernel via msgerr - o Added support for conntrack table flushing - o Added test case file (test.sh) - o Improve dump output - - - o Autoconf stuff for conntrack + some pablo's modifications. - o Fixed packet counters formatting (use %llu instead of %lu) - -2005-04-25 - - o Added support for mask based event dumping - o Added support for mask based event notification - o On-demand autoload of ip_conntrack_netlink diff --git a/cli/conntrack.8 b/cli/conntrack.8 deleted file mode 100644 index 307180b..0000000 --- a/cli/conntrack.8 +++ /dev/null @@ -1,142 +0,0 @@ -.TH CONNTRACK 8 "Jun 23, 2005" "" "" - -.\" Man page written by Harald Welte . diff --git a/cli/extensions/Makefile.am b/cli/extensions/Makefile.am deleted file mode 100644 index 5366ee3..0000000 --- a/cli/extensions/Makefile.am +++ /dev/null @@ -1,16 +0,0 @@ -include $(top_srcdir)/Make_global.am - -AM_CFLAGS=-fPIC -Wall -LIBS= - -pkglib_LTLIBRARIES = ct_proto_tcp.la ct_proto_udp.la \ - ct_proto_icmp.la ct_proto_sctp.la - -ct_proto_tcp_la_SOURCES = libct_proto_tcp.c -ct_proto_tcp_la_LDFLAGS = -module -avoid-version -ct_proto_udp_la_SOURCES = libct_proto_udp.c -ct_proto_udp_la_LDFLAGS = -module -avoid-version -ct_proto_icmp_la_SOURCES = libct_proto_icmp.c -ct_proto_icmp_la_LDFLAGS = -module -avoid-version -ct_proto_sctp_la_SOURCES = libct_proto_sctp.c -ct_proto_sctp_la_LDFLAGS = -module -avoid-version diff --git a/cli/extensions/libct_proto_icmp.c b/cli/extensions/libct_proto_icmp.c deleted file mode 100644 index e7cb04d..0000000 --- a/cli/extensions/libct_proto_icmp.c +++ /dev/null @@ -1,108 +0,0 @@ -/* - * (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 /* For htons */ -#include -#include -#include -#include "conntrack.h" - -static struct option opts[] = { - {"icmp-type", 1, 0, '1'}, - {"icmp-code", 1, 0, '2'}, - {"icmp-id", 1, 0, '3'}, - {0, 0, 0, 0} -}; - -static void help() -{ - fprintf(stdout, "--icmp-type icmp type\n"); - fprintf(stdout, "--icmp-code icmp code\n"); - fprintf(stdout, "--icmp-id icmp id\n"); -} - -/* Add 1; spaces filled with 0. */ -static u_int8_t invmap[] - = { [ICMP_ECHO] = ICMP_ECHOREPLY + 1, - [ICMP_ECHOREPLY] = ICMP_ECHO + 1, - [ICMP_TIMESTAMP] = ICMP_TIMESTAMPREPLY + 1, - [ICMP_TIMESTAMPREPLY] = ICMP_TIMESTAMP + 1, - [ICMP_INFO_REQUEST] = ICMP_INFO_REPLY + 1, - [ICMP_INFO_REPLY] = ICMP_INFO_REQUEST + 1, - [ICMP_ADDRESS] = ICMP_ADDRESSREPLY + 1, - [ICMP_ADDRESSREPLY] = ICMP_ADDRESS + 1}; - -static int parse(char c, char *argv[], - struct nfct_tuple *orig, - struct nfct_tuple *reply, - struct nfct_tuple *exptuple, - struct nfct_tuple *mask, - union nfct_protoinfo *proto, - unsigned int *flags) -{ - switch(c) { - case '1': - if (optarg) { - orig->l4dst.icmp.type = atoi(optarg); - reply->l4dst.icmp.type = - invmap[orig->l4dst.icmp.type] - 1; - *flags |= ICMP_TYPE; - } - break; - case '2': - if (optarg) { - orig->l4dst.icmp.code = atoi(optarg); - reply->l4dst.icmp.code = 0; - *flags |= ICMP_CODE; - } - break; - case '3': - if (optarg) { - orig->l4src.icmp.id = htons(atoi(optarg)); - reply->l4dst.icmp.id = 0; - *flags |= ICMP_ID; - } - break; - } - return 1; -} - -static int final_check(unsigned int flags, - unsigned int command, - struct nfct_tuple *orig, - struct nfct_tuple *reply) -{ - if (!(flags & ICMP_TYPE)) - return 0; - else if (!(flags & ICMP_CODE)) - return 0; - - return 1; -} - -static struct ctproto_handler icmp = { - .name = "icmp", - .protonum = IPPROTO_ICMP, - .parse_opts = parse, - .final_check = final_check, - .help = help, - .opts = opts, - .version = VERSION, -}; - -static void __attribute__ ((constructor)) init(void); - -static void init(void) -{ - register_proto(&icmp); -} diff --git a/cli/extensions/libct_proto_icmp.man b/cli/extensions/libct_proto_icmp.man deleted file mode 100644 index 3b860d0..0000000 --- a/cli/extensions/libct_proto_icmp.man +++ /dev/null @@ -1,10 +0,0 @@ -This module matches on ICMP-specific fields. -.TP -.BI "--icmp-type " "TYPE" -ICMP Type. Has to be specified numerically. -.TP -.BI "--icmp-code " "CODE" -ICMP Code. Has to be specified numerically. -.TP -.BI "--icmp-id " "ID" -ICMP Id. Has to be specified numerically. diff --git a/cli/extensions/libct_proto_sctp.c b/cli/extensions/libct_proto_sctp.c deleted file mode 100644 index 1c8f0d1..0000000 --- a/cli/extensions/libct_proto_sctp.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - * (C) 2005 by Harald Welte - * 2006 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 -#include -#include -#include -#include /* For htons */ -#include "conntrack.h" -#include -#include - -static struct option opts[] = { - {"orig-port-src", 1, 0, '1'}, - {"orig-port-dst", 1, 0, '2'}, - {"reply-port-src", 1, 0, '3'}, - {"reply-port-dst", 1, 0, '4'}, - {"state", 1, 0, '5'}, - {"tuple-port-src", 1, 0, '6'}, - {"tuple-port-dst", 1, 0, '7'}, - {0, 0, 0, 0} -}; - -static const char *states[] = { - "NONE", - "CLOSED", - "COOKIE_WAIT", - "COOKIE_ECHOED", - "ESTABLISHED", - "SHUTDOWN_SENT", - "SHUTDOWN_RECV", - "SHUTDOWN_ACK_SENT", -}; - -static void help() -{ - fprintf(stdout, "--orig-port-src original source port\n"); - fprintf(stdout, "--orig-port-dst original destination port\n"); - fprintf(stdout, "--reply-port-src reply source port\n"); - fprintf(stdout, "--reply-port-dst reply destination port\n"); - fprintf(stdout, "--state SCTP state, fe. ESTABLISHED\n"); - fprintf(stdout, "--tuple-port-src expectation tuple src port\n"); - fprintf(stdout, "--tuple-port-src expectation tuple dst port\n"); -} - -static int parse_options(char c, char *argv[], - struct nfct_tuple *orig, - struct nfct_tuple *reply, - struct nfct_tuple *exptuple, - struct nfct_tuple *mask, - union nfct_protoinfo *proto, - unsigned int *flags) -{ - switch(c) { - case '1': - if (optarg) { - orig->l4src.sctp.port = htons(atoi(optarg)); - *flags |= SCTP_ORIG_SPORT; - } - break; - case '2': - if (optarg) { - orig->l4dst.sctp.port = htons(atoi(optarg)); - *flags |= SCTP_ORIG_DPORT; - } - break; - case '3': - if (optarg) { - reply->l4src.sctp.port = htons(atoi(optarg)); - *flags |= SCTP_REPL_SPORT; - } - break; - case '4': - if (optarg) { - reply->l4dst.sctp.port = htons(atoi(optarg)); - *flags |= SCTP_REPL_DPORT; - } - break; - case '5': - if (optarg) { - int i; - for (i=0; i<10; i++) { - if (strcmp(optarg, states[i]) == 0) { - /* FIXME: Add state to - * nfct_protoinfo - proto->sctp.state = i; */ - break; - } - } - if (i == 10) { - printf("doh?\n"); - return 0; - } - *flags |= SCTP_STATE; - } - break; - case '6': - if (optarg) { - exptuple->l4src.sctp.port = htons(atoi(optarg)); - *flags |= SCTP_EXPTUPLE_SPORT; - } - break; - case '7': - if (optarg) { - exptuple->l4dst.sctp.port = htons(atoi(optarg)); - *flags |= SCTP_EXPTUPLE_DPORT; - } - - } - return 1; -} - -static int final_check(unsigned int flags, - unsigned int command, - struct nfct_tuple *orig, - struct nfct_tuple *reply) -{ - int ret = 0; - - if ((flags & (SCTP_ORIG_SPORT|SCTP_ORIG_DPORT)) - && !(flags & (SCTP_REPL_SPORT|SCTP_REPL_DPORT))) { - reply->l4src.sctp.port = orig->l4dst.sctp.port; - reply->l4dst.sctp.port = orig->l4src.sctp.port; - ret = 1; - } else if (!(flags & (SCTP_ORIG_SPORT|SCTP_ORIG_DPORT)) - && (flags & (SCTP_REPL_SPORT|SCTP_REPL_DPORT))) { - orig->l4src.sctp.port = reply->l4dst.sctp.port; - orig->l4dst.sctp.port = reply->l4src.sctp.port; - ret = 1; - } - if ((flags & (SCTP_ORIG_SPORT|SCTP_ORIG_DPORT)) - && ((flags & (SCTP_REPL_SPORT|SCTP_REPL_DPORT)))) - ret = 1; - - /* --state is missing and we are trying to create a conntrack */ - if (ret && (command & CT_CREATE) && (!(flags & SCTP_STATE))) - ret = 0; - - return ret; -} - -static struct ctproto_handler sctp = { - .name = "sctp", - .protonum = IPPROTO_SCTP, - .parse_opts = parse_options, - .final_check = final_check, - .help = help, - .opts = opts, - .version = VERSION, -}; - -static void __attribute__ ((constructor)) init(void); - -static void init(void) -{ - register_proto(&sctp); -} diff --git a/cli/extensions/libct_proto_tcp.c b/cli/extensions/libct_proto_tcp.c deleted file mode 100644 index ee24206..0000000 --- a/cli/extensions/libct_proto_tcp.c +++ /dev/null @@ -1,180 +0,0 @@ -/* - * (C) 2005 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 -#include -#include -#include -#include /* For htons */ -#include -#include - -#include "conntrack.h" - -static struct option opts[] = { - {"orig-port-src", 1, 0, '1'}, - {"orig-port-dst", 1, 0, '2'}, - {"reply-port-src", 1, 0, '3'}, - {"reply-port-dst", 1, 0, '4'}, - {"mask-port-src", 1, 0, '5'}, - {"mask-port-dst", 1, 0, '6'}, - {"state", 1, 0, '7'}, - {"tuple-port-src", 1, 0, '8'}, - {"tuple-port-dst", 1, 0, '9'}, - {0, 0, 0, 0} -}; - -static const char *states[] = { - "NONE", - "SYN_SENT", - "SYN_RECV", - "ESTABLISHED", - "FIN_WAIT", - "CLOSE_WAIT", - "LAST_ACK", - "TIME_WAIT", - "CLOSE", - "LISTEN" -}; - -static void help() -{ - fprintf(stdout, "--orig-port-src original source port\n"); - fprintf(stdout, "--orig-port-dst original destination port\n"); - fprintf(stdout, "--reply-port-src reply source port\n"); - fprintf(stdout, "--reply-port-dst reply destination port\n"); - fprintf(stdout, "--mask-port-src mask source port\n"); - fprintf(stdout, "--mask-port-dst mask destination port\n"); - fprintf(stdout, "--tuple-port-src expectation tuple src port\n"); - fprintf(stdout, "--tuple-port-src expectation tuple dst port\n"); - fprintf(stdout, "--state TCP state, fe. ESTABLISHED\n"); -} - -static int parse_options(char c, char *argv[], - struct nfct_tuple *orig, - struct nfct_tuple *reply, - struct nfct_tuple *exptuple, - struct nfct_tuple *mask, - union nfct_protoinfo *proto, - unsigned int *flags) -{ - switch(c) { - case '1': - if (optarg) { - orig->l4src.tcp.port = htons(atoi(optarg)); - *flags |= TCP_ORIG_SPORT; - } - break; - case '2': - if (optarg) { - orig->l4dst.tcp.port = htons(atoi(optarg)); - *flags |= TCP_ORIG_DPORT; - } - break; - case '3': - if (optarg) { - reply->l4src.tcp.port = htons(atoi(optarg)); - *flags |= TCP_REPL_SPORT; - } - break; - case '4': - if (optarg) { - reply->l4dst.tcp.port = htons(atoi(optarg)); - *flags |= TCP_REPL_DPORT; - } - break; - case '5': - if (optarg) { - mask->l4src.tcp.port = htons(atoi(optarg)); - *flags |= TCP_MASK_SPORT; - } - break; - case '6': - if (optarg) { - mask->l4dst.tcp.port = htons(atoi(optarg)); - *flags |= TCP_MASK_DPORT; - } - break; - case '7': - if (optarg) { - int i; - for (i=0; i<10; i++) { - if (strcmp(optarg, states[i]) == 0) { - proto->tcp.state = i; - break; - } - } - if (i == 10) { - printf("doh?\n"); - return 0; - } - *flags |= TCP_STATE; - } - break; - case '8': - if (optarg) { - exptuple->l4src.tcp.port = htons(atoi(optarg)); - *flags |= TCP_EXPTUPLE_SPORT; - } - break; - case '9': - if (optarg) { - exptuple->l4dst.tcp.port = htons(atoi(optarg)); - *flags |= TCP_EXPTUPLE_DPORT; - } - break; - } - return 1; -} - -static int final_check(unsigned int flags, - unsigned int command, - struct nfct_tuple *orig, - struct nfct_tuple *reply) -{ - int ret = 0; - - if ((flags & (TCP_ORIG_SPORT|TCP_ORIG_DPORT)) - && !(flags & (TCP_REPL_SPORT|TCP_REPL_DPORT))) { - reply->l4src.tcp.port = orig->l4dst.tcp.port; - reply->l4dst.tcp.port = orig->l4src.tcp.port; - ret = 1; - } else if (!(flags & (TCP_ORIG_SPORT|TCP_ORIG_DPORT)) - && (flags & (TCP_REPL_SPORT|TCP_REPL_DPORT))) { - orig->l4src.tcp.port = reply->l4dst.tcp.port; - orig->l4dst.tcp.port = reply->l4src.tcp.port; - ret = 1; - } - if ((flags & (TCP_ORIG_SPORT|TCP_ORIG_DPORT)) - && ((flags & (TCP_REPL_SPORT|TCP_REPL_DPORT)))) - ret = 1; - - /* --state is missing and we are trying to create a conntrack */ - if (ret && (command & CT_CREATE) && (!(flags & TCP_STATE))) - ret = 0; - - return ret; -} - -static struct ctproto_handler tcp = { - .name = "tcp", - .protonum = IPPROTO_TCP, - .parse_opts = parse_options, - .final_check = final_check, - .help = help, - .opts = opts, - .version = VERSION, -}; - -static void __attribute__ ((constructor)) init(void); - -static void init(void) -{ - register_proto(&tcp); -} diff --git a/cli/extensions/libct_proto_tcp.man b/cli/extensions/libct_proto_tcp.man deleted file mode 100644 index 41783f8..0000000 --- a/cli/extensions/libct_proto_tcp.man +++ /dev/null @@ -1,16 +0,0 @@ -This module matches on TCP-specific fields. -.TP -.BI "--orig-port-src " "PORT" -Source port in original direction -.TP -.BI "--orig-port-dst " "PORT" -Destination port in original direction -.TP -.BI "--reply-port-src " "PORT" -Source port in reply direction -.TP -.BI "--reply-port-dst " "PORT" -Destination port in reply direction -.TP -.BI "--state " "[NONE|SYN_SENT|SYN_RECV|ESTABLISHED|FIN_WAIT|CLOSE_WAIT|LAST_ACK|TIME_WAIT|CLOSE|LISTEN]" -TCP state diff --git a/cli/extensions/libct_proto_udp.c b/cli/extensions/libct_proto_udp.c deleted file mode 100644 index 48079e0..0000000 --- a/cli/extensions/libct_proto_udp.c +++ /dev/null @@ -1,141 +0,0 @@ -/* - * (C) 2005 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 -#include -#include -#include /* For htons */ -#include "conntrack.h" -#include -#include - -static struct option opts[] = { - {"orig-port-src", 1, 0, '1'}, - {"orig-port-dst", 1, 0, '2'}, - {"reply-port-src", 1, 0, '3'}, - {"reply-port-dst", 1, 0, '4'}, - {"mask-port-src", 1, 0, '5'}, - {"mask-port-dst", 1, 0, '6'}, - {"tuple-port-src", 1, 0, '7'}, - {"tuple-port-dst", 1, 0, '8'}, - {0, 0, 0, 0} -}; - -static void help() -{ - fprintf(stdout, "--orig-port-src original source port\n"); - fprintf(stdout, "--orig-port-dst original destination port\n"); - fprintf(stdout, "--reply-port-src reply source port\n"); - fprintf(stdout, "--reply-port-dst reply destination port\n"); - fprintf(stdout, "--mask-port-src mask source port\n"); - fprintf(stdout, "--mask-port-dst mask destination port\n"); - fprintf(stdout, "--tuple-port-src expectation tuple src port\n"); - fprintf(stdout, "--tuple-port-src expectation tuple dst port\n"); -} - -static int parse_options(char c, char *argv[], - struct nfct_tuple *orig, - struct nfct_tuple *reply, - struct nfct_tuple *exptuple, - struct nfct_tuple *mask, - union nfct_protoinfo *proto, - unsigned int *flags) -{ - switch(c) { - case '1': - if (optarg) { - orig->l4src.udp.port = htons(atoi(optarg)); - *flags |= UDP_ORIG_SPORT; - } - break; - case '2': - if (optarg) { - orig->l4dst.udp.port = htons(atoi(optarg)); - *flags |= UDP_ORIG_DPORT; - } - break; - case '3': - if (optarg) { - reply->l4src.udp.port = htons(atoi(optarg)); - *flags |= UDP_REPL_SPORT; - } - break; - case '4': - if (optarg) { - reply->l4dst.udp.port = htons(atoi(optarg)); - *flags |= UDP_REPL_DPORT; - } - break; - case '5': - if (optarg) { - mask->l4src.udp.port = htons(atoi(optarg)); - *flags |= UDP_MASK_SPORT; - } - break; - case '6': - if (optarg) { - mask->l4dst.udp.port = htons(atoi(optarg)); - *flags |= UDP_MASK_DPORT; - } - break; - case '7': - if (optarg) { - exptuple->l4src.udp.port = htons(atoi(optarg)); - *flags |= UDP_EXPTUPLE_SPORT; - } - break; - case '8': - if (optarg) { - exptuple->l4dst.udp.port = htons(atoi(optarg)); - *flags |= UDP_EXPTUPLE_DPORT; - } - - } - return 1; -} - -static int final_check(unsigned int flags, - unsigned int command, - struct nfct_tuple *orig, - struct nfct_tuple *reply) -{ - if ((flags & (UDP_ORIG_SPORT|UDP_ORIG_DPORT)) - && !(flags & (UDP_REPL_SPORT|UDP_REPL_DPORT))) { - reply->l4src.udp.port = orig->l4dst.udp.port; - reply->l4dst.udp.port = orig->l4src.udp.port; - return 1; - } else if (!(flags & (UDP_ORIG_SPORT|UDP_ORIG_DPORT)) - && (flags & (UDP_REPL_SPORT|UDP_REPL_DPORT))) { - orig->l4src.udp.port = reply->l4dst.udp.port; - orig->l4dst.udp.port = reply->l4src.udp.port; - return 1; - } - if ((flags & (UDP_ORIG_SPORT|UDP_ORIG_DPORT)) - && ((flags & (UDP_REPL_SPORT|UDP_REPL_DPORT)))) - return 1; - - return 0; -} - -static struct ctproto_handler udp = { - .name = "udp", - .protonum = IPPROTO_UDP, - .parse_opts = parse_options, - .final_check = final_check, - .help = help, - .opts = opts, - .version = VERSION, -}; - -static void __attribute__ ((constructor)) init(void); - -static void init(void) -{ - register_proto(&udp); -} diff --git a/cli/extensions/libct_proto_udp.man b/cli/extensions/libct_proto_udp.man deleted file mode 100644 index c67fedf..0000000 --- a/cli/extensions/libct_proto_udp.man +++ /dev/null @@ -1,13 +0,0 @@ -This module matches on UDP-specific fields. -.TP -.BI "--orig-port-src " "PORT" -Source port in original direction -.TP -.BI "--orig-port-dst " "PORT" -Destination port in original direction -.TP -.BI "--reply-port-src " "PORT" -Source port in reply direction -.TP -.BI "--reply-port-dst " "PORT" -Destination port in reply direction diff --git a/cli/include/conntrack.h b/cli/include/conntrack.h deleted file mode 100644 index fb3b9b6..0000000 --- a/cli/include/conntrack.h +++ /dev/null @@ -1,160 +0,0 @@ -#ifndef _CONNTRACK_H -#define _CONNTRACK_H - -#ifdef HAVE_CONFIG_H -#include "../config.h" -#endif - -#include "linux_list.h" -#include -#include - -#define PROGNAME "conntrack" - -#include -#ifndef IPPROTO_SCTP -#define IPPROTO_SCTP 132 -#endif - -enum action { - CT_NONE = 0, - - CT_LIST_BIT = 0, - CT_LIST = (1 << CT_LIST_BIT), - - CT_CREATE_BIT = 1, - CT_CREATE = (1 << CT_CREATE_BIT), - - CT_UPDATE_BIT = 2, - CT_UPDATE = (1 << CT_UPDATE_BIT), - - CT_DELETE_BIT = 3, - CT_DELETE = (1 << CT_DELETE_BIT), - - CT_GET_BIT = 4, - CT_GET = (1 << CT_GET_BIT), - - CT_FLUSH_BIT = 5, - CT_FLUSH = (1 << CT_FLUSH_BIT), - - CT_EVENT_BIT = 6, - CT_EVENT = (1 << CT_EVENT_BIT), - - CT_VERSION_BIT = 7, - CT_VERSION = (1 << CT_VERSION_BIT), - - CT_HELP_BIT = 8, - CT_HELP = (1 << CT_HELP_BIT), - - EXP_LIST_BIT = 9, - EXP_LIST = (1 << EXP_LIST_BIT), - - EXP_CREATE_BIT = 10, - EXP_CREATE = (1 << EXP_CREATE_BIT), - - EXP_DELETE_BIT = 11, - EXP_DELETE = (1 << EXP_DELETE_BIT), - - EXP_GET_BIT = 12, - EXP_GET = (1 << EXP_GET_BIT), - - EXP_FLUSH_BIT = 13, - EXP_FLUSH = (1 << EXP_FLUSH_BIT), - - EXP_EVENT_BIT = 14, - EXP_EVENT = (1 << EXP_EVENT_BIT), -}; -#define NUMBER_OF_CMD 15 - -enum options { - CT_OPT_ORIG_SRC_BIT = 0, - CT_OPT_ORIG_SRC = (1 << CT_OPT_ORIG_SRC_BIT), - - CT_OPT_ORIG_DST_BIT = 1, - CT_OPT_ORIG_DST = (1 << CT_OPT_ORIG_DST_BIT), - - CT_OPT_ORIG = (CT_OPT_ORIG_SRC | CT_OPT_ORIG_DST), - - CT_OPT_REPL_SRC_BIT = 2, - CT_OPT_REPL_SRC = (1 << CT_OPT_REPL_SRC_BIT), - - CT_OPT_REPL_DST_BIT = 3, - CT_OPT_REPL_DST = (1 << CT_OPT_REPL_DST_BIT), - - CT_OPT_REPL = (CT_OPT_REPL_SRC | CT_OPT_REPL_DST), - - CT_OPT_PROTO_BIT = 4, - CT_OPT_PROTO = (1 << CT_OPT_PROTO_BIT), - - CT_OPT_TIMEOUT_BIT = 5, - CT_OPT_TIMEOUT = (1 << CT_OPT_TIMEOUT_BIT), - - CT_OPT_STATUS_BIT = 6, - CT_OPT_STATUS = (1 << CT_OPT_STATUS_BIT), - - CT_OPT_ZERO_BIT = 7, - CT_OPT_ZERO = (1 << CT_OPT_ZERO_BIT), - - CT_OPT_EVENT_MASK_BIT = 8, - CT_OPT_EVENT_MASK = (1 << CT_OPT_EVENT_MASK_BIT), - - CT_OPT_EXP_SRC_BIT = 9, - CT_OPT_EXP_SRC = (1 << CT_OPT_EXP_SRC_BIT), - - CT_OPT_EXP_DST_BIT = 10, - CT_OPT_EXP_DST = (1 << CT_OPT_EXP_DST_BIT), - - CT_OPT_MASK_SRC_BIT = 11, - CT_OPT_MASK_SRC = (1 << CT_OPT_MASK_SRC_BIT), - - CT_OPT_MASK_DST_BIT = 12, - CT_OPT_MASK_DST = (1 << CT_OPT_MASK_DST_BIT), - - CT_OPT_NATRANGE_BIT = 13, - CT_OPT_NATRANGE = (1 << CT_OPT_NATRANGE_BIT), - - CT_OPT_MARK_BIT = 14, - CT_OPT_MARK = (1 << CT_OPT_MARK_BIT), - - CT_OPT_ID_BIT = 15, - CT_OPT_ID = (1 << CT_OPT_ID_BIT), - - CT_OPT_FAMILY_BIT = 16, - CT_OPT_FAMILY = (1 << CT_OPT_FAMILY_BIT), - - CT_OPT_MAX_BIT = CT_OPT_FAMILY_BIT -}; -#define NUMBER_OF_OPT CT_OPT_MAX_BIT+1 - -struct ctproto_handler { - struct list_head head; - - char *name; - u_int16_t protonum; - char *version; - - enum ctattr_protoinfo protoinfo_attr; - - int (*parse_opts)(char c, char *argv[], - struct nfct_tuple *orig, - struct nfct_tuple *reply, - struct nfct_tuple *exptuple, - struct nfct_tuple *mask, - union nfct_protoinfo *proto, - unsigned int *flags); - - int (*final_check)(unsigned int flags, - unsigned int command, - struct nfct_tuple *orig, - struct nfct_tuple *reply); - - void (*help)(); - - struct option *opts; - - unsigned int option_offset; -}; - -extern void register_proto(struct ctproto_handler *h); - -#endif diff --git a/cli/src/conntrack.c b/cli/src/conntrack.c deleted file mode 100644 index 30fbf69..0000000 --- a/cli/src/conntrack.c +++ /dev/null @@ -1,1131 +0,0 @@ -/* - * (C) 2005 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Note: - * Yes, portions of this code has been stolen from iptables ;) - * Special thanks to the the Netfilter Core Team. - * Thanks to Javier de Miguel Rodriguez - * for introducing me to advanced firewalling stuff. - * - * --pablo 13/04/2005 - * - * 2005-04-16 Harald Welte : - * Add support for conntrack accounting and conntrack mark - * 2005-06-23 Harald Welte : - * Add support for expect creation - * 2005-09-24 Harald Welte : - * Remove remaints of "-A" - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef HAVE_ARPA_INET_H -#include -#endif -#include -#include -#include -#include -#include "linux_list.h" -#include "conntrack.h" -#include -#include -#include - -static const char cmdflags[NUMBER_OF_CMD] -= {'L','I','U','D','G','F','E','V','h','L','I','D','G','F','E'}; - -static const char cmd_need_param[NUMBER_OF_CMD] -= { 2, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, 0, 2, 2 }; - -static const char optflags[NUMBER_OF_OPT] -= {'s','d','r','q','p','t','u','z','e','[',']','{','}','a','m','i','f'}; - -static struct option original_opts[] = { - {"dump", 2, 0, 'L'}, - {"create", 1, 0, 'I'}, - {"delete", 1, 0, 'D'}, - {"update", 1, 0, 'U'}, - {"get", 1, 0, 'G'}, - {"flush", 1, 0, 'F'}, - {"event", 1, 0, 'E'}, - {"version", 0, 0, 'V'}, - {"help", 0, 0, 'h'}, - {"orig-src", 1, 0, 's'}, - {"orig-dst", 1, 0, 'd'}, - {"reply-src", 1, 0, 'r'}, - {"reply-dst", 1, 0, 'q'}, - {"protonum", 1, 0, 'p'}, - {"timeout", 1, 0, 't'}, - {"status", 1, 0, 'u'}, - {"zero", 0, 0, 'z'}, - {"event-mask", 1, 0, 'e'}, - {"tuple-src", 1, 0, '['}, - {"tuple-dst", 1, 0, ']'}, - {"mask-src", 1, 0, '{'}, - {"mask-dst", 1, 0, '}'}, - {"nat-range", 1, 0, 'a'}, - {"mark", 1, 0, 'm'}, - {"id", 2, 0, 'i'}, - {"family", 1, 0, 'f'}, - {0, 0, 0, 0} -}; - -#define OPTION_OFFSET 256 - -static struct nfct_handle *cth; -static struct option *opts = original_opts; -static unsigned int global_option_offset = 0; - -/* Table of legal combinations of commands and options. If any of the - * given commands make an option legal, that option is legal (applies to - * CMD_LIST and CMD_ZERO only). - * Key: - * 0 illegal - * 1 compulsory - * 2 optional - */ - -static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = -/* Well, it's better than "Re: Linux vs FreeBSD" */ -{ - /* s d r q p t u z e x y k l a m i f*/ -/*CT_LIST*/ {2,2,2,2,2,0,0,2,0,0,0,0,0,0,2,2,2}, -/*CT_CREATE*/ {2,2,2,2,1,1,1,0,0,0,0,0,0,2,2,0,0}, -/*CT_UPDATE*/ {2,2,2,2,1,2,2,0,0,0,0,0,0,0,2,2,0}, -/*CT_DELETE*/ {2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,2,0}, -/*CT_GET*/ {2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,2,0}, -/*CT_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*CT_EVENT*/ {2,2,2,2,2,0,0,0,2,0,0,0,0,0,2,0,0}, -/*VERSION*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*HELP*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*EXP_LIST*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2}, -/*EXP_CREATE*/{1,1,2,2,1,1,2,0,0,1,1,1,1,0,0,0,0}, -/*EXP_DELETE*/{1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0}, -/*EXP_GET*/ {1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0}, -/*EXP_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*EXP_EVENT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -}; - -static char *lib_dir = CONNTRACK_LIB_DIR; - -static LIST_HEAD(proto_list); - -void register_proto(struct ctproto_handler *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); -} - -static struct ctproto_handler *findproto(char *name) -{ - struct list_head *i; - struct ctproto_handler *cur = NULL, *handler = NULL; - - if (!name) - return handler; - - lib_dir = getenv("CONNTRACK_LIB_DIR"); - if (!lib_dir) - lib_dir = CONNTRACK_LIB_DIR; - - list_for_each(i, &proto_list) { - cur = (struct ctproto_handler *) i; - if (strcmp(cur->name, name) == 0) { - handler = cur; - break; - } - } - - if (!handler) { - char path[sizeof("ct_proto_.so") - + strlen(name) + strlen(lib_dir)]; - sprintf(path, "%s/ct_proto_%s.so", lib_dir, name); - if (dlopen(path, RTLD_NOW)) - handler = findproto(name); - else - fprintf(stderr, "%s\n", dlerror()); - } - - return handler; -} - -enum exittype { - OTHER_PROBLEM = 1, - PARAMETER_PROBLEM, - VERSION_PROBLEM -}; - -void extension_help(struct ctproto_handler *h) -{ - fprintf(stdout, "\n"); - fprintf(stdout, "Proto `%s' help:\n", h->name); - h->help(); -} - -void -exit_tryhelp(int status) -{ - fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n", - PROGNAME, PROGNAME); - exit(status); -} - -static void -exit_error(enum exittype status, char *msg, ...) -{ - va_list args; - - /* On error paths, make sure that we don't leak the memory - * reserved during options merging */ - if (opts != original_opts) { - free(opts); - opts = original_opts; - global_option_offset = 0; - } - va_start(args, msg); - fprintf(stderr,"%s v%s: ", PROGNAME, VERSION); - vfprintf(stderr, msg, args); - va_end(args); - fprintf(stderr, "\n"); - if (status == PARAMETER_PROBLEM) - exit_tryhelp(status); - exit(status); -} - -static void -generic_cmd_check(int command, int options) -{ - int i; - - for (i = 0; i < NUMBER_OF_CMD; i++) { - if (!(command & (1< illegal, 1 => legal, 0 => undecided. */ - - for (j = 0; j < NUMBER_OF_CMD; j++) { - if (!(command & (1<size; i++) - if (strncasecmp(str, p->parameter[i], strlen) == 0) { - *value |= p->value[i]; - ret = 1; - break; - } - - return ret; -} - -static void -parse_parameter(const char *arg, unsigned int *status, int parse_type) -{ - const char *comma; - - while ((comma = strchr(arg, ',')) != NULL) { - if (comma == arg - || !do_parse_parameter(arg, comma-arg, status, parse_type)) - exit_error(PARAMETER_PROBLEM,"Bad parameter `%s'", arg); - arg = comma+1; - } - - if (strlen(arg) == 0 - || !do_parse_parameter(arg, strlen(arg), status, parse_type)) - exit_error(PARAMETER_PROBLEM, "Bad parameter `%s'", arg); -} - -static void -add_command(unsigned int *cmd, const int newcmd, const int othercmds) -{ - if (*cmd & (~othercmds)) - exit_error(PARAMETER_PROBLEM, "Invalid commands combination\n"); - *cmd |= newcmd; -} - -unsigned int check_type(int argc, char *argv[]) -{ - char *table = NULL; - - /* Nasty bug or feature in getopt_long ? - * It seems that it behaves badly with optional arguments. - * Fortunately, I just stole the fix from iptables ;) */ - if (optarg) - return 0; - else if (optind < argc && argv[optind][0] != '-' - && argv[optind][0] != '!') - table = argv[optind++]; - - if (!table) - return 0; - - if (strncmp("expect", table, 6) == 0) - return 1; - else if (strncmp("conntrack", table, 9) == 0) - return 0; - else - exit_error(PARAMETER_PROBLEM, "unknown type `%s'\n", table); - - return 0; -} - -static void set_family(int *family, int new) -{ - if (*family == AF_UNSPEC) - *family = new; - else if (*family != new) - exit_error(PARAMETER_PROBLEM, "mismatched address family\n"); -} - -struct addr_parse { - struct in_addr addr; - struct in6_addr addr6; - unsigned int family; -}; - -int __parse_inetaddr(const char *cp, struct addr_parse *parse) -{ - if (inet_aton(cp, &parse->addr)) - return AF_INET; -#ifdef HAVE_INET_PTON_IPV6 - else if (inet_pton(AF_INET6, cp, &parse->addr6) > 0) - return AF_INET6; -#endif - - exit_error(PARAMETER_PROBLEM, "Invalid IP address `%s'.", cp); -} - -int parse_inetaddr(const char *cp, union nfct_address *address) -{ - struct addr_parse parse; - int ret; - - if ((ret = __parse_inetaddr(cp, &parse)) == AF_INET) - address->v4 = parse.addr.s_addr; - else if (ret == AF_INET6) - memcpy(address->v6, &parse.addr6, sizeof(parse.addr6)); - - return ret; -} - -/* Shamelessly stolen from libipt_DNAT ;). Ranges expected in network order. */ -static void -nat_parse(char *arg, int portok, struct nfct_nat *range) -{ - char *colon, *dash, *error; - struct addr_parse parse; - - memset(range, 0, sizeof(range)); - colon = strchr(arg, ':'); - - if (colon) { - int port; - - if (!portok) - exit_error(PARAMETER_PROBLEM, - "Need TCP or UDP with port specification"); - - port = atoi(colon+1); - if (port == 0 || port > 65535) - exit_error(PARAMETER_PROBLEM, - "Port `%s' not valid\n", colon+1); - - error = strchr(colon+1, ':'); - if (error) - exit_error(PARAMETER_PROBLEM, - "Invalid port:port syntax - use dash\n"); - - dash = strchr(colon, '-'); - if (!dash) { - range->l4min.tcp.port - = range->l4max.tcp.port - = htons(port); - } else { - int maxport; - - maxport = atoi(dash + 1); - if (maxport == 0 || maxport > 65535) - exit_error(PARAMETER_PROBLEM, - "Port `%s' not valid\n", dash+1); - if (maxport < port) - /* People are stupid. */ - exit_error(PARAMETER_PROBLEM, - "Port range `%s' funky\n", colon+1); - range->l4min.tcp.port = htons(port); - range->l4max.tcp.port = htons(maxport); - } - /* Starts with a colon? No IP info... */ - if (colon == arg) - return; - *colon = '\0'; - } - - dash = strchr(arg, '-'); - if (colon && dash && dash > colon) - dash = NULL; - - if (dash) - *dash = '\0'; - - if (__parse_inetaddr(arg, &parse) != AF_INET) - return; - - range->min_ip = parse.addr.s_addr; - if (dash) { - if (__parse_inetaddr(dash+1, &parse) != AF_INET) - return; - range->max_ip = parse.addr.s_addr; - } else - range->max_ip = parse.addr.s_addr; -} - -static void event_sighandler(int s) -{ - fprintf(stdout, "Now closing conntrack event dumping...\n"); - nfct_close(cth); - exit(0); -} - -static const char usage_commands[] = - "Commands:\n" - " -L [table] [options]\t\tList conntrack or expectation table\n" - " -G [table] parameters\t\tGet conntrack or expectation\n" - " -D [table] parameters\t\tDelete conntrack or expectation\n" - " -I [table] parameters\t\tCreate a conntrack or expectation\n" - " -U [table] parameters\t\tUpdate a conntrack\n" - " -E [table] [options]\t\tShow events\n" - " -F [table]\t\t\tFlush table\n"; - -static const char usage_tables[] = - "Tables: conntrack, expect\n"; - -static const char usage_conntrack_parameters[] = - "Conntrack parameters and options:\n" - " -a, --nat-range min_ip[-max_ip]\tNAT ip range\n" - " -m, --mark mark\t\t\tSet mark\n" - " -e, --event-mask eventmask\t\tEvent mask, eg. NEW,DESTROY\n" - " -z, --zero \t\t\t\tZero counters while listing\n" - ; - -static const char usage_expectation_parameters[] = - "Expectation parameters and options:\n" - " --tuple-src ip\tSource address in expect tuple\n" - " --tuple-dst ip\tDestination address in expect tuple\n" - " --mask-src ip\t\tSource mask address\n" - " --mask-dst ip\t\tDestination mask address\n"; - -static const char usage_parameters[] = - "Common parameters and options:\n" - " -s, --orig-src ip\t\tSource address from original direction\n" - " -d, --orig-dst ip\t\tDestination address from original direction\n" - " -r, --reply-src ip\t\tSource addres from reply direction\n" - " -q, --reply-dst ip\t\tDestination address from reply direction\n" - " -p, --protonum proto\t\tLayer 4 Protocol, eg. 'tcp'\n" - " -f, --family proto\t\tLayer 3 Protocol, eg. 'ipv6'\n" - " -t, --timeout timeout\t\tSet timeout\n" - " -u, --status status\t\tSet status, eg. ASSURED\n" - " -i, --id [id]\t\t\tShow or set conntrack ID\n" - ; - - -void usage(char *prog) { - fprintf(stdout, "Tool to manipulate conntrack and expectations. Version %s\n", VERSION); - fprintf(stdout, "Usage: %s [commands] [options]\n", prog); - - fprintf(stdout, "\n%s", usage_commands); - fprintf(stdout, "\n%s", usage_tables); - fprintf(stdout, "\n%s", usage_conntrack_parameters); - fprintf(stdout, "\n%s", usage_expectation_parameters); - fprintf(stdout, "\n%s", usage_parameters); -} - -#define CT_COMPARISON (CT_OPT_PROTO | CT_OPT_ORIG | CT_OPT_REPL | CT_OPT_MARK) - -static struct nfct_tuple orig, reply, mask; -static struct nfct_tuple exptuple; -static struct ctproto_handler *h; -static union nfct_protoinfo proto; -static struct nfct_nat range; -static struct nfct_conntrack *ct; -static struct nfct_expect *exp; -static unsigned long timeout; -static unsigned int status; -static unsigned int mark; -static unsigned int id = NFCT_ANY_ID; -static struct nfct_conntrack_compare cmp; - -int main(int argc, char *argv[]) -{ - int c; - unsigned int command = 0, options = 0; - unsigned int type = 0, event_mask = 0; - unsigned int l3flags = 0, l4flags = 0, metaflags = 0; - int res = 0; - int family = AF_UNSPEC; - struct nfct_conntrack_compare *pcmp; - - while ((c = getopt_long(argc, argv, - "L::I::U::D::G::E::F::hVs:d:r:q:p:t:u:e:a:z[:]:{:}:m:i::f:", - opts, NULL)) != -1) { - switch(c) { - case 'L': - type = check_type(argc, argv); - if (type == 0) - add_command(&command, CT_LIST, CT_NONE); - else if (type == 1) - add_command(&command, EXP_LIST, CT_NONE); - break; - case 'I': - type = check_type(argc, argv); - if (type == 0) - add_command(&command, CT_CREATE, CT_NONE); - else if (type == 1) - add_command(&command, EXP_CREATE, CT_NONE); - break; - case 'U': - type = check_type(argc, argv); - if (type == 0) - add_command(&command, CT_UPDATE, CT_NONE); - else - exit_error(PARAMETER_PROBLEM, "Can't update " - "expectations"); - break; - case 'D': - type = check_type(argc, argv); - if (type == 0) - add_command(&command, CT_DELETE, CT_NONE); - else if (type == 1) - add_command(&command, EXP_DELETE, CT_NONE); - break; - case 'G': - type = check_type(argc, argv); - if (type == 0) - add_command(&command, CT_GET, CT_NONE); - else if (type == 1) - add_command(&command, EXP_GET, CT_NONE); - break; - case 'F': - type = check_type(argc, argv); - if (type == 0) - add_command(&command, CT_FLUSH, CT_NONE); - else if (type == 1) - add_command(&command, EXP_FLUSH, CT_NONE); - break; - case 'E': - type = check_type(argc, argv); - if (type == 0) - add_command(&command, CT_EVENT, CT_NONE); - else if (type == 1) - add_command(&command, EXP_EVENT, CT_NONE); - break; - case 'V': - add_command(&command, CT_VERSION, CT_NONE); - break; - case 'h': - add_command(&command, CT_HELP, CT_NONE); - break; - case 's': - options |= CT_OPT_ORIG_SRC; - if (optarg) { - orig.l3protonum = - parse_inetaddr(optarg, &orig.src); - set_family(&family, orig.l3protonum); - if (orig.l3protonum == AF_INET) - l3flags |= IPV4_ORIG_SRC; - else if (orig.l3protonum == AF_INET6) - l3flags |= IPV6_ORIG_SRC; - } - break; - case 'd': - options |= CT_OPT_ORIG_DST; - if (optarg) { - orig.l3protonum = - parse_inetaddr(optarg, &orig.dst); - set_family(&family, orig.l3protonum); - if (orig.l3protonum == AF_INET) - l3flags |= IPV4_ORIG_DST; - else if (orig.l3protonum == AF_INET6) - l3flags |= IPV6_ORIG_DST; - } - break; - case 'r': - options |= CT_OPT_REPL_SRC; - if (optarg) { - reply.l3protonum = - parse_inetaddr(optarg, &reply.src); - set_family(&family, reply.l3protonum); - if (orig.l3protonum == AF_INET) - l3flags |= IPV4_REPL_SRC; - else if (orig.l3protonum == AF_INET6) - l3flags |= IPV6_REPL_SRC; - } - break; - case 'q': - options |= CT_OPT_REPL_DST; - if (optarg) { - reply.l3protonum = - parse_inetaddr(optarg, &reply.dst); - set_family(&family, reply.l3protonum); - if (orig.l3protonum == AF_INET) - l3flags |= IPV4_REPL_DST; - else if (orig.l3protonum == AF_INET6) - l3flags |= IPV6_REPL_DST; - } - break; - case 'p': - options |= CT_OPT_PROTO; - h = findproto(optarg); - if (!h) - exit_error(PARAMETER_PROBLEM, "proto needed\n"); - orig.protonum = h->protonum; - reply.protonum = h->protonum; - exptuple.protonum = h->protonum; - mask.protonum = h->protonum; - opts = merge_options(opts, h->opts, - &h->option_offset); - break; - case 't': - options |= CT_OPT_TIMEOUT; - if (optarg) - timeout = atol(optarg); - break; - case 'u': { - if (!optarg) - continue; - - options |= CT_OPT_STATUS; - parse_parameter(optarg, &status, PARSE_STATUS); - break; - } - case 'e': - options |= CT_OPT_EVENT_MASK; - parse_parameter(optarg, &event_mask, PARSE_EVENT); - break; - case 'z': - options |= CT_OPT_ZERO; - break; - case '{': - options |= CT_OPT_MASK_SRC; - if (optarg) { - mask.l3protonum = - parse_inetaddr(optarg, &mask.src); - set_family(&family, mask.l3protonum); - } - break; - case '}': - options |= CT_OPT_MASK_DST; - if (optarg) { - mask.l3protonum = - parse_inetaddr(optarg, &mask.dst); - set_family(&family, mask.l3protonum); - } - break; - case '[': - options |= CT_OPT_EXP_SRC; - if (optarg) { - exptuple.l3protonum = - parse_inetaddr(optarg, &exptuple.src); - set_family(&family, exptuple.l3protonum); - } - break; - case ']': - options |= CT_OPT_EXP_DST; - if (optarg) { - exptuple.l3protonum = - parse_inetaddr(optarg, &exptuple.dst); - set_family(&family, exptuple.l3protonum); - } - break; - case 'a': - options |= CT_OPT_NATRANGE; - set_family(&family, AF_INET); - nat_parse(optarg, 1, &range); - break; - case 'm': - options |= CT_OPT_MARK; - mark = atol(optarg); - metaflags |= NFCT_MARK; - break; - case 'i': { - char *s = NULL; - options |= CT_OPT_ID; - if (optarg) - break; - else if (optind < argc && argv[optind][0] != '-' - && argv[optind][0] != '!') - s = argv[optind++]; - - if (s) - id = atol(s); - break; - } - case 'f': - options |= CT_OPT_FAMILY; - if (strncmp(optarg, "ipv4", strlen("ipv4")) == 0) - set_family(&family, AF_INET); - else if (strncmp(optarg, "ipv6", strlen("ipv6")) == 0) - set_family(&family, AF_INET6); - else - exit_error(PARAMETER_PROBLEM, "Unknown " - "protocol family\n"); - break; - default: - if (h && h->parse_opts - &&!h->parse_opts(c - h->option_offset, argv, &orig, - &reply, &exptuple, &mask, &proto, - &l4flags)) - exit_error(PARAMETER_PROBLEM, "parse error\n"); - - /* Unknown argument... */ - if (!h) { - usage(argv[0]); - exit_error(PARAMETER_PROBLEM, "Missing " - "arguments...\n"); - } - break; - } - } - - /* default family */ - if (family == AF_UNSPEC) - family = AF_INET; - - generic_cmd_check(command, options); - generic_opt_check(command, options); - - if (!(command & CT_HELP) - && h && h->final_check - && !h->final_check(l4flags, command, &orig, &reply)) { - usage(argv[0]); - extension_help(h); - exit_error(PARAMETER_PROBLEM, "Missing protocol arguments!\n"); - } - - switch(command) { - - case CT_LIST: - cth = nfct_open(CONNTRACK, 0); - if (!cth) - exit_error(OTHER_PROBLEM, "Can't open handler"); - - if (options & CT_COMPARISON) { - - if (options & CT_OPT_ZERO) - exit_error(PARAMETER_PROBLEM, "Can't use -z " - "with filtering parameters"); - - ct = nfct_conntrack_alloc(&orig, &reply, timeout, - &proto, status, mark, id, - NULL); - if (!ct) - exit_error(OTHER_PROBLEM, "Not enough memory"); - - cmp.ct = ct; - cmp.flags = metaflags; - cmp.l3flags = l3flags; - cmp.l4flags = l4flags; - pcmp = &cmp; - } - - if (options & CT_OPT_ID) - nfct_register_callback(cth, - nfct_default_conntrack_display_id, - (void *) pcmp); - else - nfct_register_callback(cth, - nfct_default_conntrack_display, - (void *) pcmp); - - if (options & CT_OPT_ZERO) - res = - nfct_dump_conntrack_table_reset_counters(cth, family); - else - res = nfct_dump_conntrack_table(cth, family); - nfct_close(cth); - break; - - case EXP_LIST: - cth = nfct_open(EXPECT, 0); - if (!cth) - exit_error(OTHER_PROBLEM, "Can't open handler"); - if (options & CT_OPT_ID) - nfct_register_callback(cth, - nfct_default_expect_display_id, - NULL); - else - nfct_register_callback(cth, - nfct_default_expect_display, - NULL); - res = nfct_dump_expect_list(cth, family); - nfct_close(cth); - break; - - case CT_CREATE: - if ((options & CT_OPT_ORIG) - && !(options & CT_OPT_REPL)) { - reply.l3protonum = orig.l3protonum; - memcpy(&reply.src, &orig.dst, sizeof(reply.src)); - memcpy(&reply.dst, &orig.src, sizeof(reply.dst)); - } else if (!(options & CT_OPT_ORIG) - && (options & CT_OPT_REPL)) { - orig.l3protonum = reply.l3protonum; - memcpy(&orig.src, &reply.dst, sizeof(orig.src)); - memcpy(&orig.dst, &reply.src, sizeof(orig.dst)); - } - if (options & CT_OPT_NATRANGE) - ct = nfct_conntrack_alloc(&orig, &reply, timeout, - &proto, status, mark, id, - &range); - else - ct = nfct_conntrack_alloc(&orig, &reply, timeout, - &proto, status, mark, id, - NULL); - if (!ct) - exit_error(OTHER_PROBLEM, "Not Enough memory"); - - cth = nfct_open(CONNTRACK, 0); - if (!cth) { - nfct_conntrack_free(ct); - exit_error(OTHER_PROBLEM, "Can't open handler"); - } - res = nfct_create_conntrack(cth, ct); - nfct_close(cth); - nfct_conntrack_free(ct); - break; - - case EXP_CREATE: - if (options & CT_OPT_ORIG) - exp = nfct_expect_alloc(&orig, &exptuple, - &mask, timeout, id); - else if (options & CT_OPT_REPL) - exp = nfct_expect_alloc(&reply, &exptuple, - &mask, timeout, id); - if (!exp) - exit_error(OTHER_PROBLEM, "Not enough memory"); - - cth = nfct_open(EXPECT, 0); - if (!cth) { - nfct_expect_free(exp); - exit_error(OTHER_PROBLEM, "Can't open handler"); - } - res = nfct_create_expectation(cth, exp); - nfct_expect_free(exp); - nfct_close(cth); - break; - - case CT_UPDATE: - if ((options & CT_OPT_ORIG) - && !(options & CT_OPT_REPL)) { - reply.l3protonum = orig.l3protonum; - memcpy(&reply.src, &orig.dst, sizeof(reply.src)); - memcpy(&reply.dst, &orig.src, sizeof(reply.dst)); - } else if (!(options & CT_OPT_ORIG) - && (options & CT_OPT_REPL)) { - orig.l3protonum = reply.l3protonum; - memcpy(&orig.src, &reply.dst, sizeof(orig.src)); - memcpy(&orig.dst, &reply.src, sizeof(orig.dst)); - } - ct = nfct_conntrack_alloc(&orig, &reply, timeout, - &proto, status, mark, id, - NULL); - if (!ct) - exit_error(OTHER_PROBLEM, "Not enough memory"); - - cth = nfct_open(CONNTRACK, 0); - if (!cth) { - nfct_conntrack_free(ct); - exit_error(OTHER_PROBLEM, "Can't open handler"); - } - res = nfct_update_conntrack(cth, ct); - nfct_conntrack_free(ct); - nfct_close(cth); - break; - - case CT_DELETE: - if (!(options & CT_OPT_ORIG) && !(options & CT_OPT_REPL)) - exit_error(PARAMETER_PROBLEM, "Can't kill conntracks " - "just by its ID"); - cth = nfct_open(CONNTRACK, 0); - if (!cth) - exit_error(OTHER_PROBLEM, "Can't open handler"); - if (options & CT_OPT_ORIG) - res = nfct_delete_conntrack(cth, &orig, - NFCT_DIR_ORIGINAL, - id); - else if (options & CT_OPT_REPL) - res = nfct_delete_conntrack(cth, &reply, - NFCT_DIR_REPLY, - id); - nfct_close(cth); - break; - - case EXP_DELETE: - cth = nfct_open(EXPECT, 0); - if (!cth) - exit_error(OTHER_PROBLEM, "Can't open handler"); - if (options & CT_OPT_ORIG) - res = nfct_delete_expectation(cth, &orig, id); - else if (options & CT_OPT_REPL) - res = nfct_delete_expectation(cth, &reply, id); - nfct_close(cth); - break; - - case CT_GET: - cth = nfct_open(CONNTRACK, 0); - if (!cth) - exit_error(OTHER_PROBLEM, "Can't open handler"); - nfct_register_callback(cth, nfct_default_conntrack_display, - NULL); - if (options & CT_OPT_ORIG) - res = nfct_get_conntrack(cth, &orig, - NFCT_DIR_ORIGINAL, id); - else if (options & CT_OPT_REPL) - res = nfct_get_conntrack(cth, &reply, - NFCT_DIR_REPLY, id); - nfct_close(cth); - break; - - case EXP_GET: - cth = nfct_open(EXPECT, 0); - if (!cth) - exit_error(OTHER_PROBLEM, "Can't open handler"); - nfct_register_callback(cth, nfct_default_expect_display, - NULL); - if (options & CT_OPT_ORIG) - res = nfct_get_expectation(cth, &orig, id); - else if (options & CT_OPT_REPL) - res = nfct_get_expectation(cth, &reply, id); - nfct_close(cth); - break; - - case CT_FLUSH: - cth = nfct_open(CONNTRACK, 0); - if (!cth) - exit_error(OTHER_PROBLEM, "Can't open handler"); - res = nfct_flush_conntrack_table(cth, AF_INET); - nfct_close(cth); - break; - - case EXP_FLUSH: - cth = nfct_open(EXPECT, 0); - if (!cth) - exit_error(OTHER_PROBLEM, "Can't open handler"); - res = nfct_flush_expectation_table(cth, AF_INET); - nfct_close(cth); - break; - - case CT_EVENT: - if (options & CT_OPT_EVENT_MASK) - cth = nfct_open(CONNTRACK, event_mask); - else - cth = nfct_open(CONNTRACK, NFCT_ALL_CT_GROUPS); - - if (!cth) - exit_error(OTHER_PROBLEM, "Can't open handler"); - signal(SIGINT, event_sighandler); - - if (options & CT_COMPARISON) { - ct = nfct_conntrack_alloc(&orig, &reply, timeout, - &proto, status, mark, id, - NULL); - if (!ct) - exit_error(OTHER_PROBLEM, "Not enough memory"); - - cmp.ct = ct; - cmp.flags = metaflags; - cmp.l3flags = l3flags; - cmp.l4flags = l4flags; - pcmp = &cmp; - } - - nfct_register_callback(cth, - nfct_default_conntrack_event_display, - (void *) pcmp); - res = nfct_event_conntrack(cth); - nfct_close(cth); - break; - - case EXP_EVENT: - cth = nfct_open(EXPECT, NF_NETLINK_CONNTRACK_EXP_NEW); - if (!cth) - exit_error(OTHER_PROBLEM, "Can't open handler"); - signal(SIGINT, event_sighandler); - nfct_register_callback(cth, nfct_default_expect_display, - NULL); - res = nfct_event_expectation(cth); - nfct_close(cth); - break; - - case CT_VERSION: - fprintf(stdout, "%s v%s\n", PROGNAME, VERSION); - break; - case CT_HELP: - usage(argv[0]); - if (options & CT_OPT_PROTO) - extension_help(h); - break; - default: - usage(argv[0]); - break; - } - - if (opts != original_opts) { - free(opts); - opts = original_opts; - global_option_offset = 0; - } - - if (res < 0) { - fprintf(stderr, "Operation failed: %s\n", err2str(res, command)); - exit(OTHER_PROBLEM); - } - - return 0; -} diff --git a/cli/test.sh b/cli/test.sh deleted file mode 100644 index 4694236..0000000 --- a/cli/test.sh +++ /dev/null @@ -1,110 +0,0 @@ -CONNTRACK=conntrack - -SRC=1.1.1.1 -DST=2.2.2.2 -SPORT=2005 -DPORT=21 - -case $1 in - dump) - echo "Dumping conntrack table" - $CONNTRACK -L - ;; - flush) - echo "Flushing conntrack table" - $CONNTRACK -F - ;; - new) - echo "creating a new conntrack" - $CONNTRACK -I --orig-src $SRC --orig-dst $DST \ - --reply-src $DST --reply-dst $SRC -p tcp \ - --orig-port-src $SPORT --orig-port-dst $DPORT \ - --reply-port-src $DPORT --reply-port-dst $SPORT \ - --state LISTEN -u SEEN_REPLY -t 50 - ;; - new-simple) - echo "creating a new conntrack (simplified)" - $CONNTRACK -I --orig-src $SRC --orig-dst $DST \ - -p tcp --orig-port-src $SPORT --orig-port-dst $DPORT \ - --state LISTEN -u SEEN_REPLY -t 50 - ;; - new-nat) - echo "creating a new conntrack (NAT)" - $CONNTRACK -I --orig-src $SRC --orig-dst $DST \ - -p tcp --orig-port-src $SPORT --orig-port-dst $DPORT \ - --state LISTEN -u SEEN_REPLY,SRC_NAT -t 50 -a 8.8.8.8 - ;; - get) - echo "getting a conntrack" - $CONNTRACK -G --orig-src $SRC --orig-dst $DST \ - -p tcp --orig-port-src $SPORT --orig-port-dst $DPORT \ - --reply-port-src $DPORT --reply-port-dst $SPORT - ;; - change) - echo "change a conntrack" - $CONNTRACK -U --orig-src $SRC --orig-dst $DST \ - --reply-src $DST --reply-dst $SRC -p tcp \ - --orig-port-src $SPORT --orig-port-dst $DPORT \ - --reply-port-src $DPORT --reply-port-dst $SPORT \ - --state TIME_WAIT -u ASSURED,SEEN_REPLY -t 500 - ;; - delete) - $CONNTRACK -D --orig-src $SRC --orig-dst $DST \ - -p tcp --orig-port-src $SPORT --orig-port-dst $DPORT - ;; - output) - proc=$(cat /proc/net/ip_conntrack | wc -l) - netl=$($CONNTRACK -L | wc -l) - count=$(cat /proc/sys/net/ipv4/netfilter/ip_conntrack_count) - if [ $proc -ne $netl ]; then - echo "proc is $proc and netl is $netl and count is $count" - else - if [ $proc -ne $count ]; then - echo "proc is $proc and netl is $netl and count is $count" - else - echo "now $proc" - fi - fi - ;; - dump-expect) - $CONNTRACK -L expect - ;; - flush-expect) - $CONNTRACK -F expect - ;; - create-expect) - # requires modprobe ip_conntrack_ftp - $CONNTRACK -I expect --orig-src $SRC --orig-dst $DST \ - --tuple-src 4.4.4.4 --tuple-dst 5.5.5.5 \ - --mask-src 255.255.255.0 --mask-dst 255.255.255.255 \ - -p tcp --orig-port-src $SPORT --orig-port-dst $DPORT \ - -t 200 --tuple-port-src 10 --tuple-port-dst 300 \ - --mask-port-src 10 --mask-port-dst 300 - ;; - get-expect) - $CONNTRACK -G expect --orig-src 4.4.4.4 --orig-dst 5.5.5.5 \ - --p tcp --orig-port-src 0 --orig-port-dst 0 \ - --mask-port-src 10 --mask-port-dst 11 - ;; - delete-expect) - $CONNTRACK -D expect --orig-src 4.4.4.4 \ - --orig-dst 5.5.5.5 -p tcp --orig-port-src 0 \ - --orig-port-dst 0 --mask-port-src 10 --mask-port-dst 11 - ;; - *) - echo "Usage: $0 [dump" - echo " |new" - echo " |new-simple" - echo " |new-nat" - echo " |get" - echo " |change" - echo " |delete" - echo " |output" - echo " |flush" - echo " |dump-expect" - echo " |flush-expect" - echo " |create-expect" - echo " |get-expect" - echo " |delete-expect]" - ;; -esac diff --git a/configure.in b/configure.in new file mode 100644 index 0000000..5bd9815 --- /dev/null +++ b/configure.in @@ -0,0 +1,106 @@ +AC_INIT(conntrackd, 0.9.2, pablo@netfilter.org) + +AC_CANONICAL_SYSTEM + +AM_INIT_AUTOMAKE + +AC_PROG_CC +AM_PROG_LIBTOOL +AC_PROG_INSTALL +AC_PROG_LN_S +AM_PROG_LEX +AC_PROG_YACC + +case $target in +*-*-linux*) ;; +*) AC_MSG_ERROR([Linux only, dude!]);; +esac + +AC_CHECK_PROGS(XYACC,$YACC bison yacc,none) +if test "$XYACC" = "none" +then + echo "*** Error: No suitable bison/yacc found. ***" + echo " Please install the 'bison' package." + exit 1 +fi +AC_CHECK_PROGS(XLEX,$LEX flex lex,none) +if test "$XLEX" = "none" +then + echo "*** Error: No suitable bison/yacc found. ***" + echo " Please install the 'bison' package." + exit 1 +fi + +AC_CHECK_HEADERS([linux/capability.h],, [AC_MSG_ERROR([Cannot find linux/capabibility.h])]) + +# Checks for libraries. +# FIXME: Replace `main' with a function in `-lc': +dnl AC_CHECK_LIB([c], [main]) +# FIXME: Replace `main' with a function in `-ldl': + +AC_CHECK_LIB([nfnetlink], [nfnl_talk] ,,,[-lnfnetlink]) +AC_CHECK_LIB([netfilter_conntrack], [nfct_dump_conntrack_table] ,,,[-lnetfilter_conntrack]) +AC_CHECK_LIB([pthread], [pthread_create] ,,,[-lpthread]) + +AC_CHECK_HEADERS(arpa/inet.h) +dnl check for inet_pton +AC_CHECK_FUNCS(inet_pton) +dnl Some systems have it, but not IPv6 +if test "$ac_cv_func_inet_pton" = "yes" ; then +AC_MSG_CHECKING(if inet_pton supports IPv6) +AC_TRY_RUN( + [ +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +int main() + { + struct in6_addr addr6; + if (inet_pton(AF_INET6, "::1", &addr6) < 1) + exit(1); + else + exit(0); + } + ], [ AC_MSG_RESULT(yes) + AC_DEFINE_UNQUOTED(HAVE_INET_PTON_IPV6, 1, [Define to 1 if inet_pton supports IPv6.]) + ], AC_MSG_RESULT(no), AC_MSG_RESULT(no)) +fi + +# Checks for header files. +dnl AC_HEADER_STDC +dnl AC_CHECK_HEADERS([netinet/in.h stdlib.h]) + +# Checks for typedefs, structures, and compiler characteristics. +dnl AC_C_CONST +dnl AC_C_INLINE + +# Checks for library functions. +dnl AC_FUNC_MALLOC +dnl AC_FUNC_VPRINTF +dnl AC_CHECK_FUNCS([memset]) + +dnl-------------------------------- + +if test ! -z "$libdir"; then + MODULE_DIR="\\\"$libdir/conntrack/\\\"" + CFLAGS="$CFLAGS -DCONNTRACK_LIB_DIR=$MODULE_DIR" +fi + +dnl-------------------------------- + +dnl AC_CONFIG_FILES([Makefile +dnl debug/Makefile +dnl debug/src/Makefile +dnl extensions/Makefile +dnl src/Makefile]) + +AC_OUTPUT(Makefile src/Makefile include/Makefile extensions/Makefile examples/Makefile examples/stats/Makefile examples/sync/Makefile examples/sync/persistent/Makefile examples/sync/nack/Makefile examples/sync/persistent/node1/Makefile examples/sync/persistent/node2/Makefile examples/sync/nack/node1/Makefile examples/sync/nack/node2/Makefile) diff --git a/conntrack.8 b/conntrack.8 new file mode 100644 index 0000000..307180b --- /dev/null +++ b/conntrack.8 @@ -0,0 +1,142 @@ +.TH CONNTRACK 8 "Jun 23, 2005" "" "" + +.\" Man page written by Harald Welte . diff --git a/daemon/AUTHORS b/daemon/AUTHORS deleted file mode 100644 index e6c2f6b..0000000 --- a/daemon/AUTHORS +++ /dev/null @@ -1 +0,0 @@ -Pablo Neira Ayuso diff --git a/daemon/CHANGELOG b/daemon/CHANGELOG deleted file mode 100644 index afab61d..0000000 --- a/daemon/CHANGELOG +++ /dev/null @@ -1,184 +0,0 @@ -version 0.9.3 (yet unreleased) ------------------------------- -o fix commit of confirmed expectations (reported by Nishit Shah) -o fix double increment of counters in cache_update_force() (Niko Tyni) -o nl_dump_handler must return NFCT_CB_CONTINUE (Niko Tyni) -o initialize buffer in nl_event_handler() and nl_dump_handler() (Niko Tyni) -o CacheCommit value can be set via conntrackd.conf for the NACK approach -o fix leaks in the hashtable/cache flush path (Niko Tyni) -o fix leak if a connection already exists in the cache (Niko Tyni) -o introduce a new header that encapsulates netlink messages -o remove all '_entry' tail from all functions in cache.c -o split cache.c: move cache iterators to file cache_iterators.c -o fix inconsistencies in the cache API related to counters -o cleanup 'usage' message -o fix typo in examples/sync/nack/node1/conntrackd.conf -o introduce message checksumming as described in RFC1071 (enabled by default) -o major cleanups in the synchronization code -o just warn once that the maximum netlink socket buffer has been reached -o fix ignore conntrack entries by IP and introduce ignore pool abstraction layer -o introduce netlink socket buffer overrun handler -o constification of hash, compare and hashtable_test functions in hash.c -o introduce ACKnowledgement mechanisms to reduce the size of the resend queue -o remove OK messages at startup since provide useless data -o fix compilation warning in mcast.c: recvfrom takes socklen_t not size_t -o add a lock per buffer: makes buffer code thread safe -o introduce 'Replicate' clause to explicitely set states to be replicated -o kill cache feature abuse: introduce nicer cache hooks for sync algorithms -o fix oversized buffer allocated in the stack in the cache functions -o add support to dump internal/external cache in XML format '-x' - -version 0.9.2 (2006/01/17) --------------------------- -o remove spamming packet lost messages -o generalize network netlink sequence tracking -o fix bogus error message on resync `-R' -o fix endianess issues in the network netlink message -o introduce generic netlink multicast primitives to send and receive -o fix bogus replayed multicast message due to sequence numbering wraparound -o introduce counter for malformed netlink messages received -o introduce a new syntax for the `Sync' section in the configuration file -o several cleanups and remove unused variables -o add autostuff to include examples in the tarball (reported by Victor Lozano) -o use the new API available in libnetfilter_conntrack-0.0.50 -o implement a NACK based protocol for replication - -version 0.9.1 (2006/11/06) --------------------------- -o conntrackd requires kernel >= 2.6.18 -o remove bogus TIMERS_MODE constant -o implement bulk mode '-B': first works to address the preemption issue -o fix minor reduction conflicts in the configfile grammar -o check for CAP_NET_ADMIN instead of requiring root privileges -o check that linux/capability.h exists -o fix formatting at dump statistics '-s' -o move dump traffic stats before multicast traffic stats -o move event and dump handler to a generic infrastructure: kill events.c file -o kill unused function inc_ct_stats -o kill file resync.h -o cleanup broadcast_sync: renamed to mcast_send_sync -o sed 's/perror/debug/g' local.c -o fix bogus increment of update_fail stats at dump stage -o display descriptive error if we can't connect to conntrackd via UNIX socket -o remove debugging message from alarm.c -o move dump_mcast_stats to mcast.c where it really belongs -o rename stats.c to traffic_stats.c -o check for replayed/lost multicast message: simple seq tracking w/o recovery -o reissue nfnl_catch on ENOENT error: a message for other subsystem -o remove test/ directory in tree -o improve cache commit stats -o kill last_commit and last_flush from cache statistics: use the logfile -o recover cache naming for dump stats `-s' -o display multicast sequence tracking statistics: packets lost and replayed -o zero ct_sync_state and ct_stats_state structures after allocation -o improve keepalived scripts: - - resync with conntrack table on transition to master - - send bulk on transition to backup -o implement alarm cascade of ten levels -o implement timer cache flavour: limited life of entries in the external cache -o implement a global lock that protects operation with conntrack entries -o remove debug checking in cache_del_entry -o set a reduced timeout for committed entries: 180 seconds by default -o update comments on the sync-mode code -o introduce delay destroy messages facility -o increase timer for external states from 60 to 180 seconds -o remove unused replicate/dont_replicated constants -o fix cache entry clashing issue (reported by Maik Hentsche) -o fix bogus increment of error stats in the external cache -o remove pollution generated by `[REQ] cache dump' message from logfile - -version 0.9.0 (2006/09/17) --------------------------- -o implement initial for IPv6 (untested) -o implement generic extensible cache: kill the internal and external caches -o implement persistence cache feature -o implement lifetime cache feature -o modify UNIX facilities identification numbers: - separate master conntrack facilities and internal plugin facilities -o break backward compatibility of configuration file: - remove IgnoreLoopback, use IgnoreTrafficFor instead - remove IgnoreMulticastTraffic, use IgnoreTrafficFor instead -o merge event/event_subsys and sync/sync_subsys initialization to run.c -o improve control of the iteration process in the hashtables -o fix wrong locking in the alarm thread -o supersede AcceptNAT by StripNAT clause -o replace ignore traffic array by a hashtable -o move lockfile checking before daemonization -o on initialization error give a descriptive error -o introduce netlink socket size grown limitator -o introduce force resync with master conntrack table facility '-R' -o ignore SIGPIPE signal -o kill post_step since it is not used anymore - -version 0.8.3 (2006/09/03) --------------------------- -Author: Maik Hentsche - -o Fix typo in conntrackd -h -o Disable debugging messages by default -o No signals while signals handlings -o Add extra checkings at forking -o Check maximum size for file passed via -C - -Author: Pablo Neira Ayuso - -o retry select() if EINTR is returned (Reported by Maik Hentsche) -o Fix bug in slist_for_each_entry (Reported by Maik Hetsche) -o Signal handler registration done after intialization -o Implement alarm thread (based on Maik Hentsche's patch) -o Fix segfault on conntrackd -k (Reported by Maik Hentsche) -o Fix bug on alarm removal (Reported by Maik Hentsche) -o configure stops if bison, flex or yacc are not installed - -version 0.8.2 (2006/07/05) --------------------------- -o RelaxTransitions clause introduced in Sync mode -o multicast messages sequence tracking -o SocketBufferSize clause to set up the netlink socket buffer -o use new libnfnetlink API to solve limitations of nfnl_listen -o extra sanity checkings for netlink multicast messages -o improve statistics -o tons of cleanups 8) - -version 0.8.1 (2006/06/13) --------------------------- -o -f now just flushes the internal and external caches -o -F flushes the master conntrack table -o fix segfault under heavy load and signal received -o added -S mode for statistics: still needs more thinking - -version 0.8.0 (2006/06/11) --------------------------- -o more work to generalize the daemon: now it's ready to implement -modular support for adaptive timers and conntrack statistics, time -to implement them ;). This is *still* a work in progress. - -version 0.7.2 (2006/06/05) --------------------------- -o stupid bug in normal and alarm caches initialization: flush unset -o fix racy signal handling - -version 0.7.1 (2006/06/05) --------------------------- -o Bugfix for multicast sockets communication - -version 0.7 (2006/06/01) ------------------------- -o Major code re-structuration: internal and external cache abstraction -o sequence tracking for event messages -o expect more changes, I still dislike some stuff in its current status ;) - -version 0.6 (2006/05/31) ------------------------- -o Lock file support -o use new API nfct_conntrack_event_raw -o major code clean ups - -version 0.5 (2006/05/30) -------------------------- -o Fix multicast server binds to wrong interface -o Include clause `IgnoreProtocol', deprecates IgnoreUDP and IgnoreICMP - -version 0.4 (2006/05/29) ------------------------- -o Initial release diff --git a/daemon/CONTRIBUTORS b/daemon/CONTRIBUTORS deleted file mode 100644 index c5e40b4..0000000 --- a/daemon/CONTRIBUTORS +++ /dev/null @@ -1,3 +0,0 @@ -Maik Hentsche : - - Feedback & Brainstorming - - Bug hunting diff --git a/daemon/INSTALL b/daemon/INSTALL deleted file mode 100644 index 0de8dc0..0000000 --- a/daemon/INSTALL +++ /dev/null @@ -1,199 +0,0 @@ -Copyright (C) 2006-2007 Pablo Neira Ayuso - -1.Basic Installation -==================== - - To compile and install 'conntrackd' just follow the classical steps: - - $ ./configure - $ make - # make install - # mkdir /etc/conntrackd/ - -2.1. Synchronization Mode -========================= - - Conntrackd can replicate the status of the connections that are currently - being processed by your stateful firewall based on Linux. This section - describes how to setup the daemon in synchronization mode: - -2.1.1. Requirements - - You have to install the following software in order to get conntrackd working, - make sure that you have installed them correctly before going forward: - - o linux kernel version >= 2.6.18 (http://www.kernel.org) with support for: - - connection tracking system (quite obvious ;) - - nfnetlink - - ctnetlink (ip_conntrack_netlink) - - connection tracking event notification API - - o libnfnetlink: the netfilter netlink library - - Since conntrackd version 0.9.2 you can used the official release availble at - http://www.netfilter.org/projects/libnfnetlink/files/ - - Up to conntrackd version 0.9.1 use the unofficial release available at the - download section - - o libnetfilter_conntrack: the netfilter conntrack library - - Since conntrackd version 0.9.2 you can used the official release availble at - http://www.netfilter.org/projects/libnetfilter_conntrack/files/ - - Up to conntrackd version 0.9.1 use the unnoficial release available at the - download section - - o Keepalived version 1.x (http://www.keepalived.org) - check if your distribution comes with a recent version - -2.1.2. Configuration - - 1) Setting up keepalived - - There is an example file available inside the conntrackd tarball: - - For node 1: conntrackd-x.x.x/examples/sync/node1/keepalived.conf - For node 2: conntrackd-x.x.x/examples/sync/node2/keepalived.conf - - These files can be used to set up a simple VRRP cluster composed of - two machines that hold the virtual IPs 192.168.0.100 on eth0 and - 192.168.1.100 on eth1. - - If you are not familiar with keepalived, please read the official - docs available at http://www.keepalived.org - - Please, make sure that keepalived is correctly working before passing - to step 2) - - 2) Setting up conntrackd - - To setup 'conntrackd' in synchronization mode, you have to put the - configuration file in the directory /etc/conntrackd. - - On node 1: - # cp examples/sync/_type_/node1/conntrackd.conf /etc/conntrackd.conf - - On node 2: - # cp examples/sync/_type_/node1/conntrackd.conf /etc/conntrackd.conf - - Where _type_ is the synchronization type selected, currently there are - two: the persistent mode and the NACK mode. The persistent mode consumes - more resources than the NACK mode, however the NACK mode is still - experimental - - Do not forget to edit the files in order to adapt them to the - setting that you are deploying. - - Note: If you don't want to put the config file under /etc/conntrackd, - just tell conntrackd where to find it passing the option -C - - 3) Running conntrackd - - Conntrackd can run in console mode, in that case just type 'conntrackd', - otherwise, if you want to run it in daemon mode the type 'conntrackd -d'. - - 4) Checking that conntrackd is working fine - - Conntrackd comes with several facilities to check its status: - - - Dump the cache of connections that are currently being processed by - this node (aka. internal cache): - - # conntrackd -i - - - Dump the cache of connections that has been transfered from - others active nodes in the network (aka. external cache) - - # conntrackd -e - - - Dump statistics collected by the replication daemon: - - # conntrackd -s - - 5) Setting up interaction with keepalived - - If keepalived detects the failure of the active node, then it designates - a candidate node that will replace the failing active. On such event, - the external cache, eg. the cache that contains the connections processed - by other nodes, must be commited. To commit the external cache, just type: - - # conntrackd -c - - See that keepalived provides a shell script interface to interact with - other programs, so we can automate the process of commiting the external - cache by introducing the following line in the keepalived file: - - notify_master /etc/conntrackd/script_master.sh - - The script 'script_master.sh' just the following: - - #!/bin/sh - /usr/sbin/conntrackd -c - - Therefore, on failure event, the candidate node takes over the virtual - IPs and the connections that the failing active was processing. Observe - that this file differs for the NACK mode. - - 6) Disable TCP window tracking - - Until the appropiate patches don't go into kernel mainline, you will have - to disable TCP window tracking, consider this as a temporary solution: - - # echo 1 > /proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_be_liberal - -2.2. Statistics mode -==================== - - Conntrackd can also run as statistics daemon, if you are not interested in - this mode, just skip it. It is not required in order to get the - synchronization mode working. This section details how to setup the daemon - in statistics mode: - -2.2.1. Requirements - - You have to install the following software in order to get conntrackd working, - make sure that you have them installed correctly before going forward: - - o linux kernel version >= 2.6.18 (http://www.kernel.org) with support for: - - connection tracking system - - nfnetlink - - ctnetlink (ip_conntrack_netlink) - - connection tracking event notification API - - o libnfnetlink: the netfilter netlink library - - Since conntrackd version 0.9.2 you can used the official release availble at - http://www.netfilter.org/projects/libnfnetlink/files/ - - Up to conntrackd version 0.9.1 use the unofficial release available at the - download section - - o libnetfilter_conntrack: the netfilter conntrack library - - Since conntrackd version 0.9.2 you can used the official release availble at - http://www.netfilter.org/projects/libnetfilter_conntrack/files/ - - Up to conntrackd version 0.9.1 use the unnoficial release available at the - download section - -2.2.2. Configuration - - Setting up conntrackd in statistics mode is rather easy. Just copy the - configuration file - - # cp examples/stats/conntrackd.conf /etc/conntrackd.conf - -2.2.3. Running conntrackd in statistics mode - - To run conntrackd in statistics mode: - - # conntrackd -S - - Alternatively, you can run conntrackd in daemon mode: - - # conntrackd -S -d - - In order to dump the statistics, just type: - - # conntrackd -s diff --git a/daemon/Make_global.am b/daemon/Make_global.am deleted file mode 100644 index 685add7..0000000 --- a/daemon/Make_global.am +++ /dev/null @@ -1 +0,0 @@ -INCLUDES=$(all_includes) -I$(top_srcdir)/include diff --git a/daemon/Makefile.am b/daemon/Makefile.am deleted file mode 100644 index 998f4c6..0000000 --- a/daemon/Makefile.am +++ /dev/null @@ -1,21 +0,0 @@ -include Make_global.am - -# not a GNU package. You can remove this line, if -# have all needed files, that a GNU package needs -AUTOMAKE_OPTIONS = foreign dist-bzip2 1.6 - -# man_MANS = "" -# EXTRA_DIST = $(man_MANS) Make_global.am debian -EXTRA_DIST = Make_global.am CHANGELOG TODO - -SUBDIRS = src -DIST_SUBDIRS = include src examples -LINKOPTS = -lnfnetlink -lnetfilter_conntrack -lpthread -AM_CFLAGS = -g - -$(OBJECTS): libtool -libtool: $(LIBTOOL_DEPS) - $(SHELL) ./config.status --recheck - -dist-hook: - rm -rf `find $(distdir)/debian -name .svn` diff --git a/daemon/TODO b/daemon/TODO deleted file mode 100644 index 130b1f8..0000000 --- a/daemon/TODO +++ /dev/null @@ -1,18 +0,0 @@ -There are several tasks that are pending to be done, I have classified them -by dificulty levels: - -Relatively easy -=============== - -- test ipv6 support -- improve shell scripts -- test NACK based protocol -- manpage for conntrackd - -Requires some work -================== - -- study better keepalived transitions -- implement support for TCP window tracking (patches are on the table) - - at the moment you have to disable it: - echo 1 > /proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_be_liberal diff --git a/daemon/autogen.sh b/daemon/autogen.sh deleted file mode 100755 index e76d3ef..0000000 --- a/daemon/autogen.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/sh - -run () -{ - echo "running: $*" - eval $* - - if test $? != 0 ; then - echo "error: while running '$*'" - exit 1 - fi -} - -run aclocal -run libtoolize -f -#run autoheader -run automake -a -run autoconf diff --git a/daemon/configure.in b/daemon/configure.in deleted file mode 100644 index 92e512a..0000000 --- a/daemon/configure.in +++ /dev/null @@ -1,106 +0,0 @@ -AC_INIT(conntrackd, 0.9.2, pablo@netfilter.org) - -AC_CANONICAL_SYSTEM - -AM_INIT_AUTOMAKE - -AC_PROG_CC -AM_PROG_LIBTOOL -AC_PROG_INSTALL -AC_PROG_LN_S -AM_PROG_LEX -AC_PROG_YACC - -case $target in -*-*-linux*) ;; -*) AC_MSG_ERROR([Linux only, dude!]);; -esac - -AC_CHECK_PROGS(XYACC,$YACC bison yacc,none) -if test "$XYACC" = "none" -then - echo "*** Error: No suitable bison/yacc found. ***" - echo " Please install the 'bison' package." - exit 1 -fi -AC_CHECK_PROGS(XLEX,$LEX flex lex,none) -if test "$XLEX" = "none" -then - echo "*** Error: No suitable bison/yacc found. ***" - echo " Please install the 'bison' package." - exit 1 -fi - -AC_CHECK_HEADERS([linux/capability.h],, [AC_MSG_ERROR([Cannot find linux/capabibility.h])]) - -# Checks for libraries. -# FIXME: Replace `main' with a function in `-lc': -dnl AC_CHECK_LIB([c], [main]) -# FIXME: Replace `main' with a function in `-ldl': - -AC_CHECK_LIB([nfnetlink], [nfnl_talk] ,,,[-lnfnetlink]) -AC_CHECK_LIB([netfilter_conntrack], [nfct_dump_conntrack_table] ,,,[-lnetfilter_conntrack]) -AC_CHECK_LIB([pthread], [pthread_create] ,,,[-lpthread]) - -AC_CHECK_HEADERS(arpa/inet.h) -dnl check for inet_pton -AC_CHECK_FUNCS(inet_pton) -dnl Some systems have it, but not IPv6 -if test "$ac_cv_func_inet_pton" = "yes" ; then -AC_MSG_CHECKING(if inet_pton supports IPv6) -AC_TRY_RUN( - [ -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif -int main() - { - struct in6_addr addr6; - if (inet_pton(AF_INET6, "::1", &addr6) < 1) - exit(1); - else - exit(0); - } - ], [ AC_MSG_RESULT(yes) - AC_DEFINE_UNQUOTED(HAVE_INET_PTON_IPV6, 1, [Define to 1 if inet_pton supports IPv6.]) - ], AC_MSG_RESULT(no), AC_MSG_RESULT(no)) -fi - -# Checks for header files. -dnl AC_HEADER_STDC -dnl AC_CHECK_HEADERS([netinet/in.h stdlib.h]) - -# Checks for typedefs, structures, and compiler characteristics. -dnl AC_C_CONST -dnl AC_C_INLINE - -# Checks for library functions. -dnl AC_FUNC_MALLOC -dnl AC_FUNC_VPRINTF -dnl AC_CHECK_FUNCS([memset]) - -dnl-------------------------------- - -dnl if test ! -z "$libdir"; then -dnl MODULE_DIR="\\\"$libdir/conntrack/\\\"" -dnl CFLAGS="$CFLAGS -DCONNTRACK_LIB_DIR=$MODULE_DIR" -dnl fi - -dnl-------------------------------- - -dnl AC_CONFIG_FILES([Makefile -dnl debug/Makefile -dnl debug/src/Makefile -dnl extensions/Makefile -dnl src/Makefile]) - -AC_OUTPUT(Makefile src/Makefile include/Makefile examples/Makefile examples/stats/Makefile examples/sync/Makefile examples/sync/persistent/Makefile examples/sync/nack/Makefile examples/sync/persistent/node1/Makefile examples/sync/persistent/node2/Makefile examples/sync/nack/node1/Makefile examples/sync/nack/node2/Makefile) diff --git a/daemon/examples/Makefile.am b/daemon/examples/Makefile.am deleted file mode 100644 index be83d42..0000000 --- a/daemon/examples/Makefile.am +++ /dev/null @@ -1 +0,0 @@ -SUBDIRS = stats sync diff --git a/daemon/examples/debian.conntrackd.init.d b/daemon/examples/debian.conntrackd.init.d deleted file mode 100644 index ba847dd..0000000 --- a/daemon/examples/debian.conntrackd.init.d +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/sh -# -# /etc/init.d/conntrackd -# -# Maximilian Wilhelm -# -- Mon, 06 Nov 2006 18:39:07 +0100 -# - -export PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin - -NAME="conntrackd" -DAEMON=`command -v conntrackd` -CONFIG="/etc/conntrack/conntrackd.conf" -PIDFILE="/var/run/${NAME}.pid" - - -# Gracefully exit if there is no daemon (debian way of life) -if [ ! -x "${DAEMON}" ]; then - exit 0 -fi - -# Check for config file -if [ ! -f /etc/conntrackd/conntrackd.conf ]; then - echo "Error: There is no config file for $NAME" >&2 - exit 1; -fi - -case "$1" in - start) - echo -n "Starting $NAME: " - start-stop-daemon --start --quiet --make-pidfile --pidfile "/var/run/${NAME}.pid" --background --exec "${DAEMON}" && echo "done." || echo "FAILED!" - ;; - stop) - echo -n "Stopping $NAME:" - start-stop-daemon --stop --quiet --oknodo --pidfile "/var/run/${NAME}.pid" && echo "done." || echo "FAILED!" - ;; - - restart) - $0 start - $0 stop - ;; - - *) - echo "Usage: /etc/init.d/conntrackd {start|stop|restart}" - exit 1 -esac - -exit 0 diff --git a/daemon/examples/stats/Makefile.am b/daemon/examples/stats/Makefile.am deleted file mode 100644 index b43c3b8..0000000 --- a/daemon/examples/stats/Makefile.am +++ /dev/null @@ -1 +0,0 @@ -EXTRA_DIST = conntrackd.conf diff --git a/daemon/examples/stats/conntrackd.conf b/daemon/examples/stats/conntrackd.conf deleted file mode 100644 index e514ac0..0000000 --- a/daemon/examples/stats/conntrackd.conf +++ /dev/null @@ -1,69 +0,0 @@ -# -# General settings -# -General { - # - # Number of buckets in the caches: hash table - # - HashSize 8192 - - # - # Maximum number of conntracks: - # it must be >= $ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max - # - HashLimit 65535 - - # - # Logfile - # - LogFile /var/log/conntrackd.log - - # - # Lockfile - # - LockFile /var/lock/conntrack.lock - - # - # Unix socket configuration - # - UNIX { - Path /tmp/sync.sock - Backlog 20 - } - - # - # Netlink socket buffer size - # - SocketBufferSize 262142 - - # - # Increase the socket buffer up to maximun if required - # - SocketBufferSizeMaxGrown 655355 -} - -# -# Ignore traffic for a certain set of IP's: Usually -# all the IP assigned to the firewall since local -# traffic must be ignored, just forwarded connections -# are worth to replicate -# -IgnoreTrafficFor { - IPv4_address 127.0.0.1 # loopback -} - -# -# Do not replicate certain protocol traffic -# -IgnoreProtocol { - UDP -# ICMP -# IGMP -# VRRP - # numeric numbers also valid -} - -# -# Strip NAT traffic -# -StripNAT diff --git a/daemon/examples/sync/Makefile.am b/daemon/examples/sync/Makefile.am deleted file mode 100644 index 28e7643..0000000 --- a/daemon/examples/sync/Makefile.am +++ /dev/null @@ -1 +0,0 @@ -SUBDIRS = persistent nack diff --git a/daemon/examples/sync/nack/Makefile.am b/daemon/examples/sync/nack/Makefile.am deleted file mode 100644 index 6fd99b1..0000000 --- a/daemon/examples/sync/nack/Makefile.am +++ /dev/null @@ -1,2 +0,0 @@ -EXTRA_DIST = script_backup.sh script_master.sh -SUBDIRS = node1 node2 diff --git a/daemon/examples/sync/nack/README b/daemon/examples/sync/nack/README deleted file mode 100644 index 66987f7..0000000 --- a/daemon/examples/sync/nack/README +++ /dev/null @@ -1 +0,0 @@ -This directory contains the files for the NACK based protocol diff --git a/daemon/examples/sync/nack/node1/Makefile.am b/daemon/examples/sync/nack/node1/Makefile.am deleted file mode 100644 index edc0ed7..0000000 --- a/daemon/examples/sync/nack/node1/Makefile.am +++ /dev/null @@ -1 +0,0 @@ -EXTRA_DIST = conntrackd.conf keepalived.conf diff --git a/daemon/examples/sync/nack/node1/conntrackd.conf b/daemon/examples/sync/nack/node1/conntrackd.conf deleted file mode 100644 index f24fa7e..0000000 --- a/daemon/examples/sync/nack/node1/conntrackd.conf +++ /dev/null @@ -1,125 +0,0 @@ -# -# Synchronizer settings -# -Sync { - Mode NACK { - # - # Size of the buffer that hold destroy messages for - # possible resends (in bytes) - # - ResendBufferSize 262144 - - # - # Entries committed to the connection tracking table - # starts with a limited timeout of N seconds until the - # takeover process is completed. - # - CommitTimeout 180 - - # Set Acknowledgement window size - ACKWindowSize 20 - } - - # - # Multicast IP and interface where messages are - # broadcasted (dedicated link). IMPORTANT: Make sure - # that iptables accepts traffic for destination - # 225.0.0.50, eg: - # - # iptables -I INPUT -d 225.0.0.50 -j ACCEPT - # iptables -I OUTPUT -d 225.0.0.50 -j ACCEPT - # - Multicast { - IPv4_address 225.0.0.50 - IPv4_interface 192.168.100.100 # IP of dedicated link - Group 3780 - Backlog 20 - } - - # Enable/Disable message checksumming - Checksum on - - # Uncomment this if you want to replicate just certain TCP states. - # This option introduces a tradeoff in the replication: it reduces - # CPU consumption and lost messages rate at the cost of having - # backup replicas that don't contain the current state that the active - # replica holds. TCP states are: SYN_SENT, SYN_RECV, ESTABLISHED, - # FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN. - # - # Replicate ESTABLISHED TIME_WAIT for TCP -} - -# -# General settings -# -General { - # - # Number of buckets in the caches: hash table - # - HashSize 8192 - - # - # Maximum number of conntracks: - # it must be >= $ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max - # - HashLimit 65535 - - # - # Logfile - # - LogFile /var/log/conntrackd.log - - # - # Lockfile - # - LockFile /var/lock/conntrack.lock - - # - # Unix socket configuration - # - UNIX { - Path /tmp/sync.sock - Backlog 20 - } - - # - # Netlink socket buffer size - # - SocketBufferSize 262142 - - # - # Increase the socket buffer up to maximum if required - # - SocketBufferSizeMaxGrown 655355 -} - -# -# Ignore traffic for a certain set of IP's: Usually -# all the IP assigned to the firewall since local -# traffic must be ignored, just forwarded connections -# are worth to replicate -# -IgnoreTrafficFor { - IPv4_address 127.0.0.1 # loopback - IPv4_address 192.168.0.1 - IPv4_address 192.168.1.1 - IPv4_address 192.168.100.100 # dedicated link ip - IPv4_address 192.168.0.100 # virtual IP 1 - IPv4_address 192.168.1.100 # virtual IP 2 -} - -# -# Do not replicate certain protocol traffic -# -IgnoreProtocol { - UDP - ICMP - IGMP - VRRP - # numeric numbers also valid -} - -# -# Strip NAT traffic -# -StripNAT diff --git a/daemon/examples/sync/nack/node1/keepalived.conf b/daemon/examples/sync/nack/node1/keepalived.conf deleted file mode 100644 index 41aa35b..0000000 --- a/daemon/examples/sync/nack/node1/keepalived.conf +++ /dev/null @@ -1,38 +0,0 @@ -vrrp_sync_group G1 { # must be before vrrp_instance declaration - group { - VI_1 - VI_2 - } - notify_master /etc/conntrackd/script_master.sh - notify_backup /etc/conntrackd/script_backup.sh -} - -vrrp_instance VI_1 { - interface eth1 - state SLAVE - virtual_router_id 61 - priority 80 - advert_int 3 - authentication { - auth_type PASS - auth_pass papas_con_tomate - } - virtual_ipaddress { - 192.168.0.100 # default CIDR mask is /32 - } -} - -vrrp_instance VI_2 { - interface eth0 - state SLAVE - virtual_router_id 62 - priority 80 - advert_int 3 - authentication { - auth_type PASS - auth_pass papas_con_tomate - } - virtual_ipaddress { - 192.168.1.100 - } -} diff --git a/daemon/examples/sync/nack/node2/Makefile.am b/daemon/examples/sync/nack/node2/Makefile.am deleted file mode 100644 index edc0ed7..0000000 --- a/daemon/examples/sync/nack/node2/Makefile.am +++ /dev/null @@ -1 +0,0 @@ -EXTRA_DIST = conntrackd.conf keepalived.conf diff --git a/daemon/examples/sync/nack/node2/conntrackd.conf b/daemon/examples/sync/nack/node2/conntrackd.conf deleted file mode 100644 index 4f15773..0000000 --- a/daemon/examples/sync/nack/node2/conntrackd.conf +++ /dev/null @@ -1,124 +0,0 @@ -# -# Synchronizer settings -# -Sync { - Mode NACK { - # - # Size of the buffer that hold destroy messages for - # possible resends (in bytes) - # - ResendBufferSize 262144 - - # Entries committed to the connection tracking table - # starts with a limited timeout of N seconds until the - # takeover process is completed. - # - CommitTimeout 180 - - # Set Acknowledgement window size - ACKWindowSize 20 - } - - # - # Multicast IP and interface where messages are - # broadcasted (dedicated link). IMPORTANT: Make sure - # that iptables accepts traffic for destination - # 225.0.0.50, eg: - # - # iptables -I INPUT -d 225.0.0.50 -j ACCEPT - # iptables -I OUTPUT -d 225.0.0.50 -j ACCEPT - # - Multicast { - IPv4_address 225.0.0.50 - IPv4_interface 192.168.100.200 # IP of dedicated link - Group 3780 - Backlog 20 - } - - # Enable/Disable message checksumming - Checksum on - - # Uncomment this if you want to replicate just certain TCP states. - # This option introduces a tradeoff in the replication: it reduces - # CPU consumption and lost messages rate at the cost of having - # backup replicas that don't contain the current state that the active - # replica holds. TCP states are: SYN_SENT, SYN_RECV, ESTABLISHED, - # FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN. - # - # Replicate ESTABLISHED TIME_WAIT for TCP -} - -# -# General settings -# -General { - # - # Number of buckets in the caches: hash table - # - HashSize 8192 - - # - # Maximum number of conntracks: - # it must be >= $ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max - # - HashLimit 65535 - - # - # Logfile - # - LogFile /var/log/conntrackd.log - - # - # Lockfile - # - LockFile /var/lock/conntrack.lock - - # - # Unix socket configuration - # - UNIX { - Path /tmp/sync.sock - Backlog 20 - } - - # - # Netlink socket buffer size - # - SocketBufferSize 262142 - - # - # Increase the socket buffer up to maximum if required - # - SocketBufferSizeMaxGrown 655355 -} - -# -# Ignore traffic for a certain set of IP's: Usually -# all the IP assigned to the firewall since local -# traffic must be ignored, just forwarded connections -# are worth to replicate -# -IgnoreTrafficFor { - IPv4_address 127.0.0.1 # loopback - IPv4_address 192.168.0.2 - IPv4_address 192.168.1.2 - IPv4_address 192.168.100.200 # dedicated link ip - IPv4_address 192.168.0.200 # virtual IP 1 - IPv4_address 192.168.1.200 # virtual IP 2 -} - -# -# Do not replicate certain protocol traffic -# -IgnoreProtocol { - UDP - ICMP - IGMP - VRRP - # numeric numbers also valid -} - -# -# Strip NAT traffic -# -StripNAT diff --git a/daemon/examples/sync/nack/node2/keepalived.conf b/daemon/examples/sync/nack/node2/keepalived.conf deleted file mode 100644 index 41aa35b..0000000 --- a/daemon/examples/sync/nack/node2/keepalived.conf +++ /dev/null @@ -1,38 +0,0 @@ -vrrp_sync_group G1 { # must be before vrrp_instance declaration - group { - VI_1 - VI_2 - } - notify_master /etc/conntrackd/script_master.sh - notify_backup /etc/conntrackd/script_backup.sh -} - -vrrp_instance VI_1 { - interface eth1 - state SLAVE - virtual_router_id 61 - priority 80 - advert_int 3 - authentication { - auth_type PASS - auth_pass papas_con_tomate - } - virtual_ipaddress { - 192.168.0.100 # default CIDR mask is /32 - } -} - -vrrp_instance VI_2 { - interface eth0 - state SLAVE - virtual_router_id 62 - priority 80 - advert_int 3 - authentication { - auth_type PASS - auth_pass papas_con_tomate - } - virtual_ipaddress { - 192.168.1.100 - } -} diff --git a/daemon/examples/sync/nack/script_backup.sh b/daemon/examples/sync/nack/script_backup.sh deleted file mode 100755 index 813e375..0000000 --- a/daemon/examples/sync/nack/script_backup.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -/usr/sbin/conntrackd -n # request a resync from other nodes via multicast diff --git a/daemon/examples/sync/nack/script_master.sh b/daemon/examples/sync/nack/script_master.sh deleted file mode 100755 index ff1dbc0..0000000 --- a/daemon/examples/sync/nack/script_master.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh - -/usr/sbin/conntrackd -c # commit the cache -/usr/sbin/conntrackd -f # flush the caches -/usr/sbin/conntrackd -R # resync with kernel conntrack table diff --git a/daemon/examples/sync/persistent/Makefile.am b/daemon/examples/sync/persistent/Makefile.am deleted file mode 100644 index 6fd99b1..0000000 --- a/daemon/examples/sync/persistent/Makefile.am +++ /dev/null @@ -1,2 +0,0 @@ -EXTRA_DIST = script_backup.sh script_master.sh -SUBDIRS = node1 node2 diff --git a/daemon/examples/sync/persistent/README b/daemon/examples/sync/persistent/README deleted file mode 100644 index 36b5989..0000000 --- a/daemon/examples/sync/persistent/README +++ /dev/null @@ -1 +0,0 @@ -This directory contains the files for the PERSISTENT based protocol diff --git a/daemon/examples/sync/persistent/node1/Makefile.am b/daemon/examples/sync/persistent/node1/Makefile.am deleted file mode 100644 index edc0ed7..0000000 --- a/daemon/examples/sync/persistent/node1/Makefile.am +++ /dev/null @@ -1 +0,0 @@ -EXTRA_DIST = conntrackd.conf keepalived.conf diff --git a/daemon/examples/sync/persistent/node1/conntrackd.conf b/daemon/examples/sync/persistent/node1/conntrackd.conf deleted file mode 100644 index 90afeb7..0000000 --- a/daemon/examples/sync/persistent/node1/conntrackd.conf +++ /dev/null @@ -1,130 +0,0 @@ -# -# Synchronizer settings -# -Sync { - Mode PERSISTENT { - # - # If a conntrack entry is not modified in <= 15 seconds, then - # a message is broadcasted. This mechanism is used to - # resynchronize nodes that just joined the multicast group - # - RefreshTime 15 - - # - # If we don't receive a notification about the state of - # an entry in the external cache after N seconds, then - # remove it. - # - CacheTimeout 180 - - # - # Entries committed to the connection tracking table - # starts with a limited timeout of N seconds until the - # takeover process is completed. - # - CommitTimeout 180 - } - - # - # Multicast IP and interface where messages are - # broadcasted (dedicated link). IMPORTANT: Make sure - # that iptables accepts traffic for destination - # 225.0.0.50, eg: - # - # iptables -I INPUT -d 225.0.0.50 -j ACCEPT - # iptables -I OUTPUT -d 225.0.0.50 -j ACCEPT - # - Multicast { - IPv4_address 225.0.0.50 - IPv4_interface 192.168.100.100 # IP of dedicated link - Group 3780 - Backlog 20 - } - - # Enable/Disable message checksumming - Checksum on - - # Uncomment this if you want to replicate just certain TCP states. - # This option introduces a tradeoff in the replication: it reduces - # CPU consumption and lost messages rate at the cost of having - # backup replicas that don't contain the current state that the active - # replica holds. TCP states are: SYN_SENT, SYN_RECV, ESTABLISHED, - # FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN. - # - # Replicate ESTABLISHED TIME_WAIT for TCP -} - -# -# General settings -# -General { - # - # Number of buckets in the caches: hash table - # - HashSize 8192 - - # - # Maximum number of conntracks: - # it must be >= $ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max - # - HashLimit 65535 - - # - # Logfile - # - LogFile /var/log/conntrackd.log - - # - # Lockfile - # - LockFile /var/lock/conntrack.lock - - # - # Unix socket configuration - # - UNIX { - Path /tmp/sync.sock - Backlog 20 - } - - # - # Netlink socket buffer size - # - SocketBufferSize 262142 - - # - # Increase the socket buffer up to maximum if required - # - SocketBufferSizeMaxGrown 655355 -} - -# -# Ignore traffic for a certain set of IP's: Usually -# all the IP assigned to the firewall since local -# traffic must be ignored, just forwarded connections -# are worth to replicate -# -IgnoreTrafficFor { - IPv4_address 127.0.0.1 # loopback - IPv4_address 192.168.0.1 - IPv4_address 192.168.1.1 - IPv4_address 192.168.100.100 # dedicated link ip - IPv4_address 192.168.0.100 # virtual IP 1 - IPv4_address 192.168.1.100 # virtual IP 2 -} - -# -# Do not replicate certain protocol traffic -# -IgnoreProtocol { - UDP - ICMP - IGMP - VRRP - # numeric numbers also valid -} - -# -# Strip NAT traffic -# -StripNAT diff --git a/daemon/examples/sync/persistent/node1/keepalived.conf b/daemon/examples/sync/persistent/node1/keepalived.conf deleted file mode 100644 index 41aa35b..0000000 --- a/daemon/examples/sync/persistent/node1/keepalived.conf +++ /dev/null @@ -1,38 +0,0 @@ -vrrp_sync_group G1 { # must be before vrrp_instance declaration - group { - VI_1 - VI_2 - } - notify_master /etc/conntrackd/script_master.sh - notify_backup /etc/conntrackd/script_backup.sh -} - -vrrp_instance VI_1 { - interface eth1 - state SLAVE - virtual_router_id 61 - priority 80 - advert_int 3 - authentication { - auth_type PASS - auth_pass papas_con_tomate - } - virtual_ipaddress { - 192.168.0.100 # default CIDR mask is /32 - } -} - -vrrp_instance VI_2 { - interface eth0 - state SLAVE - virtual_router_id 62 - priority 80 - advert_int 3 - authentication { - auth_type PASS - auth_pass papas_con_tomate - } - virtual_ipaddress { - 192.168.1.100 - } -} diff --git a/daemon/examples/sync/persistent/node2/Makefile.am b/daemon/examples/sync/persistent/node2/Makefile.am deleted file mode 100644 index edc0ed7..0000000 --- a/daemon/examples/sync/persistent/node2/Makefile.am +++ /dev/null @@ -1 +0,0 @@ -EXTRA_DIST = conntrackd.conf keepalived.conf diff --git a/daemon/examples/sync/persistent/node2/conntrackd.conf b/daemon/examples/sync/persistent/node2/conntrackd.conf deleted file mode 100644 index aee4a29..0000000 --- a/daemon/examples/sync/persistent/node2/conntrackd.conf +++ /dev/null @@ -1,130 +0,0 @@ -# -# Synchronizer settings -# -Sync { - Mode PERSISTENT { - # - # If a conntrack entry is not modified in <= 15 seconds, then - # a message is broadcasted. This mechanism is used to - # resynchronize nodes that just joined the multicast group - # - RefreshTime 15 - - # - # If we don't receive a notification about the state of - # an entry in the external cache after N seconds, then - # remove it. - # - CacheTimeout 180 - - # - # Entries committed to the connection tracking table - # starts with a limited timeout of N seconds until the - # takeover process is completed. - # - CommitTimeout 180 - } - - # - # Multicast IP and interface where messages are - # broadcasted (dedicated link). IMPORTANT: Make sure - # that iptables accepts traffic for destination - # 225.0.0.50, eg: - # - # iptables -I INPUT -d 225.0.0.50 -j ACCEPT - # iptables -I OUTPUT -d 225.0.0.50 -j ACCEPT - # - Multicast { - IPv4_address 225.0.0.50 - IPv4_interface 192.168.100.200 # IP of dedicated link - Group 3780 - Backlog 20 - } - - # Enable/Disable message checksumming - Checksum on - - # Uncomment this if you want to replicate just certain TCP states. - # This option introduces a tradeoff in the replication: it reduces - # CPU consumption and lost messages rate at the cost of having - # backup replicas that don't contain the current state that the active - # replica holds. TCP states are: SYN_SENT, SYN_RECV, ESTABLISHED, - # FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN. - # - # Replicate ESTABLISHED TIME_WAIT for TCP -} - -# -# General settings -# -General { - # - # Number of buckets in the caches: hash table - # - HashSize 8192 - - # - # Maximum number of conntracks: - # it must be >= $ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max - # - HashLimit 65535 - - # - # Logfile - # - LogFile /var/log/conntrackd.log - - # - # Lockfile - # - LockFile /var/lock/conntrack.lock - - # - # Unix socket configuration - # - UNIX { - Path /tmp/sync.sock - Backlog 20 - } - - # - # Netlink socket buffer size - # - SocketBufferSize 262142 - - # - # Increase the socket buffer up to maximum if required - # - SocketBufferSizeMaxGrown 655355 -} - -# -# Ignore traffic for a certain set of IP's: Usually -# all the IP assigned to the firewall since local -# traffic must be ignored, just forwarded connections -# are worth to replicate -# -IgnoreTrafficFor { - IPv4_address 127.0.0.1 # loopback - IPv4_address 192.168.0.2 - IPv4_address 192.168.1.2 - IPv4_address 192.168.100.200 # dedicated link ip - IPv4_address 192.168.0.200 # virtual IP 1 - IPv4_address 192.168.1.200 # virtual IP 2 -} - -# -# Do not replicate certain protocol traffic -# -IgnoreProtocol { - UDP - ICMP - IGMP - VRRP - # numeric numbers also valid -} - -# -# Strip NAT traffic -# -StripNAT diff --git a/daemon/examples/sync/persistent/node2/keepalived.conf b/daemon/examples/sync/persistent/node2/keepalived.conf deleted file mode 100644 index 41aa35b..0000000 --- a/daemon/examples/sync/persistent/node2/keepalived.conf +++ /dev/null @@ -1,38 +0,0 @@ -vrrp_sync_group G1 { # must be before vrrp_instance declaration - group { - VI_1 - VI_2 - } - notify_master /etc/conntrackd/script_master.sh - notify_backup /etc/conntrackd/script_backup.sh -} - -vrrp_instance VI_1 { - interface eth1 - state SLAVE - virtual_router_id 61 - priority 80 - advert_int 3 - authentication { - auth_type PASS - auth_pass papas_con_tomate - } - virtual_ipaddress { - 192.168.0.100 # default CIDR mask is /32 - } -} - -vrrp_instance VI_2 { - interface eth0 - state SLAVE - virtual_router_id 62 - priority 80 - advert_int 3 - authentication { - auth_type PASS - auth_pass papas_con_tomate - } - virtual_ipaddress { - 192.168.1.100 - } -} diff --git a/daemon/examples/sync/persistent/script_backup.sh b/daemon/examples/sync/persistent/script_backup.sh deleted file mode 100755 index 8ea2ad8..0000000 --- a/daemon/examples/sync/persistent/script_backup.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -/usr/sbin/conntrackd -B diff --git a/daemon/examples/sync/persistent/script_master.sh b/daemon/examples/sync/persistent/script_master.sh deleted file mode 100755 index 70c26c9..0000000 --- a/daemon/examples/sync/persistent/script_master.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -/usr/sbin/conntrackd -c -/usr/sbin/conntrackd -R diff --git a/daemon/include/Makefile.am b/daemon/include/Makefile.am deleted file mode 100644 index e669d73..0000000 --- a/daemon/include/Makefile.am +++ /dev/null @@ -1,5 +0,0 @@ - -noinst_HEADERS = alarm.h jhash.h slist.h cache.h linux_list.h \ - sync.h conntrackd.h local.h us-conntrack.h \ - debug.h log.h hash.h mcast.h buffer.h - diff --git a/daemon/include/alarm.h b/daemon/include/alarm.h deleted file mode 100644 index 93e6482..0000000 --- a/daemon/include/alarm.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef _TIMER_H_ -#define _TIMER_H_ - -#include "linux_list.h" - -struct alarm_list { - struct list_head head; - unsigned long expires; - void *data; - void (*function)(struct alarm_list *a, void *data); -}; - -#endif diff --git a/daemon/include/buffer.h b/daemon/include/buffer.h deleted file mode 100644 index 8d72dfb..0000000 --- a/daemon/include/buffer.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef _BUFFER_H_ -#define _BUFFER_H_ - -#include -#include -#include -#include -#include "linux_list.h" - -struct buffer { - pthread_mutex_t lock; - size_t max_size; - size_t cur_size; - struct list_head head; -}; - -struct buffer_node { - struct list_head head; - size_t size; - char data[0]; -}; - -struct buffer *buffer_create(size_t max_size); -void buffer_destroy(struct buffer *b); -int buffer_add(struct buffer *b, const void *data, size_t size); -void buffer_del(struct buffer *b, void *data); -void __buffer_del(struct buffer *b, void *data); -void buffer_iterate(struct buffer *b, - void *data, - int (*iterate)(void *data1, void *data2)); - -#endif diff --git a/daemon/include/cache.h b/daemon/include/cache.h deleted file mode 100644 index 7d9559a..0000000 --- a/daemon/include/cache.h +++ /dev/null @@ -1,92 +0,0 @@ -#ifndef _CACHE_H_ -#define _CACHE_H_ - -#include -#include - -/* cache features */ -enum { - NO_FEATURES = 0, - - TIMER_FEATURE = 0, - TIMER = (1 << TIMER_FEATURE), - - LIFETIME_FEATURE = 2, - LIFETIME = (1 << LIFETIME_FEATURE), - - __CACHE_MAX_FEATURE -}; -#define CACHE_MAX_FEATURE __CACHE_MAX_FEATURE - -struct cache; -struct us_conntrack; - -struct cache_feature { - size_t size; - void (*add)(struct us_conntrack *u, void *data); - void (*update)(struct us_conntrack *u, void *data); - void (*destroy)(struct us_conntrack *u, void *data); - int (*dump)(struct us_conntrack *u, void *data, char *buf, int type); -}; - -extern struct cache_feature lifetime_feature; -extern struct cache_feature timer_feature; - -#define CACHE_MAX_NAMELEN 32 - -struct cache { - char name[CACHE_MAX_NAMELEN]; - struct hashtable *h; - - unsigned int num_features; - struct cache_feature **features; - unsigned int feature_type[CACHE_MAX_FEATURE]; - unsigned int *feature_offset; - struct cache_extra *extra; - unsigned int extra_offset; - - /* statistics */ - unsigned int add_ok; - unsigned int del_ok; - unsigned int upd_ok; - - unsigned int add_fail; - unsigned int del_fail; - unsigned int upd_fail; - - unsigned int commit_ok; - unsigned int commit_exist; - unsigned int commit_fail; - - unsigned int flush; -}; - -struct cache_extra { - unsigned int size; - - void (*add)(struct us_conntrack *u, void *data); - void (*update)(struct us_conntrack *u, void *data); - void (*destroy)(struct us_conntrack *u, void *data); -}; - -struct nf_conntrack; - -struct cache *cache_create(char *name, unsigned int features, u_int8_t proto, struct cache_extra *extra); -void cache_destroy(struct cache *e); - -struct us_conntrack *cache_add(struct cache *c, struct nf_conntrack *ct); -struct us_conntrack *cache_update(struct cache *c, struct nf_conntrack *ct); -struct us_conntrack *cache_update_force(struct cache *c, struct nf_conntrack *ct); -int cache_del(struct cache *c, struct nf_conntrack *ct); -int cache_test(struct cache *c, struct nf_conntrack *ct); -void cache_stats(struct cache *c, int fd); -struct us_conntrack *cache_get_conntrack(struct cache *, void *); -void *cache_get_extra(struct cache *, void *); - -/* iterators */ -void cache_dump(struct cache *c, int fd, int type); -void cache_commit(struct cache *c); -void cache_flush(struct cache *c); -void cache_bulk(struct cache *c); - -#endif diff --git a/daemon/include/conntrackd.h b/daemon/include/conntrackd.h deleted file mode 100644 index a5f7a3a..0000000 --- a/daemon/include/conntrackd.h +++ /dev/null @@ -1,174 +0,0 @@ -#ifndef _CONNTRACKD_H_ -#define _CONNTRACKD_H_ - -#include "mcast.h" -#include "local.h" - -#include -#include -#include "cache.h" -#include "debug.h" -#include -#include "state_helper.h" -#include - -/* UNIX facilities */ -#define FLUSH_MASTER 0 /* flush kernel conntrack table */ -#define RESYNC_MASTER 1 /* resync with kernel conntrack table */ -#define DUMP_INTERNAL 16 /* dump internal cache */ -#define DUMP_EXTERNAL 17 /* dump external cache */ -#define COMMIT 18 /* commit external cache */ -#define FLUSH_CACHE 19 /* flush cache */ -#define KILL 20 /* kill conntrackd */ -#define STATS 21 /* dump statistics */ -#define SEND_BULK 22 /* send a bulk */ -#define REQUEST_DUMP 23 /* request dump */ -#define DUMP_INT_XML 24 /* dump internal cache in XML */ -#define DUMP_EXT_XML 25 /* dump external cache in XML */ - -#define DEFAULT_CONFIGFILE "/etc/conntrackd/conntrackd.conf" -#define DEFAULT_LOCKFILE "/var/lock/conntrackd.lock" - -enum { - STRIP_NAT_BIT = 0, - STRIP_NAT = (1 << STRIP_NAT_BIT), - - DELAY_DESTROY_MSG_BIT = 1, - DELAY_DESTROY_MSG = (1 << DELAY_DESTROY_MSG_BIT), - - RELAX_TRANSITIONS_BIT = 2, - RELAX_TRANSITIONS = (1 << RELAX_TRANSITIONS_BIT), - - SYNC_MODE_PERSISTENT_BIT = 3, - SYNC_MODE_PERSISTENT = (1 << SYNC_MODE_PERSISTENT_BIT), - - SYNC_MODE_NACK_BIT = 4, - SYNC_MODE_NACK = (1 << SYNC_MODE_NACK_BIT), - - DONT_CHECKSUM_BIT = 5, - DONT_CHECKSUM = (1 << DONT_CHECKSUM_BIT), -}; - -/* daemon/request modes */ -#define NOT_SET 0 -#define DAEMON 1 -#define REQUEST 2 - -/* conntrackd modes */ -#define SYNC_MODE 0 -#define STATS_MODE 1 - -/* FILENAME_MAX is 4096 on my system, perhaps too much? */ -#ifndef FILENAME_MAXLEN -#define FILENAME_MAXLEN 256 -#endif - -union inet_address { - u_int32_t ipv4; - u_int32_t ipv6[4]; - u_int32_t all[4]; -}; - -#define CONFIG(x) conf.x - -struct ct_conf { - char logfile[FILENAME_MAXLEN]; - char lockfile[FILENAME_MAXLEN]; - int hashsize; /* hashtable size */ - struct mcast_conf mcast; /* multicast settings */ - struct local_conf local; /* unix socket facilities */ - int limit; - int refresh; - int cache_timeout; /* cache entries timeout */ - int commit_timeout; /* committed entries timeout */ - unsigned int netlink_buffer_size; - unsigned int netlink_buffer_size_max_grown; - unsigned char ignore_protocol[IPPROTO_MAX]; - union inet_address *listen_to; - unsigned int listen_to_len; - unsigned int flags; - int family; /* protocol family */ - unsigned int resend_buffer_size;/* NACK protocol */ - unsigned int window_size; -}; - -#define STATE(x) st.x - -struct ct_general_state { - sigset_t block; - FILE *log; - int local; - struct ct_mode *mode; - struct ignore_pool *ignore_pool; - - struct nfnl_handle *event; /* event handler */ - struct nfnl_handle *sync; /* sync handler */ - struct nfnl_handle *dump; /* dump handler */ - - struct nfnl_subsys_handle *subsys_event; /* events */ - struct nfnl_subsys_handle *subsys_sync; /* resync */ - struct nfnl_subsys_handle *subsys_dump; /* dump */ - - /* statistics */ - u_int64_t malformed; - u_int64_t bytes[NFCT_DIR_MAX]; - u_int64_t packets[NFCT_DIR_MAX]; -}; - -#define STATE_SYNC(x) state.sync->x - -struct ct_sync_state { - struct cache *internal; /* internal events cache (netlink) */ - struct cache *external; /* external events cache (mcast) */ - - struct mcast_sock *mcast_server; /* multicast socket: incoming */ - struct mcast_sock *mcast_client; /* multicast socket: outgoing */ - - struct sync_mode *mcast_sync; - struct buffer *buffer; - - u_int32_t last_seq_sent; /* last sequence number sent */ - u_int32_t last_seq_recv; /* last sequence number recv */ - u_int64_t packets_replayed; /* number of replayed packets */ - u_int64_t packets_lost; /* lost packets: sequence tracking */ -}; - -#define STATE_STATS(x) state.stats->x - -struct ct_stats_state { - struct cache *cache; /* internal events cache (netlink) */ -}; - -union ct_state { - struct ct_sync_state *sync; - struct ct_stats_state *stats; -}; - -extern struct ct_conf conf; -extern union ct_state state; -extern struct ct_general_state st; - -#ifndef IPPROTO_VRRP -#define IPPROTO_VRRP 112 -#endif - -struct ct_mode { - int (*init)(void); - int (*add_fds_to_set)(fd_set *readfds); - void (*step)(fd_set *readfds); - int (*local)(int fd, int type, void *data); - void (*kill)(void); - void (*dump)(struct nf_conntrack *ct, struct nlmsghdr *nlh); - void (*overrun)(struct nf_conntrack *ct, struct nlmsghdr *nlh); - void (*event_new)(struct nf_conntrack *ct, struct nlmsghdr *nlh); - void (*event_upd)(struct nf_conntrack *ct, struct nlmsghdr *nlh); - int (*event_dst)(struct nf_conntrack *ct, struct nlmsghdr *nlh); -}; - -/* conntrackd modes */ -extern struct ct_mode sync_mode; -extern struct ct_mode stats_mode; - -#define MAX(x, y) x > y ? x : y - -#endif diff --git a/daemon/include/debug.h b/daemon/include/debug.h deleted file mode 100644 index 67f2c71..0000000 --- a/daemon/include/debug.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef _DEBUG_H -#define _DEBUG_H - -#if 0 -#define debug printf -#else -#define debug -#endif - -#include -#include -#include - -static inline void debug_ct(struct nf_conntrack *ct, char *msg) -{ - struct in_addr addr, addr2, addr3, addr4; - - debug("----%s (%p) ----\n", msg, ct); - memcpy(&addr, - nfct_get_attr(ct, ATTR_ORIG_IPV4_SRC), - sizeof(u_int32_t)); - memcpy(&addr2, - nfct_get_attr(ct, ATTR_ORIG_IPV4_DST), - sizeof(u_int32_t)); - memcpy(&addr3, - nfct_get_attr(ct, ATTR_REPL_IPV4_SRC), - sizeof(u_int32_t)); - memcpy(&addr4, - nfct_get_attr(ct, ATTR_REPL_IPV4_DST), - sizeof(u_int32_t)); - - debug("status: %x\n", nfct_get_attr_u32(ct, ATTR_STATUS)); - debug("l3:%d l4:%d ", - nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO), - nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO)); - debug("%s:%hu ->", inet_ntoa(addr), - ntohs(nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC))); - debug("%s:%hu\n", - inet_ntoa(addr2), - ntohs(nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST))); - debug("l3:%d l4:%d ", - nfct_get_attr_u8(ct, ATTR_REPL_L3PROTO), - nfct_get_attr_u8(ct, ATTR_REPL_L4PROTO)); - debug("%s:%hu ->", - inet_ntoa(addr3), - ntohs(nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC))); - debug("%s:%hu\n", - inet_ntoa(addr4), - ntohs(nfct_get_attr_u16(ct, ATTR_REPL_PORT_DST))); - debug("-------------------------\n"); -} - -#endif diff --git a/daemon/include/hash.h b/daemon/include/hash.h deleted file mode 100644 index fd971e7..0000000 --- a/daemon/include/hash.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef _NF_SET_HASH_H_ -#define _NF_SET_HASH_H_ - -#include -#include -#include "slist.h" -#include "linux_list.h" - -struct hashtable; -struct hashtable_node; - -struct hashtable { - u_int32_t hashsize; - u_int32_t limit; - u_int32_t count; - u_int32_t initval; - u_int32_t datasize; - - u_int32_t (*hash)(const void *data, struct hashtable *table); - int (*compare)(const void *data1, const void *data2); - - struct slist_head members[0]; -}; - -struct hashtable_node { - struct slist_head head; - char data[0]; -}; - -struct hashtable_node *hashtable_alloc_node(int datasize, void *data); -void hashtable_destroy_node(struct hashtable_node *h); - -struct hashtable * -hashtable_create(int hashsize, int limit, int datasize, - u_int32_t (*hash)(const void *data, struct hashtable *table), - int (*compare)(const void *data1, const void *data2)); -void hashtable_destroy(struct hashtable *h); - -void *hashtable_add(struct hashtable *table, void *data); -void *hashtable_test(struct hashtable *table, const void *data); -int hashtable_del(struct hashtable *table, void *data); -int hashtable_flush(struct hashtable *table); -int hashtable_iterate(struct hashtable *table, void *data, - int (*iterate)(void *data1, void *data2)); -unsigned int hashtable_counter(struct hashtable *table); - -#endif diff --git a/daemon/include/ignore.h b/daemon/include/ignore.h deleted file mode 100644 index 40cb02d..0000000 --- a/daemon/include/ignore.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _IGNORE_H_ -#define _IGNORE_H_ - -struct ignore_pool { - struct hashtable *h; -}; - -struct ignore_pool *ignore_pool_create(u_int8_t family); -void ignore_pool_destroy(struct ignore_pool *ip); -int ignore_pool_add(struct ignore_pool *ip, void *data); - -#endif diff --git a/daemon/include/jhash.h b/daemon/include/jhash.h deleted file mode 100644 index 38b8780..0000000 --- a/daemon/include/jhash.h +++ /dev/null @@ -1,146 +0,0 @@ -#ifndef _LINUX_JHASH_H -#define _LINUX_JHASH_H - -#define u32 unsigned int -#define u8 char - -/* jhash.h: Jenkins hash support. - * - * Copyright (C) 1996 Bob Jenkins (bob_jenkins@burtleburtle.net) - * - * http://burtleburtle.net/bob/hash/ - * - * These are the credits from Bob's sources: - * - * lookup2.c, by Bob Jenkins, December 1996, Public Domain. - * hash(), hash2(), hash3, and mix() are externally useful functions. - * Routines to test the hash are included if SELF_TEST is defined. - * You can use this free for any purpose. It has no warranty. - * - * Copyright (C) 2003 David S. Miller (davem@redhat.com) - * - * I've modified Bob's hash to be useful in the Linux kernel, and - * any bugs present are surely my fault. -DaveM - */ - -/* NOTE: Arguments are modified. */ -#define __jhash_mix(a, b, c) \ -{ \ - a -= b; a -= c; a ^= (c>>13); \ - b -= c; b -= a; b ^= (a<<8); \ - c -= a; c -= b; c ^= (b>>13); \ - a -= b; a -= c; a ^= (c>>12); \ - b -= c; b -= a; b ^= (a<<16); \ - c -= a; c -= b; c ^= (b>>5); \ - a -= b; a -= c; a ^= (c>>3); \ - b -= c; b -= a; b ^= (a<<10); \ - c -= a; c -= b; c ^= (b>>15); \ -} - -/* The golden ration: an arbitrary value */ -#define JHASH_GOLDEN_RATIO 0x9e3779b9 - -/* The most generic version, hashes an arbitrary sequence - * of bytes. No alignment or length assumptions are made about - * the input key. - */ -static inline u32 jhash(const void *key, u32 length, u32 initval) -{ - u32 a, b, c, len; - const u8 *k = key; - - len = length; - a = b = JHASH_GOLDEN_RATIO; - c = initval; - - while (len >= 12) { - a += (k[0] +((u32)k[1]<<8) +((u32)k[2]<<16) +((u32)k[3]<<24)); - b += (k[4] +((u32)k[5]<<8) +((u32)k[6]<<16) +((u32)k[7]<<24)); - c += (k[8] +((u32)k[9]<<8) +((u32)k[10]<<16)+((u32)k[11]<<24)); - - __jhash_mix(a,b,c); - - k += 12; - len -= 12; - } - - c += length; - switch (len) { - case 11: c += ((u32)k[10]<<24); - case 10: c += ((u32)k[9]<<16); - case 9 : c += ((u32)k[8]<<8); - case 8 : b += ((u32)k[7]<<24); - case 7 : b += ((u32)k[6]<<16); - case 6 : b += ((u32)k[5]<<8); - case 5 : b += k[4]; - case 4 : a += ((u32)k[3]<<24); - case 3 : a += ((u32)k[2]<<16); - case 2 : a += ((u32)k[1]<<8); - case 1 : a += k[0]; - }; - - __jhash_mix(a,b,c); - - return c; -} - -/* A special optimized version that handles 1 or more of u32s. - * The length parameter here is the number of u32s in the key. - */ -static inline u32 jhash2(u32 *k, u32 length, u32 initval) -{ - u32 a, b, c, len; - - a = b = JHASH_GOLDEN_RATIO; - c = initval; - len = length; - - while (len >= 3) { - a += k[0]; - b += k[1]; - c += k[2]; - __jhash_mix(a, b, c); - k += 3; len -= 3; - } - - c += length * 4; - - switch (len) { - case 2 : b += k[1]; - case 1 : a += k[0]; - }; - - __jhash_mix(a,b,c); - - return c; -} - - -/* A special ultra-optimized versions that knows they are hashing exactly - * 3, 2 or 1 word(s). - * - * NOTE: In partilar the "c += length; __jhash_mix(a,b,c);" normally - * done at the end is not done here. - */ -static inline u32 jhash_3words(u32 a, u32 b, u32 c, u32 initval) -{ - a += JHASH_GOLDEN_RATIO; - b += JHASH_GOLDEN_RATIO; - c += initval; - - __jhash_mix(a, b, c); - - return c; -} - -static inline u32 jhash_2words(u32 a, u32 b, u32 initval) -{ - return jhash_3words(a, b, 0, initval); -} - -static inline u32 jhash_1word(u32 a, u32 initval) -{ - return jhash_3words(a, 0, 0, initval); -} - -#endif /* _LINUX_JHASH_H */ diff --git a/daemon/include/linux_list.h b/daemon/include/linux_list.h deleted file mode 100644 index 57b56d7..0000000 --- a/daemon/include/linux_list.h +++ /dev/null @@ -1,725 +0,0 @@ -#ifndef _LINUX_LIST_H -#define _LINUX_LIST_H - -#undef offsetof -#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) - -/** - * container_of - cast a member of a structure out to the containing structure - * - * @ptr: the pointer to the member. - * @type: the type of the container struct this is embedded in. - * @member: the name of the member within the struct. - * - */ -#define container_of(ptr, type, member) ({ \ - const typeof( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) );}) - -/* - * Check at compile time that something is of a particular type. - * Always evaluates to 1 so you may use it easily in comparisons. - */ -#define typecheck(type,x) \ -({ type __dummy; \ - typeof(x) __dummy2; \ - (void)(&__dummy == &__dummy2); \ - 1; \ -}) - -#define prefetch(x) 1 - -/* empty define to make this work in userspace -HW */ -#ifndef smp_wmb -#define smp_wmb() -#endif - -/* - * These are non-NULL pointers that will result in page faults - * under normal circumstances, used to verify that nobody uses - * non-initialized list entries. - */ -#define LIST_POISON1 ((void *) 0x00100100) -#define LIST_POISON2 ((void *) 0x00200200) - -/* - * Simple doubly linked list implementation. - * - * Some of the internal functions ("__xxx") are useful when - * manipulating whole lists rather than single entries, as - * sometimes we already know the next/prev entries and we can - * generate better code by using them directly rather than - * using the generic single-entry routines. - */ - -struct list_head { - struct list_head *next, *prev; -}; - -#define LIST_HEAD_INIT(name) { &(name), &(name) } - -#define LIST_HEAD(name) \ - struct list_head name = LIST_HEAD_INIT(name) - -#define INIT_LIST_HEAD(ptr) do { \ - (ptr)->next = (ptr); (ptr)->prev = (ptr); \ -} while (0) - -/* - * Insert a new entry between two known consecutive entries. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -static inline void __list_add(struct list_head *new, - struct list_head *prev, - struct list_head *next) -{ - next->prev = new; - new->next = next; - new->prev = prev; - prev->next = new; -} - -/** - * list_add - add a new entry - * @new: new entry to be added - * @head: list head to add it after - * - * Insert a new entry after the specified head. - * This is good for implementing stacks. - */ -static inline void list_add(struct list_head *new, struct list_head *head) -{ - __list_add(new, head, head->next); -} - -/** - * list_add_tail - add a new entry - * @new: new entry to be added - * @head: list head to add it before - * - * Insert a new entry before the specified head. - * This is useful for implementing queues. - */ -static inline void list_add_tail(struct list_head *new, struct list_head *head) -{ - __list_add(new, head->prev, head); -} - -/* - * Insert a new entry between two known consecutive entries. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -static inline void __list_add_rcu(struct list_head * new, - struct list_head * prev, struct list_head * next) -{ - new->next = next; - new->prev = prev; - smp_wmb(); - next->prev = new; - prev->next = new; -} - -/** - * list_add_rcu - add a new entry to rcu-protected list - * @new: new entry to be added - * @head: list head to add it after - * - * Insert a new entry after the specified head. - * This is good for implementing stacks. - * - * The caller must take whatever precautions are necessary - * (such as holding appropriate locks) to avoid racing - * with another list-mutation primitive, such as list_add_rcu() - * or list_del_rcu(), running on this same list. - * However, it is perfectly legal to run concurrently with - * the _rcu list-traversal primitives, such as - * list_for_each_entry_rcu(). - */ -static inline void list_add_rcu(struct list_head *new, struct list_head *head) -{ - __list_add_rcu(new, head, head->next); -} - -/** - * list_add_tail_rcu - add a new entry to rcu-protected list - * @new: new entry to be added - * @head: list head to add it before - * - * Insert a new entry before the specified head. - * This is useful for implementing queues. - * - * The caller must take whatever precautions are necessary - * (such as holding appropriate locks) to avoid racing - * with another list-mutation primitive, such as list_add_tail_rcu() - * or list_del_rcu(), running on this same list. - * However, it is perfectly legal to run concurrently with - * the _rcu list-traversal primitives, such as - * list_for_each_entry_rcu(). - */ -static inline void list_add_tail_rcu(struct list_head *new, - struct list_head *head) -{ - __list_add_rcu(new, head->prev, head); -} - -/* - * Delete a list entry by making the prev/next entries - * point to each other. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -static inline void __list_del(struct list_head * prev, struct list_head * next) -{ - next->prev = prev; - prev->next = next; -} - -/** - * list_del - deletes entry from list. - * @entry: the element to delete from the list. - * Note: list_empty on entry does not return true after this, the entry is - * in an undefined state. - */ -static inline void list_del(struct list_head *entry) -{ - __list_del(entry->prev, entry->next); - entry->next = LIST_POISON1; - entry->prev = LIST_POISON2; -} - -/** - * list_del_rcu - deletes entry from list without re-initialization - * @entry: the element to delete from the list. - * - * Note: list_empty on entry does not return true after this, - * the entry is in an undefined state. It is useful for RCU based - * lockfree traversal. - * - * In particular, it means that we can not poison the forward - * pointers that may still be used for walking the list. - * - * The caller must take whatever precautions are necessary - * (such as holding appropriate locks) to avoid racing - * with another list-mutation primitive, such as list_del_rcu() - * or list_add_rcu(), running on this same list. - * However, it is perfectly legal to run concurrently with - * the _rcu list-traversal primitives, such as - * list_for_each_entry_rcu(). - * - * Note that the caller is not permitted to immediately free - * the newly deleted entry. Instead, either synchronize_kernel() - * or call_rcu() must be used to defer freeing until an RCU - * grace period has elapsed. - */ -static inline void list_del_rcu(struct list_head *entry) -{ - __list_del(entry->prev, entry->next); - entry->prev = LIST_POISON2; -} - -/** - * list_del_init - deletes entry from list and reinitialize it. - * @entry: the element to delete from the list. - */ -static inline void list_del_init(struct list_head *entry) -{ - __list_del(entry->prev, entry->next); - INIT_LIST_HEAD(entry); -} - -/** - * list_move - delete from one list and add as another's head - * @list: the entry to move - * @head: the head that will precede our entry - */ -static inline void list_move(struct list_head *list, struct list_head *head) -{ - __list_del(list->prev, list->next); - list_add(list, head); -} - -/** - * list_move_tail - delete from one list and add as another's tail - * @list: the entry to move - * @head: the head that will follow our entry - */ -static inline void list_move_tail(struct list_head *list, - struct list_head *head) -{ - __list_del(list->prev, list->next); - list_add_tail(list, head); -} - -/** - * list_empty - tests whether a list is empty - * @head: the list to test. - */ -static inline int list_empty(const struct list_head *head) -{ - return head->next == head; -} - -/** - * list_empty_careful - tests whether a list is - * empty _and_ checks that no other CPU might be - * in the process of still modifying either member - * - * NOTE: using list_empty_careful() without synchronization - * can only be safe if the only activity that can happen - * to the list entry is list_del_init(). Eg. it cannot be used - * if another CPU could re-list_add() it. - * - * @head: the list to test. - */ -static inline int list_empty_careful(const struct list_head *head) -{ - struct list_head *next = head->next; - return (next == head) && (next == head->prev); -} - -static inline void __list_splice(struct list_head *list, - struct list_head *head) -{ - struct list_head *first = list->next; - struct list_head *last = list->prev; - struct list_head *at = head->next; - - first->prev = head; - head->next = first; - - last->next = at; - at->prev = last; -} - -/** - * list_splice - join two lists - * @list: the new list to add. - * @head: the place to add it in the first list. - */ -static inline void list_splice(struct list_head *list, struct list_head *head) -{ - if (!list_empty(list)) - __list_splice(list, head); -} - -/** - * list_splice_init - join two lists and reinitialise the emptied list. - * @list: the new list to add. - * @head: the place to add it in the first list. - * - * The list at @list is reinitialised - */ -static inline void list_splice_init(struct list_head *list, - struct list_head *head) -{ - if (!list_empty(list)) { - __list_splice(list, head); - INIT_LIST_HEAD(list); - } -} - -/** - * list_entry - get the struct for this entry - * @ptr: the &struct list_head pointer. - * @type: the type of the struct this is embedded in. - * @member: the name of the list_struct within the struct. - */ -#define list_entry(ptr, type, member) \ - container_of(ptr, type, member) - -/** - * list_for_each - iterate over a list - * @pos: the &struct list_head to use as a loop counter. - * @head: the head for your list. - */ -#define list_for_each(pos, head) \ - for (pos = (head)->next, prefetch(pos->next); pos != (head); \ - pos = pos->next, prefetch(pos->next)) - -/** - * __list_for_each - iterate over a list - * @pos: the &struct list_head to use as a loop counter. - * @head: the head for your list. - * - * This variant differs from list_for_each() in that it's the - * simplest possible list iteration code, no prefetching is done. - * Use this for code that knows the list to be very short (empty - * or 1 entry) most of the time. - */ -#define __list_for_each(pos, head) \ - for (pos = (head)->next; pos != (head); pos = pos->next) - -/** - * list_for_each_prev - iterate over a list backwards - * @pos: the &struct list_head to use as a loop counter. - * @head: the head for your list. - */ -#define list_for_each_prev(pos, head) \ - for (pos = (head)->prev, prefetch(pos->prev); pos != (head); \ - pos = pos->prev, prefetch(pos->prev)) - -/** - * list_for_each_safe - iterate over a list safe against removal of list entry - * @pos: the &struct list_head to use as a loop counter. - * @n: another &struct list_head to use as temporary storage - * @head: the head for your list. - */ -#define list_for_each_safe(pos, n, head) \ - for (pos = (head)->next, n = pos->next; pos != (head); \ - pos = n, n = pos->next) - -/** - * list_for_each_entry - iterate over list of given type - * @pos: the type * to use as a loop counter. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry(pos, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member), \ - prefetch(pos->member.next); \ - &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member), \ - prefetch(pos->member.next)) - -/** - * list_for_each_entry_reverse - iterate backwards over list of given type. - * @pos: the type * to use as a loop counter. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry_reverse(pos, head, member) \ - for (pos = list_entry((head)->prev, typeof(*pos), member), \ - prefetch(pos->member.prev); \ - &pos->member != (head); \ - pos = list_entry(pos->member.prev, typeof(*pos), member), \ - prefetch(pos->member.prev)) - -/** - * list_prepare_entry - prepare a pos entry for use as a start point in - * list_for_each_entry_continue - * @pos: the type * to use as a start point - * @head: the head of the list - * @member: the name of the list_struct within the struct. - */ -#define list_prepare_entry(pos, head, member) \ - ((pos) ? : list_entry(head, typeof(*pos), member)) - -/** - * list_for_each_entry_continue - iterate over list of given type - * continuing after existing point - * @pos: the type * to use as a loop counter. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry_continue(pos, head, member) \ - for (pos = list_entry(pos->member.next, typeof(*pos), member), \ - prefetch(pos->member.next); \ - &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member), \ - prefetch(pos->member.next)) - -/** - * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry - * @pos: the type * to use as a loop counter. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry_safe(pos, n, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member), \ - n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -/** - * list_for_each_rcu - iterate over an rcu-protected list - * @pos: the &struct list_head to use as a loop counter. - * @head: the head for your list. - * - * This list-traversal primitive may safely run concurrently with - * the _rcu list-mutation primitives such as list_add_rcu() - * as long as the traversal is guarded by rcu_read_lock(). - */ -#define list_for_each_rcu(pos, head) \ - for (pos = (head)->next, prefetch(pos->next); pos != (head); \ - pos = pos->next, ({ smp_read_barrier_depends(); 0;}), prefetch(pos->next)) - -#define __list_for_each_rcu(pos, head) \ - for (pos = (head)->next; pos != (head); \ - pos = pos->next, ({ smp_read_barrier_depends(); 0;})) - -/** - * list_for_each_safe_rcu - iterate over an rcu-protected list safe - * against removal of list entry - * @pos: the &struct list_head to use as a loop counter. - * @n: another &struct list_head to use as temporary storage - * @head: the head for your list. - * - * This list-traversal primitive may safely run concurrently with - * the _rcu list-mutation primitives such as list_add_rcu() - * as long as the traversal is guarded by rcu_read_lock(). - */ -#define list_for_each_safe_rcu(pos, n, head) \ - for (pos = (head)->next, n = pos->next; pos != (head); \ - pos = n, ({ smp_read_barrier_depends(); 0;}), n = pos->next) - -/** - * list_for_each_entry_rcu - iterate over rcu list of given type - * @pos: the type * to use as a loop counter. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * This list-traversal primitive may safely run concurrently with - * the _rcu list-mutation primitives such as list_add_rcu() - * as long as the traversal is guarded by rcu_read_lock(). - */ -#define list_for_each_entry_rcu(pos, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member), \ - prefetch(pos->member.next); \ - &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member), \ - ({ smp_read_barrier_depends(); 0;}), \ - prefetch(pos->member.next)) - - -/** - * list_for_each_continue_rcu - iterate over an rcu-protected list - * continuing after existing point. - * @pos: the &struct list_head to use as a loop counter. - * @head: the head for your list. - * - * This list-traversal primitive may safely run concurrently with - * the _rcu list-mutation primitives such as list_add_rcu() - * as long as the traversal is guarded by rcu_read_lock(). - */ -#define list_for_each_continue_rcu(pos, head) \ - for ((pos) = (pos)->next, prefetch((pos)->next); (pos) != (head); \ - (pos) = (pos)->next, ({ smp_read_barrier_depends(); 0;}), prefetch((pos)->next)) - -/* - * Double linked lists with a single pointer list head. - * Mostly useful for hash tables where the two pointer list head is - * too wasteful. - * You lose the ability to access the tail in O(1). - */ - -struct hlist_head { - struct hlist_node *first; -}; - -struct hlist_node { - struct hlist_node *next, **pprev; -}; - -#define HLIST_HEAD_INIT { .first = NULL } -#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL } -#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) -#define INIT_HLIST_NODE(ptr) ((ptr)->next = NULL, (ptr)->pprev = NULL) - -static inline int hlist_unhashed(const struct hlist_node *h) -{ - return !h->pprev; -} - -static inline int hlist_empty(const struct hlist_head *h) -{ - return !h->first; -} - -static inline void __hlist_del(struct hlist_node *n) -{ - struct hlist_node *next = n->next; - struct hlist_node **pprev = n->pprev; - *pprev = next; - if (next) - next->pprev = pprev; -} - -static inline void hlist_del(struct hlist_node *n) -{ - __hlist_del(n); - n->next = LIST_POISON1; - n->pprev = LIST_POISON2; -} - -/** - * hlist_del_rcu - deletes entry from hash list without re-initialization - * @n: the element to delete from the hash list. - * - * Note: list_unhashed() on entry does not return true after this, - * the entry is in an undefined state. It is useful for RCU based - * lockfree traversal. - * - * In particular, it means that we can not poison the forward - * pointers that may still be used for walking the hash list. - * - * The caller must take whatever precautions are necessary - * (such as holding appropriate locks) to avoid racing - * with another list-mutation primitive, such as hlist_add_head_rcu() - * or hlist_del_rcu(), running on this same list. - * However, it is perfectly legal to run concurrently with - * the _rcu list-traversal primitives, such as - * hlist_for_each_entry(). - */ -static inline void hlist_del_rcu(struct hlist_node *n) -{ - __hlist_del(n); - n->pprev = LIST_POISON2; -} - -static inline void hlist_del_init(struct hlist_node *n) -{ - if (n->pprev) { - __hlist_del(n); - INIT_HLIST_NODE(n); - } -} - -#define hlist_del_rcu_init hlist_del_init - -static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) -{ - struct hlist_node *first = h->first; - n->next = first; - if (first) - first->pprev = &n->next; - h->first = n; - n->pprev = &h->first; -} - - -/** - * hlist_add_head_rcu - adds the specified element to the specified hlist, - * while permitting racing traversals. - * @n: the element to add to the hash list. - * @h: the list to add to. - * - * The caller must take whatever precautions are necessary - * (such as holding appropriate locks) to avoid racing - * with another list-mutation primitive, such as hlist_add_head_rcu() - * or hlist_del_rcu(), running on this same list. - * However, it is perfectly legal to run concurrently with - * the _rcu list-traversal primitives, such as - * hlist_for_each_entry(), but only if smp_read_barrier_depends() - * is used to prevent memory-consistency problems on Alpha CPUs. - * Regardless of the type of CPU, the list-traversal primitive - * must be guarded by rcu_read_lock(). - * - * OK, so why don't we have an hlist_for_each_entry_rcu()??? - */ -static inline void hlist_add_head_rcu(struct hlist_node *n, - struct hlist_head *h) -{ - struct hlist_node *first = h->first; - n->next = first; - n->pprev = &h->first; - smp_wmb(); - if (first) - first->pprev = &n->next; - h->first = n; -} - -/* next must be != NULL */ -static inline void hlist_add_before(struct hlist_node *n, - struct hlist_node *next) -{ - n->pprev = next->pprev; - n->next = next; - next->pprev = &n->next; - *(n->pprev) = n; -} - -static inline void hlist_add_after(struct hlist_node *n, - struct hlist_node *next) -{ - next->next = n->next; - n->next = next; - next->pprev = &n->next; - - if(next->next) - next->next->pprev = &next->next; -} - -#define hlist_entry(ptr, type, member) container_of(ptr,type,member) - -#define hlist_for_each(pos, head) \ - for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \ - pos = pos->next) - -#define hlist_for_each_safe(pos, n, head) \ - for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \ - pos = n) - -/** - * hlist_for_each_entry - iterate over list of given type - * @tpos: the type * to use as a loop counter. - * @pos: the &struct hlist_node to use as a loop counter. - * @head: the head for your list. - * @member: the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry(tpos, pos, head, member) \ - for (pos = (head)->first; \ - pos && ({ prefetch(pos->next); 1;}) && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ - pos = pos->next) - -/** - * hlist_for_each_entry_continue - iterate over a hlist continuing after existing point - * @tpos: the type * to use as a loop counter. - * @pos: the &struct hlist_node to use as a loop counter. - * @member: the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry_continue(tpos, pos, member) \ - for (pos = (pos)->next; \ - pos && ({ prefetch(pos->next); 1;}) && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ - pos = pos->next) - -/** - * hlist_for_each_entry_from - iterate over a hlist continuing from existing point - * @tpos: the type * to use as a loop counter. - * @pos: the &struct hlist_node to use as a loop counter. - * @member: the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry_from(tpos, pos, member) \ - for (; pos && ({ prefetch(pos->next); 1;}) && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ - pos = pos->next) - -/** - * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry - * @tpos: the type * to use as a loop counter. - * @pos: the &struct hlist_node to use as a loop counter. - * @n: another &struct hlist_node to use as temporary storage - * @head: the head for your list. - * @member: the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ - for (pos = (head)->first; \ - pos && ({ n = pos->next; 1; }) && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ - pos = n) - -/** - * hlist_for_each_entry_rcu - iterate over rcu list of given type - * @pos: the type * to use as a loop counter. - * @pos: the &struct hlist_node to use as a loop counter. - * @head: the head for your list. - * @member: the name of the hlist_node within the struct. - * - * This list-traversal primitive may safely run concurrently with - * the _rcu list-mutation primitives such as hlist_add_rcu() - * as long as the traversal is guarded by rcu_read_lock(). - */ -#define hlist_for_each_entry_rcu(tpos, pos, head, member) \ - for (pos = (head)->first; \ - pos && ({ prefetch(pos->next); 1;}) && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ - pos = pos->next, ({ smp_read_barrier_depends(); 0; }) ) - -#endif diff --git a/daemon/include/local.h b/daemon/include/local.h deleted file mode 100644 index 350b8bf..0000000 --- a/daemon/include/local.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef _LOCAL_SOCKET_H_ -#define _LOCAL_SOCKET_H_ - -#include - -#ifndef UNIX_PATH_MAX -#define UNIX_PATH_MAX 108 -#endif - -struct local_conf { - int backlog; - int reuseaddr; - char path[UNIX_PATH_MAX]; -}; - -/* local server */ -int local_server_create(struct local_conf *conf); -void local_server_destroy(int fd); -int do_local_server_step(int fd, void *data, - void (*process)(int fd, void *data)); - -/* local client */ -int local_client_create(struct local_conf *conf); -void local_client_destroy(int fd); -int do_local_client_step(int fd, void (*process)(char *buf)); -int do_local_request(int, struct local_conf *,void (*step)(char *buf)); -void local_step(char *buf); - -#endif diff --git a/daemon/include/log.h b/daemon/include/log.h deleted file mode 100644 index 9ecff30..0000000 --- a/daemon/include/log.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef _LOG_H_ -#define _LOG_H_ - -#include - -FILE *init_log(char *filename); -void dlog(FILE *fd, char *format, ...); -void close_log(FILE *fd); - -#endif diff --git a/daemon/include/mcast.h b/daemon/include/mcast.h deleted file mode 100644 index 0f3e3cd..0000000 --- a/daemon/include/mcast.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef _MCAST_H_ -#define _MCAST_H_ - -#include - -struct mcast_conf { - int ipproto; - int backlog; - int reuseaddr; - unsigned short port; - union { - struct in_addr inet_addr; - struct in6_addr inet_addr6; - } in; - union { - struct in_addr interface_addr; - struct in6_addr interface_addr6; - } ifa; -}; - -struct mcast_stats { - u_int64_t bytes; - u_int64_t messages; - u_int64_t error; -}; - -struct mcast_sock { - int fd; - union { - struct sockaddr_in ipv4; - struct sockaddr_in6 ipv6; - } addr; - struct mcast_stats stats; -}; - -struct mcast_sock *mcast_server_create(struct mcast_conf *conf); -void mcast_server_destroy(struct mcast_sock *m); - -struct mcast_sock *mcast_client_create(struct mcast_conf *conf); -void mcast_client_destroy(struct mcast_sock *m); - -int mcast_send(struct mcast_sock *m, void *data, int size); -int mcast_recv(struct mcast_sock *m, void *data, int size); - -struct mcast_stats *mcast_get_stats(struct mcast_sock *m); -void mcast_dump_stats(int fd, struct mcast_sock *s, struct mcast_sock *r); - -#endif diff --git a/daemon/include/network.h b/daemon/include/network.h deleted file mode 100644 index dab50db..0000000 --- a/daemon/include/network.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef _NETWORK_H_ -#define _NETWORK_H_ - -#include - -struct nlnetwork { - u_int16_t flags; - u_int16_t checksum; - u_int32_t seq; -}; - -struct nlnetwork_ack { - u_int16_t flags; - u_int16_t checksum; - u_int32_t seq; - u_int32_t from; - u_int32_t to; -}; - -enum { - NET_HELLO_BIT = 0, - NET_HELLO = (1 << NET_HELLO_BIT), - - NET_RESYNC_BIT = 1, - NET_RESYNC = (1 << NET_RESYNC_BIT), - - NET_NACK_BIT = 2, - NET_NACK = (1 << NET_NACK_BIT), - - NET_ACK_BIT = 3, - NET_ACK = (1 << NET_ACK_BIT), -}; - -#endif diff --git a/daemon/include/slist.h b/daemon/include/slist.h deleted file mode 100644 index ab7fa34..0000000 --- a/daemon/include/slist.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef _SLIST_H_ -#define _SLIST_H_ - -#include "linux_list.h" - -#define INIT_SLIST_HEAD(ptr) ((ptr).next = NULL) - -struct slist_head { - struct slist_head *next; -}; - -static inline int slist_empty(const struct slist_head *h) -{ - return !h->next; -} - -static inline void slist_del(struct slist_head *t, struct slist_head *prev) -{ - prev->next = t->next; - t->next = LIST_POISON1; -} - -static inline void slist_add(struct slist_head *head, struct slist_head *t) -{ - struct slist_head *tmp = head->next; - head->next = t; - t->next = tmp; -} - -#define slist_entry(ptr, type, member) container_of(ptr,type,member) - -#define slist_for_each(pos, head) \ - for (pos = (head)->next; pos && ({ prefetch(pos.next); 1; }); \ - pos = pos->next) - -#define slist_for_each_safe(pos, prev, next, head) \ - for (pos = (head)->next, prev = (head); \ - pos && ({ next = pos->next; 1; }); \ - ({ prev = (prev->next != next) ? prev->next : prev; }), pos = next) - -#endif diff --git a/daemon/include/state_helper.h b/daemon/include/state_helper.h deleted file mode 100644 index 1ed0b79..0000000 --- a/daemon/include/state_helper.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef _STATE_HELPER_H_ -#define _STATE_HELPER_H_ - -enum { - ST_H_SKIP, - ST_H_REPLICATE -}; - -struct state_replication_helper { - u_int8_t proto; - unsigned int state; - - int (*verdict)(const struct state_replication_helper *h, - const struct nf_conntrack *ct); -}; - -int state_helper_verdict(int type, struct nf_conntrack *ct); -void state_helper_register(struct state_replication_helper *h, int state); - -#endif diff --git a/daemon/include/sync.h b/daemon/include/sync.h deleted file mode 100644 index 7756c87..0000000 --- a/daemon/include/sync.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef _SYNC_HOOKS_H_ -#define _SYNC_HOOKS_H_ - -struct nlnetwork; -struct us_conntrack; - -struct sync_mode { - int internal_cache_flags; - int external_cache_flags; - struct cache_extra *internal_cache_extra; - struct cache_extra *external_cache_extra; - - int (*init)(void); - void (*kill)(void); - int (*local)(int fd, int type, void *data); - int (*pre_recv)(const struct nlnetwork *net); - void (*post_send)(const struct nlnetwork *net, struct us_conntrack *u); -}; - -extern struct sync_mode notrack; -extern struct sync_mode nack; - -#endif diff --git a/daemon/include/us-conntrack.h b/daemon/include/us-conntrack.h deleted file mode 100644 index 3d71e22..0000000 --- a/daemon/include/us-conntrack.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef _US_CONNTRACK_H_ -#define _US_CONNTRACK_H_ - -#include - -/* be careful, do not modify the layout */ -struct us_conntrack { - struct nf_conntrack *ct; - struct cache *cache; /* add new attributes here */ - char data[0]; -}; - -#endif diff --git a/daemon/src/Makefile.am b/daemon/src/Makefile.am deleted file mode 100644 index 5d1c6cb..0000000 --- a/daemon/src/Makefile.am +++ /dev/null @@ -1,22 +0,0 @@ -include $(top_srcdir)/Make_global.am - -YACC=@YACC@ -d - -CLEANFILES = read_config_yy.c read_config_lex.c - -sbin_PROGRAMS = conntrackd -conntrackd_SOURCES = alarm.c main.c run.c hash.c buffer.c \ - local.c log.c mcast.c netlink.c proxy.c lock.c \ - ignore_pool.c \ - cache.c cache_iterators.c \ - cache_lifetime.c cache_timer.c \ - sync-mode.c sync-notrack.c sync-nack.c \ - traffic_stats.c stats-mode.c \ - network.c checksum.c \ - state_helper.c state_helper_tcp.c \ - read_config_yy.y read_config_lex.l - -conntrackd_LDFLAGS = $(all_libraries) -lnfnetlink -lnetfilter_conntrack \ - -lpthread - -EXTRA_DIST = read_config_yy.h diff --git a/daemon/src/alarm.c b/daemon/src/alarm.c deleted file mode 100644 index 1a465c2..0000000 --- a/daemon/src/alarm.c +++ /dev/null @@ -1,141 +0,0 @@ -/* - * (C) 2006 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include "linux_list.h" -#include "conntrackd.h" -#include "alarm.h" -#include "jhash.h" -#include -#include -#include - -/* alarm cascade */ -#define ALARM_CASCADE_SIZE 10 -static struct list_head *alarm_cascade; - -/* thread stuff */ -static pthread_t alarm_thread; - -struct alarm_list *create_alarm() -{ - return (struct alarm_list *) malloc(sizeof(struct alarm_list)); -} - -void destroy_alarm(struct alarm_list *t) -{ - free(t); -} - -void set_alarm_expiration(struct alarm_list *t, unsigned long expires) -{ - t->expires = expires; -} - -void set_alarm_function(struct alarm_list *t, - void (*fcn)(struct alarm_list *a, void *data)) -{ - t->function = fcn; -} - -void set_alarm_data(struct alarm_list *t, void *data) -{ - t->data = data; -} - -void init_alarm(struct alarm_list *t) -{ - INIT_LIST_HEAD(&t->head); - - t->expires = 0; - t->data = 0; - t->function = NULL; -} - -void add_alarm(struct alarm_list *alarm) -{ - unsigned int pos = jhash(alarm, sizeof(alarm), 0) % ALARM_CASCADE_SIZE; - - list_add(&alarm->head, &alarm_cascade[pos]); -} - -void del_alarm(struct alarm_list *alarm) -{ - list_del(&alarm->head); -} - -int mod_alarm(struct alarm_list *alarm, unsigned long expires) -{ - alarm->expires = expires; - return 0; -} - -void __run_alarms() -{ - struct list_head *i, *tmp; - struct alarm_list *t; - struct timespec req = {0, 1000000000 / ALARM_CASCADE_SIZE}; - struct timespec rem; - static int step = 0; - -retry: - if (nanosleep(&req, &rem) == -1) { - /* interrupted syscall: retry with remaining time */ - if (errno == EINTR) { - memcpy(&req, &rem, sizeof(struct timespec)); - goto retry; - } - } - - lock(); - list_for_each_safe(i, tmp, &alarm_cascade[step]) { - t = (struct alarm_list *) i; - - t->expires--; - if (t->expires == 0) - t->function(t, t->data); - } - step = (step + 1) < ALARM_CASCADE_SIZE ? step + 1 : 0; - unlock(); -} - -void *run_alarms(void *foo) -{ - while(1) - __run_alarms(); -} - -int create_alarm_thread() -{ - int i; - - alarm_cascade = malloc(sizeof(struct list_head) * ALARM_CASCADE_SIZE); - if (alarm_cascade == NULL) - return -1; - - for (i=0; i - * - * 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "buffer.h" - -struct buffer *buffer_create(size_t max_size) -{ - struct buffer *b; - - b = malloc(sizeof(struct buffer)); - if (b == NULL) - return NULL; - memset(b, 0, sizeof(struct buffer)); - - b->max_size = max_size; - INIT_LIST_HEAD(&b->head); - pthread_mutex_init(&b->lock, NULL); - - return b; -} - -void buffer_destroy(struct buffer *b) -{ - struct list_head *i, *tmp; - struct buffer_node *node; - - pthread_mutex_lock(&b->lock); - list_for_each_safe(i, tmp, &b->head) { - node = (struct buffer_node *) i; - list_del(i); - free(node); - } - pthread_mutex_unlock(&b->lock); - pthread_mutex_destroy(&b->lock); - free(b); -} - -static struct buffer_node *buffer_node_create(const void *data, size_t size) -{ - struct buffer_node *n; - - n = malloc(sizeof(struct buffer_node) + size); - if (n == NULL) - return NULL; - - INIT_LIST_HEAD(&n->head); - n->size = size; - memcpy(n->data, data, size); - - return n; -} - -int buffer_add(struct buffer *b, const void *data, size_t size) -{ - int ret = 0; - struct buffer_node *n; - - pthread_mutex_lock(&b->lock); - - /* does it fit this buffer? */ - if (size > b->max_size) { - errno = ENOSPC; - ret = -1; - goto err; - } - -retry: - /* buffer is full: kill the oldest entry */ - if (b->cur_size + size > b->max_size) { - n = (struct buffer_node *) b->head.prev; - list_del(b->head.prev); - b->cur_size -= n->size; - free(n); - goto retry; - } - - n = buffer_node_create(data, size); - if (n == NULL) { - ret = -1; - goto err; - } - - list_add(&n->head, &b->head); - b->cur_size += size; - -err: - pthread_mutex_unlock(&b->lock); - return ret; -} - -void __buffer_del(struct buffer *b, void *data) -{ - struct buffer_node *n = container_of(data, struct buffer_node, data); - - list_del(&n->head); - b->cur_size -= n->size; - free(n); -} - -void buffer_del(struct buffer *b, void *data) -{ - pthread_mutex_lock(&b->lock); - buffer_del(b, data); - pthread_mutex_unlock(&b->lock); -} - -void buffer_iterate(struct buffer *b, - void *data, - int (*iterate)(void *data1, void *data2)) -{ - struct list_head *i, *tmp; - struct buffer_node *n; - - pthread_mutex_lock(&b->lock); - list_for_each_safe(i, tmp, &b->head) { - n = (struct buffer_node *) i; - if (iterate(n->data, data)) - break; - } - pthread_mutex_unlock(&b->lock); -} diff --git a/daemon/src/cache.c b/daemon/src/cache.c deleted file mode 100644 index 6f7442b..0000000 --- a/daemon/src/cache.c +++ /dev/null @@ -1,446 +0,0 @@ -/* - * (C) 2006-2007 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "jhash.h" -#include "hash.h" -#include "conntrackd.h" -#include -#include -#include "us-conntrack.h" -#include "cache.h" -#include "debug.h" - -static u_int32_t hash(const void *data, struct hashtable *table) -{ - unsigned int a, b; - const struct us_conntrack *u = data; - struct nf_conntrack *ct = u->ct; - - a = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV4_SRC), sizeof(u_int32_t), - ((nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO) << 16) | - (nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO)))); - - b = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV4_DST), sizeof(u_int32_t), - ((nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC) << 16) | - (nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST)))); - - return jhash_2words(a, b, 0) % table->hashsize; -} - -static u_int32_t hash6(const void *data, struct hashtable *table) -{ - unsigned int a, b; - const struct us_conntrack *u = data; - struct nf_conntrack *ct = u->ct; - - a = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV6_SRC), sizeof(u_int32_t), - ((nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO) << 16) | - (nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO)))); - - b = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV6_DST), sizeof(u_int32_t), - ((nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC) << 16) | - (nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST)))); - - return jhash_2words(a, b, 0) % table->hashsize; -} - -static int __compare(const struct nf_conntrack *ct1, - const struct nf_conntrack *ct2) -{ - return ((nfct_get_attr_u8(ct1, ATTR_ORIG_L3PROTO) == - nfct_get_attr_u8(ct2, ATTR_ORIG_L3PROTO)) && - (nfct_get_attr_u8(ct1, ATTR_ORIG_L4PROTO) == - nfct_get_attr_u8(ct2, ATTR_ORIG_L4PROTO)) && - (nfct_get_attr_u16(ct1, ATTR_ORIG_PORT_SRC) == - nfct_get_attr_u16(ct2, ATTR_ORIG_PORT_SRC)) && - (nfct_get_attr_u16(ct1, ATTR_ORIG_PORT_DST) == - nfct_get_attr_u16(ct2, ATTR_ORIG_PORT_DST)) && - (nfct_get_attr_u16(ct1, ATTR_REPL_PORT_SRC) == - nfct_get_attr_u16(ct2, ATTR_REPL_PORT_SRC)) && - (nfct_get_attr_u16(ct1, ATTR_REPL_PORT_DST) == - nfct_get_attr_u16(ct2, ATTR_REPL_PORT_DST))); -} - -static int compare(const void *data1, const void *data2) -{ - const struct us_conntrack *u1 = data1; - const struct us_conntrack *u2 = data2; - - return ((nfct_get_attr_u32(u1->ct, ATTR_ORIG_IPV4_SRC) == - nfct_get_attr_u32(u2->ct, ATTR_ORIG_IPV4_SRC)) && - (nfct_get_attr_u32(u1->ct, ATTR_ORIG_IPV4_DST) == - nfct_get_attr_u32(u2->ct, ATTR_ORIG_IPV4_DST)) && - (nfct_get_attr_u32(u1->ct, ATTR_REPL_IPV4_SRC) == - nfct_get_attr_u32(u2->ct, ATTR_REPL_IPV4_SRC)) && - (nfct_get_attr_u32(u1->ct, ATTR_REPL_IPV4_DST) == - nfct_get_attr_u32(u2->ct, ATTR_REPL_IPV4_DST)) && - __compare(u1->ct, u2->ct)); -} - -static int compare6(const void *data1, const void *data2) -{ - const struct us_conntrack *u1 = data1; - const struct us_conntrack *u2 = data2; - - return ((nfct_get_attr_u32(u1->ct, ATTR_ORIG_IPV6_SRC) == - nfct_get_attr_u32(u2->ct, ATTR_ORIG_IPV6_SRC)) && - (nfct_get_attr_u32(u1->ct, ATTR_ORIG_IPV6_DST) == - nfct_get_attr_u32(u2->ct, ATTR_ORIG_IPV6_DST)) && - (nfct_get_attr_u32(u1->ct, ATTR_REPL_IPV6_SRC) == - nfct_get_attr_u32(u2->ct, ATTR_REPL_IPV6_SRC)) && - (nfct_get_attr_u32(u1->ct, ATTR_REPL_IPV6_DST) == - nfct_get_attr_u32(u2->ct, ATTR_REPL_IPV6_DST)) && - __compare(u1->ct, u2->ct)); -} - -struct cache_feature *cache_feature[CACHE_MAX_FEATURE] = { - [TIMER_FEATURE] = &timer_feature, - [LIFETIME_FEATURE] = &lifetime_feature, -}; - -struct cache *cache_create(char *name, - unsigned int features, - u_int8_t proto, - struct cache_extra *extra) -{ - size_t size = sizeof(struct us_conntrack); - int i, j = 0; - struct cache *c; - struct cache_feature *feature_array[CACHE_MAX_FEATURE] = {}; - unsigned int feature_offset[CACHE_MAX_FEATURE] = {}; - unsigned int feature_type[CACHE_MAX_FEATURE] = {}; - - c = malloc(sizeof(struct cache)); - if (!c) - return NULL; - memset(c, 0, sizeof(struct cache)); - - strcpy(c->name, name); - - for (i = 0; i < CACHE_MAX_FEATURE; i++) { - if ((1 << i) & features) { - feature_array[j] = cache_feature[i]; - feature_offset[j] = size; - feature_type[i] = j; - size += cache_feature[i]->size; - j++; - } - } - - memcpy(c->feature_type, feature_type, sizeof(feature_type)); - - c->features = malloc(sizeof(struct cache_feature) * j); - if (!c->features) { - free(c); - return NULL; - } - memcpy(c->features, feature_array, sizeof(struct cache_feature) * j); - c->num_features = j; - - c->extra_offset = size; - c->extra = extra; - if (extra) - size += extra->size; - - c->feature_offset = malloc(sizeof(unsigned int) * j); - if (!c->feature_offset) { - free(c->features); - free(c); - return NULL; - } - memcpy(c->feature_offset, feature_offset, sizeof(unsigned int) * j); - - switch(proto) { - case AF_INET: - c->h = hashtable_create(CONFIG(hashsize), - CONFIG(limit), - size, - hash, - compare); - break; - case AF_INET6: - c->h = hashtable_create(CONFIG(hashsize), - CONFIG(limit), - size, - hash6, - compare6); - break; - } - - if (!c->h) { - free(c->features); - free(c->feature_offset); - free(c); - return NULL; - } - - return c; -} - -void cache_destroy(struct cache *c) -{ - lock(); - hashtable_destroy(c->h); - unlock(); - free(c->features); - free(c->feature_offset); - free(c); -} - -static struct us_conntrack *__add(struct cache *c, struct nf_conntrack *ct) -{ - int i; - size_t size = c->h->datasize; - char buf[size]; - struct us_conntrack *u = (struct us_conntrack *) buf; - struct nf_conntrack *newct; - - memset(u, 0, size); - - u->cache = c; - if ((u->ct = newct = nfct_new()) == NULL) { - errno = ENOMEM; - return 0; - } - memcpy(u->ct, ct, nfct_sizeof(ct)); - - u = hashtable_add(c->h, u); - if (u) { - void *data = u->data; - - for (i = 0; i < c->num_features; i++) { - c->features[i]->add(u, data); - data += c->features[i]->size; - } - - if (c->extra) - c->extra->add(u, ((void *) u) + c->extra_offset); - - return u; - } - free(newct); - - return NULL; -} - -struct us_conntrack *__cache_add(struct cache *c, struct nf_conntrack *ct) -{ - struct us_conntrack *u; - - u = __add(c, ct); - if (u) { - c->add_ok++; - return u; - } - c->add_fail++; - - return NULL; -} - -struct us_conntrack *cache_add(struct cache *c, struct nf_conntrack *ct) -{ - struct us_conntrack *u; - - lock(); - u = __cache_add(c, ct); - unlock(); - - return u; -} - -static struct us_conntrack *__update(struct cache *c, struct nf_conntrack *ct) -{ - size_t size = c->h->datasize; - char buf[size]; - struct us_conntrack *u = (struct us_conntrack *) buf; - - u->ct = ct; - - u = (struct us_conntrack *) hashtable_test(c->h, u); - if (u) { - int i; - void *data = u->data; - - for (i = 0; i < c->num_features; i++) { - c->features[i]->update(u, data); - data += c->features[i]->size; - } - - if (c->extra) - c->extra->update(u, ((void *) u) + c->extra_offset); - - if (nfct_attr_is_set(ct, ATTR_STATUS)) - nfct_set_attr_u32(u->ct, ATTR_STATUS, - nfct_get_attr_u32(ct, ATTR_STATUS)); - if (nfct_attr_is_set(ct, ATTR_TCP_STATE)) - nfct_set_attr_u8(u->ct, ATTR_TCP_STATE, - nfct_get_attr_u8(ct, ATTR_TCP_STATE)); - if (nfct_attr_is_set(ct, ATTR_TIMEOUT)) - nfct_set_attr_u32(u->ct, ATTR_TIMEOUT, - nfct_get_attr_u32(ct, ATTR_TIMEOUT)); - - return u; - } - return NULL; -} - -struct us_conntrack *__cache_update(struct cache *c, struct nf_conntrack *ct) -{ - struct us_conntrack *u; - - u = __update(c, ct); - if (u) { - c->upd_ok++; - return u; - } - c->upd_fail++; - - return NULL; -} - -struct us_conntrack *cache_update(struct cache *c, struct nf_conntrack *ct) -{ - struct us_conntrack *u; - - lock(); - u = __cache_update(c, ct); - unlock(); - - return u; -} - -struct us_conntrack *cache_update_force(struct cache *c, - struct nf_conntrack *ct) -{ - struct us_conntrack *u; - - lock(); - if ((u = __update(c, ct)) != NULL) { - c->upd_ok++; - unlock(); - return u; - } - if ((u = __add(c, ct)) != NULL) { - c->add_ok++; - unlock(); - return u; - } - c->add_fail++; - unlock(); - return NULL; -} - -int cache_test(struct cache *c, struct nf_conntrack *ct) -{ - size_t size = c->h->datasize; - char buf[size]; - struct us_conntrack *u = (struct us_conntrack *) buf; - void *ret; - - u->ct = ct; - - lock(); - ret = hashtable_test(c->h, u); - unlock(); - - return ret != NULL; -} - -static int __del(struct cache *c, struct nf_conntrack *ct) -{ - size_t size = c->h->datasize; - char buf[size]; - struct us_conntrack *u = (struct us_conntrack *) buf; - - u->ct = ct; - - u = (struct us_conntrack *) hashtable_test(c->h, u); - if (u) { - int i; - void *data = u->data; - struct nf_conntrack *p = u->ct; - - for (i = 0; i < c->num_features; i++) { - c->features[i]->destroy(u, data); - data += c->features[i]->size; - } - - if (c->extra) - c->extra->destroy(u, ((void *) u) + c->extra_offset); - - hashtable_del(c->h, u); - free(p); - return 1; - } - return 0; -} - -int __cache_del(struct cache *c, struct nf_conntrack *ct) -{ - if (__del(c, ct)) { - c->del_ok++; - return 1; - } - c->del_fail++; - - return 0; -} - -int cache_del(struct cache *c, struct nf_conntrack *ct) -{ - int ret; - - lock(); - ret = __cache_del(c, ct); - unlock(); - - return ret; -} - -struct us_conntrack *cache_get_conntrack(struct cache *c, void *data) -{ - return data - c->extra_offset; -} - -void *cache_get_extra(struct cache *c, void *data) -{ - return data + c->extra_offset; -} - -void cache_stats(struct cache *c, int fd) -{ - char buf[512]; - int size; - - lock(); - size = sprintf(buf, "cache %s:\n" - "current active connections:\t%12u\n" - "connections created:\t\t%12u\tfailed:\t%12u\n" - "connections updated:\t\t%12u\tfailed:\t%12u\n" - "connections destroyed:\t\t%12u\tfailed:\t%12u\n\n", - c->name, - hashtable_counter(c->h), - c->add_ok, - c->add_fail, - c->upd_ok, - c->upd_fail, - c->del_ok, - c->del_fail); - unlock(); - send(fd, buf, size, 0); -} diff --git a/daemon/src/cache_iterators.c b/daemon/src/cache_iterators.c deleted file mode 100644 index 5d5d22b..0000000 --- a/daemon/src/cache_iterators.c +++ /dev/null @@ -1,229 +0,0 @@ -/* - * (C) 2006-2007 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "cache.h" -#include "jhash.h" -#include "hash.h" -#include "conntrackd.h" -#include -#include -#include "us-conntrack.h" -#include "debug.h" - -struct __dump_container { - int fd; - int type; -}; - -static int do_dump(void *data1, void *data2) -{ - char buf[1024]; - int size; - struct __dump_container *container = data1; - struct us_conntrack *u = data2; - void *data = u->data; - int i; - - memset(buf, 0, sizeof(buf)); - size = nfct_snprintf(buf, - sizeof(buf), - u->ct, - NFCT_T_UNKNOWN, - container->type, - 0); - - for (i = 0; i < u->cache->num_features; i++) { - if (u->cache->features[i]->dump) { - size += u->cache->features[i]->dump(u, - data, - buf+size, - container->type); - data += u->cache->features[i]->size; - } - } - size += sprintf(buf+size, "\n"); - if (send(container->fd, buf, size, 0) == -1) { - if (errno != EPIPE) - return -1; - } - - return 0; -} - -void cache_dump(struct cache *c, int fd, int type) -{ - struct __dump_container tmp = { - .fd = fd, - .type = type - }; - - lock(); - hashtable_iterate(c->h, (void *) &tmp, do_dump); - unlock(); -} - -static int do_commit(void *data1, void *data2) -{ - int ret; - struct cache *c = data1; - struct us_conntrack *u = data2; - struct nf_conntrack *ct; - char buf[4096]; - struct nlmsghdr *nlh = (struct nlmsghdr *)buf; - - ct = nfct_clone(u->ct); - if (ct == NULL) - return 0; - - if (nfct_attr_is_set(ct, ATTR_STATUS)) { - u_int32_t status = nfct_get_attr_u32(ct, ATTR_STATUS); - status &= ~IPS_EXPECTED; - nfct_set_attr_u32(ct, ATTR_STATUS, status); - } - - if (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) - nfct_setobjopt(ct, NFCT_SOPT_UNDO_SNAT); - if (nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) - nfct_setobjopt(ct, NFCT_SOPT_UNDO_DNAT); - if (nfct_getobjopt(ct, NFCT_GOPT_IS_SPAT)) - nfct_setobjopt(ct, NFCT_SOPT_UNDO_SPAT); - if (nfct_getobjopt(ct, NFCT_GOPT_IS_DPAT)) - nfct_setobjopt(ct, NFCT_SOPT_UNDO_DPAT); - - /* - * Set a reduced timeout for candidate-to-be-committed - * conntracks that live in the external cache - */ - nfct_set_attr_u32(ct, ATTR_TIMEOUT, CONFIG(commit_timeout)); - - ret = nfct_build_query(STATE(subsys_sync), - NFCT_Q_CREATE, - ct, - nlh, - sizeof(buf)); - - free(ct); - - if (ret == -1) { - /* XXX: Please cleanup this debug crap, default in logfile */ - debug("--- failed to build: %s --- \n", strerror(errno)); - return 0; - } - - ret = nfnl_query(STATE(sync), nlh); - if (ret == -1) { - switch(errno) { - case EEXIST: - c->commit_exist++; - break; - default: - c->commit_fail++; - break; - } - debug("--- failed to commit: %s --- \n", strerror(errno)); - } else { - c->commit_ok++; - debug("----- commit -----\n"); - } - - /* keep iterating even if we have found errors */ - return 0; -} - -void cache_commit(struct cache *c) -{ - unsigned int commit_ok = c->commit_ok; - unsigned int commit_exist = c->commit_exist; - unsigned int commit_fail = c->commit_fail; - - lock(); - hashtable_iterate(c->h, c, do_commit); - unlock(); - - /* calculate new entries committed */ - commit_ok = c->commit_ok - commit_ok; - commit_fail = c->commit_fail - commit_fail; - commit_exist = c->commit_exist - commit_exist; - - /* log results */ - dlog(STATE(log), "Committed %u new entries", commit_ok); - - if (commit_exist) - dlog(STATE(log), "%u entries ignored, " - "already exist", commit_exist); - if (commit_fail) - dlog(STATE(log), "%u entries can't be " - "committed", commit_fail); -} - -static int do_flush(void *data1, void *data2) -{ - struct cache *c = data1; - struct us_conntrack *u = data2; - void *data = u->data; - int i; - - for (i = 0; i < c->num_features; i++) { - c->features[i]->destroy(u, data); - data += c->features[i]->size; - } - free(u->ct); - - return 0; -} - -void cache_flush(struct cache *c) -{ - lock(); - hashtable_iterate(c->h, c, do_flush); - hashtable_flush(c->h); - c->flush++; - unlock(); -} - -#include "sync.h" -#include "network.h" - -static int do_bulk(void *data1, void *data2) -{ - int ret; - struct us_conntrack *u = data2; - char buf[4096]; - struct nlnetwork *net = (struct nlnetwork *) buf; - - ret = build_network_msg(NFCT_Q_UPDATE, - STATE(subsys_sync), - u->ct, - buf, - sizeof(buf)); - if (ret == -1) - debug_ct(u->ct, "failed to build"); - - mcast_send_netmsg(STATE_SYNC(mcast_client), net); - STATE_SYNC(mcast_sync)->post_send(net, u); - - /* keep iterating even if we have found errors */ - return 0; -} - -void cache_bulk(struct cache *c) -{ - lock(); - hashtable_iterate(c->h, NULL, do_bulk); - unlock(); -} diff --git a/daemon/src/cache_lifetime.c b/daemon/src/cache_lifetime.c deleted file mode 100644 index ae54df2..0000000 --- a/daemon/src/cache_lifetime.c +++ /dev/null @@ -1,65 +0,0 @@ -/* - * (C) 2006 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include "conntrackd.h" -#include "us-conntrack.h" -#include "cache.h" -#include "alarm.h" - -static void lifetime_add(struct us_conntrack *u, void *data) -{ - long *lifetime = data; - struct timeval tv; - - gettimeofday(&tv, NULL); - - *lifetime = tv.tv_sec; -} - -static void lifetime_update(struct us_conntrack *u, void *data) -{ -} - -static void lifetime_destroy(struct us_conntrack *u, void *data) -{ -} - -static int lifetime_dump(struct us_conntrack *u, - void *data, - char *buf, - int type) -{ - long *lifetime = data; - struct timeval tv; - - if (type == NFCT_O_XML) - return 0; - - gettimeofday(&tv, NULL); - - return sprintf(buf, " [active since %lds]", tv.tv_sec - *lifetime); -} - -struct cache_feature lifetime_feature = { - .size = sizeof(long), - .add = lifetime_add, - .update = lifetime_update, - .destroy = lifetime_destroy, - .dump = lifetime_dump -}; diff --git a/daemon/src/cache_timer.c b/daemon/src/cache_timer.c deleted file mode 100644 index 213b59a..0000000 --- a/daemon/src/cache_timer.c +++ /dev/null @@ -1,72 +0,0 @@ -/* - * (C) 2006 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include "conntrackd.h" -#include "us-conntrack.h" -#include "cache.h" -#include "alarm.h" - -static void timeout(struct alarm_list *a, void *data) -{ - struct us_conntrack *u = data; - - debug_ct(u->ct, "expired timeout"); - __cache_del(u->cache, u->ct); -} - -static void timer_add(struct us_conntrack *u, void *data) -{ - struct alarm_list *alarm = data; - - init_alarm(alarm); - set_alarm_expiration(alarm, CONFIG(cache_timeout)); - set_alarm_data(alarm, u); - set_alarm_function(alarm, timeout); - add_alarm(alarm); -} - -static void timer_update(struct us_conntrack *u, void *data) -{ - struct alarm_list *alarm = data; - mod_alarm(alarm, CONFIG(cache_timeout)); -} - -static void timer_destroy(struct us_conntrack *u, void *data) -{ - struct alarm_list *alarm = data; - del_alarm(alarm); -} - -static int timer_dump(struct us_conntrack *u, void *data, char *buf, int type) -{ - struct alarm_list *alarm = data; - - if (type == NFCT_O_XML) - return 0; - - return sprintf(buf, " [expires in %ds]", alarm->expires); -} - -struct cache_feature timer_feature = { - .size = sizeof(struct alarm_list), - .add = timer_add, - .update = timer_update, - .destroy = timer_destroy, - .dump = timer_dump -}; diff --git a/daemon/src/checksum.c b/daemon/src/checksum.c deleted file mode 100644 index 41866ff..0000000 --- a/daemon/src/checksum.c +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Extracted from RFC 1071 with some minor changes to fix compilation on GCC, - * this can probably be improved - * --pablo 11/feb/07 - */ - -#include - -unsigned short do_csum(const void *addr, unsigned int count) -{ - unsigned int sum = 0; - - /* checksumming disabled, just skip */ - if (CONFIG(flags) & DONT_CHECKSUM) - return 0; - - while(count > 1) { - /* This is the inner loop */ - sum += *((unsigned short *) addr++); - count -= 2; - } - - /* Add left-over byte, if any */ - if(count > 0) - sum += *((unsigned char *) addr); - - /* Fold 32-bit sum to 16 bits */ - while (sum>>16) - sum = (sum & 0xffff) + (sum >> 16); - - return ~sum; -} diff --git a/daemon/src/hash.c b/daemon/src/hash.c deleted file mode 100644 index 274a140..0000000 --- a/daemon/src/hash.c +++ /dev/null @@ -1,199 +0,0 @@ -/* - * (C) 2006-2007 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Description: generic hash table implementation - */ - -#include -#include -#include -#include -#include -#include "slist.h" -#include "hash.h" - - -struct hashtable_node *hashtable_alloc_node(int datasize, void *data) -{ - struct hashtable_node *n; - int size = sizeof(struct hashtable_node) + datasize; - - n = malloc(size); - if (!n) - return NULL; - memset(n, 0, size); - memcpy(n->data, data, datasize); - - return n; -} - -void hashtable_destroy_node(struct hashtable_node *h) -{ - free(h); -} - -struct hashtable * -hashtable_create(int hashsize, int limit, int datasize, - u_int32_t (*hash)(const void *data, struct hashtable *table), - int (*compare)(const void *data1, const void *data2)) -{ - int i; - struct hashtable *h; - struct hashtype *t; - int size = sizeof(struct hashtable) - + hashsize * sizeof(struct slist_head); - - h = (struct hashtable *) malloc(size); - if (!h) { - errno = ENOMEM; - return NULL; - } - - memset(h, 0, size); - for (i=0; imembers[i]); - - h->hashsize = hashsize; - h->limit = limit; - h->datasize = datasize; - h->hash = hash; - h->compare = compare; - - return h; -} - -void hashtable_destroy(struct hashtable *h) -{ - hashtable_flush(h); - free(h); -} - -void *hashtable_add(struct hashtable *table, void *data) -{ - struct slist_head *e; - struct hashtable_node *n; - u_int32_t id; - int i; - - /* hash table is full */ - if (table->count >= table->limit) { - errno = ENOSPC; - return NULL; - } - - id = table->hash(data, table); - - slist_for_each(e, &table->members[id]) { - n = slist_entry(e, struct hashtable_node, head); - if (table->compare(n->data, data)) { - errno = EEXIST; - return NULL; - } - } - - n = hashtable_alloc_node(table->datasize, data); - if (n == NULL) { - errno = ENOMEM; - return NULL; - } - - slist_add(&table->members[id], &n->head); - table->count++; - - return n->data; -} - -void *hashtable_test(struct hashtable *table, const void *data) -{ - struct slist_head *e; - u_int32_t id; - struct hashtable_node *n; - int i; - - id = table->hash(data, table); - - slist_for_each(e, &table->members[id]) { - n = slist_entry(e, struct hashtable_node, head); - if (table->compare(n->data, data)) - return n->data; - } - - errno = ENOENT; - return NULL; -} - -int hashtable_del(struct hashtable *table, void *data) -{ - struct slist_head *e, *next, *prev; - u_int32_t id; - struct hashtable_node *n; - int i; - - id = table->hash(data, table); - - slist_for_each_safe(e, prev, next, &table->members[id]) { - n = slist_entry(e, struct hashtable_node, head); - if (table->compare(n->data, data)) { - slist_del(e, prev); - hashtable_destroy_node(n); - table->count--; - return 0; - } - } - errno = ENOENT; - return -1; -} - -int hashtable_flush(struct hashtable *table) -{ - int i; - struct slist_head *e, *next, *prev; - struct hashtable_node *n; - - for (i=0; i < table->hashsize; i++) - slist_for_each_safe(e, prev, next, &table->members[i]) { - n = slist_entry(e, struct hashtable_node, head); - slist_del(e, prev); - hashtable_destroy_node(n); - } - - table->count = 0; - - return 0; -} - -int hashtable_iterate(struct hashtable *table, void *data, - int (*iterate)(void *data1, void *data2)) -{ - int i; - struct slist_head *e, *next, *prev; - struct hashtable_node *n; - - for (i=0; i < table->hashsize; i++) { - slist_for_each_safe(e, prev, next, &table->members[i]) { - n = slist_entry(e, struct hashtable_node, head); - if (iterate(data, n->data) == -1) - return -1; - } - } - return 0; -} - -unsigned int hashtable_counter(struct hashtable *table) -{ - return table->count; -} diff --git a/daemon/src/ignore_pool.c b/daemon/src/ignore_pool.c deleted file mode 100644 index 5946617..0000000 --- a/daemon/src/ignore_pool.c +++ /dev/null @@ -1,136 +0,0 @@ -/* - * (C) 2006-2007 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "jhash.h" -#include "hash.h" -#include "conntrackd.h" -#include "ignore.h" -#include "debug.h" -#include - -#define IGNORE_POOL_SIZE 32 -#define IGNORE_POOL_LIMIT 1024 - -static u_int32_t hash(const void *data, struct hashtable *table) -{ - const u_int32_t *ip = data; - - return jhash_1word(*ip, 0) % table->hashsize; -} - -static u_int32_t hash6(const void *data, struct hashtable *table) -{ - return jhash(data, sizeof(u_int32_t)*4, 0) % table->hashsize; -} - -static int compare(const void *data1, const void *data2) -{ - const u_int32_t *ip1 = data1; - const u_int32_t *ip2 = data2; - - return *ip1 == *ip2; -} - -static int compare6(const void *data1, const void *data2) -{ - return memcmp(data1, data2, sizeof(u_int32_t)*4) == 0; -} - -struct ignore_pool *ignore_pool_create(u_int8_t proto) -{ - int i, j = 0; - struct ignore_pool *ip; - - ip = malloc(sizeof(struct ignore_pool)); - if (!ip) - return NULL; - memset(ip, 0, sizeof(struct ignore_pool)); - - switch(proto) { - case AF_INET: - ip->h = hashtable_create(IGNORE_POOL_SIZE, - IGNORE_POOL_LIMIT, - sizeof(u_int32_t), - hash, - compare); - break; - case AF_INET6: - ip->h = hashtable_create(IGNORE_POOL_SIZE, - IGNORE_POOL_LIMIT, - sizeof(u_int32_t)*4, - hash6, - compare6); - break; - } - - if (!ip->h) { - free(ip); - return NULL; - } - - return ip; -} - -void ignore_pool_destroy(struct ignore_pool *ip) -{ - hashtable_destroy(ip->h); - free(ip); -} - -int ignore_pool_add(struct ignore_pool *ip, void *data) -{ - if (!hashtable_add(ip->h, data)) - return 0; - - return 1; -} - -int __ignore_pool_test_ipv4(struct ignore_pool *ip, struct nf_conntrack *ct) -{ - return (hashtable_test(ip->h, nfct_get_attr(ct, ATTR_ORIG_IPV4_SRC)) || - hashtable_test(ip->h, nfct_get_attr(ct, ATTR_ORIG_IPV4_DST)) || - hashtable_test(ip->h, nfct_get_attr(ct, ATTR_REPL_IPV4_SRC)) || - hashtable_test(ip->h, nfct_get_attr(ct, ATTR_REPL_IPV4_DST))); -} - -int __ignore_pool_test_ipv6(struct ignore_pool *ip, struct nf_conntrack *ct) -{ - return (hashtable_test(ip->h, nfct_get_attr(ct, ATTR_ORIG_IPV6_SRC)) || - hashtable_test(ip->h, nfct_get_attr(ct, ATTR_ORIG_IPV6_DST)) || - hashtable_test(ip->h, nfct_get_attr(ct, ATTR_REPL_IPV6_SRC)) || - hashtable_test(ip->h, nfct_get_attr(ct, ATTR_REPL_IPV6_DST))); -} - -int ignore_pool_test(struct ignore_pool *ip, struct nf_conntrack *ct) -{ - int ret; - - switch(nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO)) { - case AF_INET: - ret = __ignore_pool_test_ipv4(ip, ct); - break; - case AF_INET6: - ret = __ignore_pool_test_ipv6(ip, ct); - break; - default: - dlog(STATE(log), "unknown conntrack layer 3 protocol?"); - break; - } - - return ret; -} diff --git a/daemon/src/local.c b/daemon/src/local.c deleted file mode 100644 index eef70ad..0000000 --- a/daemon/src/local.c +++ /dev/null @@ -1,159 +0,0 @@ -/* - * (C) 2006 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Description: UNIX sockets library - */ - -#include -#include -#include -#include -#include "debug.h" - -#include "local.h" - -int local_server_create(struct local_conf *conf) -{ - int fd; - int len; - struct sockaddr_un local; - - if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { - debug("local_server_create:socket"); - return -1; - } - - if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &conf->reuseaddr, - sizeof(conf->reuseaddr)) == -1) { - debug("local_server_create:setsockopt"); - close(fd); - return -1; - } - - local.sun_family = AF_UNIX; - strcpy(local.sun_path, conf->path); - len = strlen(local.sun_path) + sizeof(local.sun_family); - unlink(conf->path); - - if (bind(fd, (struct sockaddr *) &local, len) == -1) { - debug("local_server_create:bind"); - close(fd); - return -1; - } - - if (listen(fd, conf->backlog) == -1) { - close(fd); - debug("local_server_create:listen"); - return -1; - } - - return fd; -} - -void local_server_destroy(int fd) -{ - close(fd); -} - -int do_local_server_step(int fd, void *data, - void (*process)(int fd, void *data)) -{ - int rfd; - struct sockaddr_un local; - size_t sin_size = sizeof(struct sockaddr_un); - - if ((rfd = accept(fd, (struct sockaddr *)&local, &sin_size)) == -1) { - debug("do_local_server_step:accept"); - return -1; - } - - process(rfd, data); - close(rfd); - - return 0; -} - -int local_client_create(struct local_conf *conf) -{ - int len; - struct sockaddr_un local; - int fd; - - if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) - return -1; - - local.sun_family = AF_UNIX; - strcpy(local.sun_path, conf->path); - len = strlen(local.sun_path) + sizeof(local.sun_family); - - if (connect(fd, (struct sockaddr *) &local, len) == -1) { - close(fd); - debug("local_client_create: connect: "); - return -1; - } - - return fd; -} - -void local_client_destroy(int fd) -{ - close(fd); -} - -int do_local_client_step(int fd, void (*process)(char *buf)) -{ - int numbytes; - char buf[1024]; - - memset(buf, 0, sizeof(buf)); - while ((numbytes = recv(fd, buf, sizeof(buf)-1, 0)) > 0) { - buf[sizeof(buf)-1] = '\0'; - if (process) - process(buf); - memset(buf, 0, sizeof(buf)); - } - - return 0; -} - -void local_step(char *buf) -{ - printf(buf); -} - -int do_local_request(int request, - struct local_conf *conf, - void (*step)(char *buf)) -{ - int fd, ret; - - fd = local_client_create(conf); - if (fd == -1) - return -1; - - ret = send(fd, &request, sizeof(int), 0); - if (ret == -1) { - debug("send:"); - return -1; - } - - do_local_client_step(fd, step); - - local_client_destroy(fd); - - return 0; -} diff --git a/daemon/src/lock.c b/daemon/src/lock.c deleted file mode 100644 index cd68baf..0000000 --- a/daemon/src/lock.c +++ /dev/null @@ -1,32 +0,0 @@ -/* - * (C) 2006 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include - -static pthread_mutex_t global_lock = PTHREAD_MUTEX_INITIALIZER; - -void lock() -{ - pthread_mutex_lock(&global_lock); -} - -void unlock() -{ - pthread_mutex_unlock(&global_lock); -} diff --git a/daemon/src/log.c b/daemon/src/log.c deleted file mode 100644 index 88cadea..0000000 --- a/daemon/src/log.c +++ /dev/null @@ -1,57 +0,0 @@ -/* - * (C) 2006 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Description: Logging support for the conntrack daemon - */ - -#include -#include -#include -#include - -FILE *init_log(char *filename) -{ - FILE *fd; - - fd = fopen(filename, "a+"); - if (fd == NULL) { - fprintf(stderr, "can't open log file `%s'\n", filename); - return NULL; - } - - return fd; -} - -void dlog(FILE *fd, char *format, ...) -{ - time_t t = time(NULL); - char *buf = ctime(&t); - va_list args; - - buf[strlen(buf)-1]='\0'; - va_start(args, format); - fprintf(fd, "[%s] (pid=%d) ", buf, getpid()); - vfprintf(fd, format, args); - va_end(args); - fprintf(fd, "\n"); - fflush(fd); -} - -void close_log(FILE *fd) -{ - fclose(fd); -} diff --git a/daemon/src/main.c b/daemon/src/main.c deleted file mode 100644 index 1c75970..0000000 --- a/daemon/src/main.c +++ /dev/null @@ -1,302 +0,0 @@ -/* - * (C) 2006-2007 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include "conntrackd.h" -#include "log.h" -#include -#include -#include -#include -#include -#include -#include "hash.h" -#include "jhash.h" - -struct ct_general_state st; -union ct_state state; - -static const char usage_daemon_commands[] = - "Daemon mode commands:\n" - " -d [options]\t\tRun in daemon mode\n" - " -S [options]\t\tRun in statistics mode\n"; - -static const char usage_client_commands[] = - "Client mode commands:\n" - " -c, commit external cache to conntrack table\n" - " -f, flush internal and external cache\n" - " -F, flush kernel conntrack table\n" - " -i, display content of the internal cache\n" - " -e, display the content of the external cache\n" - " -k, kill conntrack daemon\n" - " -s, dump statistics\n" - " -R, resync with kernel conntrack table\n" - " -n, request resync with other node (only NACK mode)\n" - " -x, dump cache in XML format (requires -i or -e)"; - -static const char usage_options[] = - "Options:\n" - " -C [configfile], configuration file path\n"; - -void show_usage(char *progname) -{ - fprintf(stdout, "Connection tracking userspace daemon v%s\n", VERSION); - fprintf(stdout, "Usage: %s [commands] [options]\n\n", progname); - fprintf(stdout, "%s\n", usage_daemon_commands); - fprintf(stdout, "%s\n", usage_client_commands); - fprintf(stdout, "%s\n", usage_options); -} - -/* These live in run.c */ -int init(int); -void run(void); - -void set_operation_mode(int *current, int want, char *argv[]) -{ - if (*current == NOT_SET) { - *current = want; - return; - } - if (*current != want) { - show_usage(argv[0]); - fprintf(stderr, "\nError: Invalid parameters\n"); - exit(EXIT_FAILURE); - } -} - -static int check_capabilities(void) -{ - int ret; - cap_user_header_t hcap; - cap_user_data_t dcap; - - hcap = malloc(sizeof(cap_user_header_t)); - if (!hcap) - return -1; - - hcap->version = _LINUX_CAPABILITY_VERSION; - hcap->pid = getpid(); - - dcap = malloc(sizeof(cap_user_data_t)); - if (!dcap) { - free(hcap); - return -1; - } - - if (capget(hcap, dcap) == -1) { - free(hcap); - free(dcap); - return -1; - } - - ret = dcap->permitted & (1 << CAP_NET_ADMIN); - - free(hcap); - free(dcap); - - return ret; -} - -int main(int argc, char *argv[]) -{ - int ret, i, config_set = 0, action; - char config_file[PATH_MAX]; - int type = 0, mode = 0; - struct utsname u; - int version, major, minor; - - /* Check kernel version: it must be >= 2.6.18 */ - if (uname(&u) == -1) { - fprintf(stderr, "Can't retrieve kernel version via uname()\n"); - exit(EXIT_FAILURE); - } - sscanf(u.release, "%d.%d.%d", &version, &major, &minor); - if (version < 2 && major < 6) { - fprintf(stderr, "Linux kernel version must be >= 2.6.18\n"); - exit(EXIT_FAILURE); - } - - if (major == 6 && minor < 18) { - fprintf(stderr, "Linux kernel version must be >= 2.6.18\n"); - exit(EXIT_FAILURE); - } - - ret = check_capabilities(); - switch (ret) { - case -1: - fprintf(stderr, "Can't get capabilities\n"); - exit(EXIT_FAILURE); - break; - case 0: - fprintf(stderr, "You require CAP_NET_ADMIN in order " - "to run conntrackd\n"); - exit(EXIT_FAILURE); - break; - default: - break; - } - - for (i=1; i= PATH_MAX){ - config_file[PATH_MAX-1]='\0'; - fprintf(stderr, "Path to config file " - "to long. Cutting it " - "down to %d characters", - PATH_MAX); - } - config_set = 1; - break; - } - show_usage(argv[0]); - fprintf(stderr, "Missing config filename\n"); - break; - case 'F': - set_operation_mode(&type, REQUEST, argv); - action = FLUSH_MASTER; - case 'f': - set_operation_mode(&type, REQUEST, argv); - action = FLUSH_CACHE; - break; - case 'R': - set_operation_mode(&type, REQUEST, argv); - action = RESYNC_MASTER; - break; - case 'B': - set_operation_mode(&type, REQUEST, argv); - action = SEND_BULK; - break; - case 'k': - set_operation_mode(&type, REQUEST, argv); - action = KILL; - break; - case 's': - set_operation_mode(&type, REQUEST, argv); - action = STATS; - break; - case 'S': - set_operation_mode(&mode, STATS_MODE, argv); - break; - case 'n': - set_operation_mode(&type, REQUEST, argv); - action = REQUEST_DUMP; - break; - case 'x': - if (action == DUMP_INTERNAL) - action = DUMP_INT_XML; - else if (action == DUMP_EXTERNAL) - action = DUMP_EXT_XML; - else { - show_usage(argv[0]); - fprintf(stderr, "Error: Invalid parameters\n"); - exit(EXIT_FAILURE); - - } - break; - default: - show_usage(argv[0]); - fprintf(stderr, "Unknown option: %s\n", argv[i]); - return 0; - break; - } - } - - if (config_set == 0) - strcpy(config_file, DEFAULT_CONFIGFILE); - - if ((ret = init_config(config_file)) == -1) { - fprintf(stderr, "can't open config file `%s'\n", config_file); - exit(EXIT_FAILURE); - } - - /* - * Setting up logfile - */ - STATE(log) = init_log(CONFIG(logfile)); - if (!STATE(log)) { - fprintf(stdout, "can't open logfile `%s\n'", CONFIG(logfile)); - exit(EXIT_FAILURE); - } - - if (type == REQUEST) { - if (do_local_request(action, &conf.local, local_step) == -1) - fprintf(stderr, "can't connect: is conntrackd " - "running? appropiate permissions?\n"); - exit(EXIT_SUCCESS); - } - - /* - * lock file - */ - if ((ret = open(CONFIG(lockfile), O_CREAT | O_EXCL | O_TRUNC)) == -1) { - fprintf(stderr, "lockfile `%s' exists, perhaps conntrackd " - "already running?\n", CONFIG(lockfile)); - exit(EXIT_FAILURE); - } - close(ret); - - /* Daemonize conntrackd */ - if (type == DAEMON) { - pid_t pid; - - if ((pid = fork()) == -1) { - dlog(STATE(log), "fork() failed: " - "%s", strerror(errno)); - exit(EXIT_FAILURE); - } else if (pid) - exit(EXIT_SUCCESS); - - dlog(STATE(log), "--- starting in daemon mode ---"); - } else - dlog(STATE(log), "--- starting in console mode ---"); - - /* - * initialization process - */ - - if (init(mode) == -1) { - close_log(STATE(log)); - fprintf(stderr, "ERROR: conntrackd cannot start, please " - "check the logfile for more info\n"); - unlink(CONFIG(lockfile)); - exit(EXIT_FAILURE); - } - - /* - * run main process - */ - run(); -} diff --git a/daemon/src/mcast.c b/daemon/src/mcast.c deleted file mode 100644 index 9904544..0000000 --- a/daemon/src/mcast.c +++ /dev/null @@ -1,287 +0,0 @@ -/* - * (C) 2006 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Description: multicast socket library - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "mcast.h" -#include "debug.h" - -struct mcast_sock *mcast_server_create(struct mcast_conf *conf) -{ - int yes = 1; - union { - struct ip_mreq ipv4; - struct ipv6_mreq ipv6; - } mreq; - struct mcast_sock *m; - - m = (struct mcast_sock *) malloc(sizeof(struct mcast_sock)); - if (!m) - return NULL; - memset(m, 0, sizeof(struct mcast_sock)); - - switch(conf->ipproto) { - case AF_INET: - mreq.ipv4.imr_multiaddr.s_addr = conf->in.inet_addr.s_addr; - mreq.ipv4.imr_interface.s_addr =conf->ifa.interface_addr.s_addr; - - m->addr.ipv4.sin_family = AF_INET; - m->addr.ipv4.sin_port = htons(conf->port); - m->addr.ipv4.sin_addr.s_addr = htonl(INADDR_ANY); - break; - - case AF_INET6: - memcpy(&mreq.ipv6.ipv6mr_multiaddr, &conf->in.inet_addr6, - sizeof(u_int32_t) * 4); - memcpy(&mreq.ipv6.ipv6mr_interface, &conf->ifa.interface_addr6, - sizeof(u_int32_t) * 4); - - m->addr.ipv6.sin6_family = AF_INET6; - m->addr.ipv6.sin6_port = htons(conf->port); - m->addr.ipv6.sin6_addr = in6addr_any; - break; - } - - if ((m->fd = socket(conf->ipproto, SOCK_DGRAM, 0)) == -1) { - debug("mcast_sock_server_create:socket"); - free(m); - return NULL; - } - - if (setsockopt(m->fd, SOL_SOCKET, SO_REUSEADDR, &yes, - sizeof(int)) == -1) { - debug("mcast_sock_server_create:setsockopt1"); - close(m->fd); - free(m); - return NULL; - } - - if (bind(m->fd, (struct sockaddr *) &m->addr, - sizeof(struct sockaddr)) == -1) { - debug("mcast_sock_server_create:bind"); - close(m->fd); - free(m); - return NULL; - } - - - switch(conf->ipproto) { - case AF_INET: - if (setsockopt(m->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, - &mreq.ipv4, sizeof(mreq.ipv4)) < 0) { - debug("mcast_sock_server_create:setsockopt2"); - close(m->fd); - free(m); - return NULL; - } - break; - case AF_INET6: - if (setsockopt(m->fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, - &mreq.ipv6, sizeof(mreq.ipv6)) < 0) { - debug("mcast_sock_server_create:setsockopt2"); - close(m->fd); - free(m); - return NULL; - } - break; - } - - return m; -} - -void mcast_server_destroy(struct mcast_sock *m) -{ - close(m->fd); - free(m); -} - -static int -__mcast_client_create_ipv4(struct mcast_sock *m, struct mcast_conf *conf) -{ - int no = 0; - - m->addr.ipv4.sin_family = AF_INET; - m->addr.ipv4.sin_port = htons(conf->port); - m->addr.ipv4.sin_addr = conf->in.inet_addr; - - if (setsockopt(m->fd, IPPROTO_IP, IP_MULTICAST_LOOP, &no, - sizeof(int)) < 0) { - debug("mcast_sock_client_create:setsockopt2"); - close(m->fd); - return -1; - } - - if (setsockopt(m->fd, IPPROTO_IP, IP_MULTICAST_IF, - &conf->ifa.interface_addr, - sizeof(struct in_addr)) == -1) { - debug("mcast_sock_client_create:setsockopt3"); - close(m->fd); - free(m); - return -1; - } - - return 0; -} - -static int -__mcast_client_create_ipv6(struct mcast_sock *m, struct mcast_conf *conf) -{ - int no = 0; - - m->addr.ipv6.sin6_family = AF_INET6; - m->addr.ipv6.sin6_port = htons(conf->port); - memcpy(&m->addr.ipv6.sin6_addr, - &conf->in.inet_addr6, - sizeof(struct in6_addr)); - - if (setsockopt(m->fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &no, - sizeof(int)) < 0) { - debug("mcast_sock_client_create:setsockopt2"); - close(m->fd); - return -1; - } - - if (setsockopt(m->fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, - &conf->ifa.interface_addr, - sizeof(struct in_addr)) == -1) { - debug("mcast_sock_client_create:setsockopt3"); - close(m->fd); - free(m); - return -1; - } - - return 0; -} - -struct mcast_sock *mcast_client_create(struct mcast_conf *conf) -{ - int ret = 0; - struct sockaddr_in addr; - struct mcast_sock *m; - - m = (struct mcast_sock *) malloc(sizeof(struct mcast_sock)); - if (!m) - return NULL; - memset(m, 0, sizeof(struct mcast_sock)); - - if ((m->fd = socket(conf->ipproto, SOCK_DGRAM, 0)) == -1) { - debug("mcast_sock_client_create:socket"); - return NULL; - } - - switch(conf->ipproto) { - case AF_INET: - ret = __mcast_client_create_ipv4(m, conf); - break; - case AF_INET6: - ret = __mcast_client_create_ipv6(m, conf); - break; - default: - break; - } - - if (ret == -1) { - free(m); - m = NULL; - } - - return m; -} - -void mcast_client_destroy(struct mcast_sock *m) -{ - close(m->fd); - free(m); -} - -int mcast_send(struct mcast_sock *m, void *data, int size) -{ - int ret; - - ret = sendto(m->fd, - data, - size, - 0, - (struct sockaddr *) &m->addr, - sizeof(struct sockaddr)); - if (ret == -1) { - debug("mcast_sock_send"); - m->stats.error++; - return ret; - } - - m->stats.bytes += ret; - m->stats.messages++; - - return ret; -} - -int mcast_recv(struct mcast_sock *m, void *data, int size) -{ - int ret; - socklen_t sin_size = sizeof(struct sockaddr_in); - - ret = recvfrom(m->fd, - data, - size, - 0, - (struct sockaddr *)&m->addr, - &sin_size); - if (ret == -1) { - debug("mcast_sock_recv"); - m->stats.error++; - return ret; - } - - m->stats.bytes += ret; - m->stats.messages++; - - return ret; -} - -struct mcast_stats *mcast_get_stats(struct mcast_sock *m) -{ - return &m->stats; -} - -void mcast_dump_stats(int fd, struct mcast_sock *s, struct mcast_sock *r) -{ - char buf[512]; - int size; - - size = sprintf(buf, "multicast traffic:\n" - "%20llu Bytes sent " - "%20llu Bytes recv\n" - "%20llu Pckts sent " - "%20llu Pckts recv\n" - "%20llu Error send " - "%20llu Error recv\n\n", - s->stats.bytes, r->stats.bytes, - s->stats.messages, r->stats.messages, - s->stats.error, r->stats.error); - - send(fd, buf, size, 0); -} diff --git a/daemon/src/netlink.c b/daemon/src/netlink.c deleted file mode 100644 index 0bde632..0000000 --- a/daemon/src/netlink.c +++ /dev/null @@ -1,326 +0,0 @@ -/* - * (C) 2006 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "conntrackd.h" -#include -#include -#include -#include "us-conntrack.h" -#include -#include -#include "network.h" - -static int ignore_conntrack(struct nf_conntrack *ct) -{ - /* ignore a certain protocol */ - if (CONFIG(ignore_protocol)[nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO)]) - return 1; - - /* Accept DNAT'ed traffic: not really coming to the local machine */ - if ((CONFIG(flags) & STRIP_NAT) && - nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) { - debug_ct(ct, "DNAT"); - return 0; - } - - /* Accept SNAT'ed traffic: not really coming to the local machine */ - if ((CONFIG(flags) & STRIP_NAT) && - nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) { - debug_ct(ct, "SNAT"); - return 0; - } - - /* Ignore traffic */ - if (ignore_pool_test(STATE(ignore_pool), ct)) { - debug_ct(ct, "ignore traffic"); - return 1; - } - - return 0; -} - -static int nl_event_handler(struct nlmsghdr *nlh, - struct nfattr *nfa[], - void *data) -{ - char tmp[1024]; - struct nf_conntrack *ct = (struct nf_conntrack *) tmp; - int type; - - memset(tmp, 0, sizeof(tmp)); - - if ((type = nfct_parse_conntrack(NFCT_T_ALL, nlh, ct)) == NFCT_T_ERROR) - return NFCT_CB_STOP; - - /* - * Ignore this conntrack: it talks about a - * connection that is not interesting for us. - */ - if (ignore_conntrack(ct)) - return NFCT_CB_STOP; - - switch(type) { - case NFCT_T_NEW: - STATE(mode)->event_new(ct, nlh); - break; - case NFCT_T_UPDATE: - STATE(mode)->event_upd(ct, nlh); - break; - case NFCT_T_DESTROY: - if (STATE(mode)->event_dst(ct, nlh)) - update_traffic_stats(ct); - break; - default: - dlog(STATE(log), "received unknown msg from ctnetlink\n"); - break; - } - - return NFCT_CB_STOP; -} - -int nl_init_event_handler(void) -{ - struct nfnl_callback cb_events = { - .call = nl_event_handler, - .attr_count = CTA_MAX - }; - - /* open event netlink socket */ - STATE(event) = nfnl_open(); - if (!STATE(event)) - return -1; - - /* set up socket buffer size */ - if (CONFIG(netlink_buffer_size)) - nfnl_rcvbufsiz(STATE(event), CONFIG(netlink_buffer_size)); - else { - socklen_t socklen = sizeof(unsigned int); - unsigned int read_size; - - /* get current buffer size */ - getsockopt(nfnl_fd(STATE(event)), SOL_SOCKET, - SO_RCVBUF, &read_size, &socklen); - - CONFIG(netlink_buffer_size) = read_size; - } - - /* ensure that maximum grown size is >= than maximum size */ - if (CONFIG(netlink_buffer_size_max_grown) < CONFIG(netlink_buffer_size)) - CONFIG(netlink_buffer_size_max_grown) = - CONFIG(netlink_buffer_size); - - /* open event subsystem */ - STATE(subsys_event) = nfnl_subsys_open(STATE(event), - NFNL_SUBSYS_CTNETLINK, - IPCTNL_MSG_MAX, - NFCT_ALL_CT_GROUPS); - if (STATE(subsys_event) == NULL) - return -1; - - /* register callback for new and update events */ - nfnl_callback_register(STATE(subsys_event), - IPCTNL_MSG_CT_NEW, - &cb_events); - - /* register callback for delete events */ - nfnl_callback_register(STATE(subsys_event), - IPCTNL_MSG_CT_DELETE, - &cb_events); - - return 0; -} - -static int nl_dump_handler(struct nlmsghdr *nlh, - struct nfattr *nfa[], - void *data) -{ - char buf[1024]; - struct nf_conntrack *ct = (struct nf_conntrack *) buf; - int type; - - memset(buf, 0, sizeof(buf)); - - if ((type = nfct_parse_conntrack(NFCT_T_ALL, nlh, ct)) == NFCT_T_ERROR) - return NFCT_CB_CONTINUE; - - /* - * Ignore this conntrack: it talks about a - * connection that is not interesting for us. - */ - if (ignore_conntrack(ct)) - return NFCT_CB_CONTINUE; - - switch(type) { - case NFCT_T_UPDATE: - STATE(mode)->dump(ct, nlh); - break; - default: - dlog(STATE(log), "received unknown msg from ctnetlink"); - break; - } - return NFCT_CB_CONTINUE; -} - -int nl_init_dump_handler(void) -{ - struct nfnl_callback cb_dump = { - .call = nl_dump_handler, - .attr_count = CTA_MAX - }; - - /* open dump netlink socket */ - STATE(dump) = nfnl_open(); - if (!STATE(dump)) - return -1; - - /* open dump subsystem */ - STATE(subsys_dump) = nfnl_subsys_open(STATE(dump), - NFNL_SUBSYS_CTNETLINK, - IPCTNL_MSG_MAX, - 0); - if (STATE(subsys_dump) == NULL) - return -1; - - /* register callback for dumped entries */ - nfnl_callback_register(STATE(subsys_dump), - IPCTNL_MSG_CT_NEW, - &cb_dump); - - if (nl_dump_conntrack_table(STATE(dump), STATE(subsys_dump)) == -1) - return -1; - - return 0; -} - -static int nl_overrun_handler(struct nlmsghdr *nlh, - struct nfattr *nfa[], - void *data) -{ - char buf[1024]; - struct nf_conntrack *ct = (struct nf_conntrack *) buf; - int type; - - memset(buf, 0, sizeof(buf)); - - if ((type = nfct_parse_conntrack(NFCT_T_ALL, nlh, ct)) == NFCT_T_ERROR) - return NFCT_CB_CONTINUE; - - /* - * Ignore this conntrack: it talks about a - * connection that is not interesting for us. - */ - if (ignore_conntrack(ct)) - return NFCT_CB_CONTINUE; - - switch(type) { - case NFCT_T_UPDATE: - if (STATE(mode)->overrun) - STATE(mode)->overrun(ct, nlh); - break; - default: - dlog(STATE(log), "received unknown msg from ctnetlink"); - break; - } - return NFCT_CB_CONTINUE; -} - -int nl_init_overrun_handler(void) -{ - struct nfnl_callback cb_sync = { - .call = nl_overrun_handler, - .attr_count = CTA_MAX - }; - - /* open sync netlink socket */ - STATE(sync) = nfnl_open(); - if (!STATE(sync)) - return -1; - - /* open synchronizer subsystem */ - STATE(subsys_sync) = nfnl_subsys_open(STATE(sync), - NFNL_SUBSYS_CTNETLINK, - IPCTNL_MSG_MAX, - 0); - if (STATE(subsys_sync) == NULL) - return -1; - - /* register callback for dumped entries */ - nfnl_callback_register(STATE(subsys_sync), - IPCTNL_MSG_CT_NEW, - &cb_sync); - - return 0; -} - -static int warned = 0; - -void nl_resize_socket_buffer(struct nfnl_handle *h) -{ - unsigned int s = CONFIG(netlink_buffer_size) * 2; - - /* already warned that we have reached the maximum buffer size */ - if (warned) - return; - - if (s > CONFIG(netlink_buffer_size_max_grown)) { - dlog(STATE(log), "maximum netlink socket buffer size reached"); - s = CONFIG(netlink_buffer_size_max_grown); - warned = 1; - } - - CONFIG(netlink_buffer_size) = nfnl_rcvbufsiz(h, s); - - /* notify the sysadmin */ - dlog(STATE(log), "netlink socket buffer size has been set to %u bytes", - CONFIG(netlink_buffer_size)); -} - -int nl_dump_conntrack_table(struct nfnl_handle *h, - struct nfnl_subsys_handle *subsys) -{ - struct nfnlhdr req; - - memset(&req, 0, sizeof(req)); - nfct_build_query(subsys, - NFCT_Q_DUMP, - &CONFIG(family), - &req, - sizeof(req)); - - if (nfnl_query(h, &req.nlh) == -1) - return -1; - - return 0; -} - -int nl_flush_master_conntrack_table(void) -{ - struct nfnlhdr req; - - memset(&req, 0, sizeof(req)); - nfct_build_query(STATE(subsys_sync), - NFCT_Q_FLUSH, - &CONFIG(family), - &req, - sizeof(req)); - - if (nfnl_query(STATE(sync), &req.nlh) == -1) - return -1; - - return 0; -} diff --git a/daemon/src/network.c b/daemon/src/network.c deleted file mode 100644 index b9be318..0000000 --- a/daemon/src/network.c +++ /dev/null @@ -1,282 +0,0 @@ -/* - * (C) 2006-2007 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "conntrackd.h" -#include "network.h" - -#if 0 -#define _TEST_DROP -#else -#undef _TEST_DROP -#endif - -static int drop = 0; /* debugging purposes */ -static unsigned int seq_set, cur_seq; - -static int send_netmsg(struct mcast_sock *m, void *data, unsigned int len) -{ - struct nlnetwork *net = data; - -#ifdef _TEST_DROP - if (++drop > 10) { - drop = 0; - printf("dropping resend (seq=%u)\n", ntohl(net->seq)); - return 0; - } -#endif - return mcast_send(m, net, len); -} - -int mcast_send_netmsg(struct mcast_sock *m, void *data) -{ - struct nlmsghdr *nlh = data + sizeof(struct nlnetwork); - unsigned int len = nlh->nlmsg_len + sizeof(struct nlnetwork); - struct nlnetwork *net = data; - - if (!seq_set) { - seq_set = 1; - cur_seq = time(NULL); - net->flags |= NET_HELLO; - } - - net->flags = htons(net->flags); - net->seq = htonl(cur_seq++); - - if (nlh_host2network(nlh) == -1) - return -1; - - net->checksum = 0; - net->checksum = ntohs(do_csum(data, len)); - - return send_netmsg(m, data, len); -} - -int mcast_resend_netmsg(struct mcast_sock *m, void *data) -{ - struct nlnetwork *net = data; - struct nlmsghdr *nlh = data + sizeof(struct nlnetwork); - unsigned int len = htonl(nlh->nlmsg_len) + sizeof(struct nlnetwork); - - net->flags = ntohs(net->flags); - - if (!seq_set) { - seq_set = 1; - cur_seq = time(NULL); - net->flags |= NET_HELLO; - } - - if (net->flags & NET_NACK || net->flags & NET_ACK) { - struct nlnetwork_ack *nack = (struct nlnetwork_ack *) net; - len = sizeof(struct nlnetwork_ack); - } - - net->flags = htons(net->flags); - net->seq = htonl(cur_seq++); - net->checksum = 0; - net->checksum = ntohs(do_csum(data, len)); - - return send_netmsg(m, data, len); -} - -int mcast_send_error(struct mcast_sock *m, void *data) -{ - struct nlnetwork *net = data; - unsigned int len = sizeof(struct nlnetwork); - - if (!seq_set) { - seq_set = 1; - cur_seq = time(NULL); - net->flags |= NET_HELLO; - } - - if (net->flags & NET_NACK || net->flags & NET_ACK) { - struct nlnetwork_ack *nack = (struct nlnetwork_ack *) net; - nack->from = htonl(nack->from); - nack->to = htonl(nack->to); - len = sizeof(struct nlnetwork_ack); - } - - net->flags = htons(net->flags); - net->seq = htonl(cur_seq++); - net->checksum = 0; - net->checksum = ntohs(do_csum(data, len)); - - return send_netmsg(m, data, len); -} - -static int valid_checksum(void *data, unsigned int len) -{ - struct nlnetwork *net = data; - unsigned short checksum, tmp; - - checksum = ntohs(net->checksum); - - /* no checksum, skip */ - if (!checksum) - return 1; - - net->checksum = 0; - tmp = do_csum(data, len); - - return tmp == checksum; -} - -int mcast_recv_netmsg(struct mcast_sock *m, void *data, int len) -{ - int ret; - struct nlnetwork *net = data; - struct nlmsghdr *nlh = data + sizeof(struct nlnetwork); - struct nfgenmsg *nfhdr; - - ret = mcast_recv(m, net, len); - if (ret <= 0) - return ret; - - if (ret < sizeof(struct nlnetwork)) - return -1; - - if (!valid_checksum(data, ret)) - return -1; - - net->flags = ntohs(net->flags); - net->seq = ntohl(net->seq); - - if (net->flags & NET_HELLO) - STATE_SYNC(last_seq_recv) = net->seq-1; - - if (net->flags & NET_NACK || net->flags & NET_ACK) { - struct nlnetwork_ack *nack = (struct nlnetwork_ack *) net; - - if (ret < sizeof(struct nlnetwork_ack)) - return -1; - - nack->from = ntohl(nack->from); - nack->to = ntohl(nack->to); - - return ret; - } - - if (net->flags & NET_RESYNC) - return ret; - - /* information received is too small */ - if (ret < NLMSG_SPACE(sizeof(struct nfgenmsg))) - return -1; - - /* information received and message length does not match */ - if (ret != ntohl(nlh->nlmsg_len) + sizeof(struct nlnetwork)) - return -1; - - /* this message does not come from ctnetlink */ - if (NFNL_SUBSYS_ID(ntohs(nlh->nlmsg_type)) != NFNL_SUBSYS_CTNETLINK) - return -1; - - nfhdr = NLMSG_DATA(nlh); - - /* only AF_INET and AF_INET6 are supported */ - if (nfhdr->nfgen_family != AF_INET && - nfhdr->nfgen_family != AF_INET6) - return -1; - - /* only process message coming from nfnetlink v0 */ - if (nfhdr->version != NFNETLINK_V0) - return -1; - - if (nlh_network2host(nlh) == -1) - return -1; - - return ret; -} - -int mcast_track_seq(u_int32_t seq, u_int32_t *exp_seq) -{ - static int seq_set = 0; - int ret = 1; - - /* netlink sequence tracking initialization */ - if (!seq_set) { - seq_set = 1; - goto out; - } - - /* fast path: we received the correct sequence */ - if (seq == STATE_SYNC(last_seq_recv)+1) - goto out; - - /* out of sequence: some messages got lost */ - if (seq > STATE_SYNC(last_seq_recv)+1) { - STATE_SYNC(packets_lost) += seq-STATE_SYNC(last_seq_recv)+1; - ret = 0; - goto out; - } - - /* out of sequence: replayed or sequence wrapped around issues */ - if (seq < STATE_SYNC(last_seq_recv)+1) { - /* - * Check if the sequence has wrapped around. - * Perhaps it can be a replayed packet. - */ - if (STATE_SYNC(last_seq_recv)+1-seq > ~0U/2) { - /* - * Indeed, it is a wrapped around - */ - STATE_SYNC(packets_lost) += - ~0U-STATE_SYNC(last_seq_recv)+1+seq; - } else { - /* - * It is a delayed packet - */ - dlog(STATE(log), "delayed packet? exp=%u rcv=%u", - STATE_SYNC(last_seq_recv)+1, seq); - } - ret = 0; - } - -out: - *exp_seq = STATE_SYNC(last_seq_recv)+1; - /* update expected sequence */ - STATE_SYNC(last_seq_recv) = seq; - - return ret; -} - -int build_network_msg(const int msg_type, - struct nfnl_subsys_handle *ssh, - struct nf_conntrack *ct, - void *buffer, - unsigned int size) -{ - memset(buffer, 0, size); - buffer += sizeof(struct nlnetwork); - return nfct_build_query(ssh, msg_type, ct, buffer, size); -} - -unsigned int parse_network_msg(struct nf_conntrack *ct, - const struct nlmsghdr *nlh) -{ - /* - * The parsing of netlink messages going through network is - * similar to the one that is done for messages coming from - * kernel, therefore do not replicate more code and use the - * function provided in the libraries. - * - * Yup, this is a hack 8) - */ - return nfct_parse_conntrack(NFCT_T_ALL, nlh, ct); -} - diff --git a/daemon/src/proxy.c b/daemon/src/proxy.c deleted file mode 100644 index b9bb04e..0000000 --- a/daemon/src/proxy.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * (C) 2006 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include - -#if 0 -#define dprintf printf -#else -#define dprintf -#endif - -int nlh_payload_host2network(struct nfattr *nfa, int len) -{ - struct nfattr *__nfa; - - while (NFA_OK(nfa, len)) { - - dprintf("type=%d nfalen=%d len=%d [%s]\n", - nfa->nfa_type & 0x7fff, - nfa->nfa_len, len, - nfa->nfa_type & NFNL_NFA_NEST ? "NEST":""); - - if (nfa->nfa_type & NFNL_NFA_NEST) { - if (NFA_PAYLOAD(nfa) > len) - return -1; - - if (nlh_payload_host2network(NFA_DATA(nfa), - NFA_PAYLOAD(nfa)) == -1) - return -1; - } - - __nfa = NFA_NEXT(nfa, len); - - nfa->nfa_type = htons(nfa->nfa_type); - nfa->nfa_len = htons(nfa->nfa_len); - - nfa = __nfa; - } - return 0; -} - -int nlh_host2network(struct nlmsghdr *nlh) -{ - struct nfgenmsg *nfhdr = NLMSG_DATA(nlh); - struct nfattr *cda[CTA_MAX]; - unsigned int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg)); - unsigned int len = nlh->nlmsg_len - NLMSG_ALIGN(min_len); - - nlh->nlmsg_len = htonl(nlh->nlmsg_len); - nlh->nlmsg_type = htons(nlh->nlmsg_type); - nlh->nlmsg_flags = htons(nlh->nlmsg_flags); - nlh->nlmsg_seq = htonl(nlh->nlmsg_seq); - nlh->nlmsg_pid = htonl(nlh->nlmsg_pid); - - nfhdr->res_id = htons(nfhdr->res_id); - - return nlh_payload_host2network(NFM_NFA(NLMSG_DATA(nlh)), len); -} - -int nlh_payload_network2host(struct nfattr *nfa, int len) -{ - nfa->nfa_type = ntohs(nfa->nfa_type); - nfa->nfa_len = ntohs(nfa->nfa_len); - - while(NFA_OK(nfa, len)) { - - dprintf("type=%d nfalen=%d len=%d [%s]\n", - nfa->nfa_type & 0x7fff, - nfa->nfa_len, len, - nfa->nfa_type & NFNL_NFA_NEST ? "NEST":""); - - if (nfa->nfa_type & NFNL_NFA_NEST) { - if (NFA_PAYLOAD(nfa) > len) - return -1; - - if (nlh_payload_network2host(NFA_DATA(nfa), - NFA_PAYLOAD(nfa)) == -1) - return -1; - } - - nfa = NFA_NEXT(nfa,len); - - if (len < NFA_LENGTH(0)) - break; - - nfa->nfa_type = ntohs(nfa->nfa_type); - nfa->nfa_len = ntohs(nfa->nfa_len); - } - return 0; -} - -int nlh_network2host(struct nlmsghdr *nlh) -{ - struct nfgenmsg *nfhdr = NLMSG_DATA(nlh); - struct nfattr *cda[CTA_MAX]; - unsigned int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg)); - unsigned int len = ntohl(nlh->nlmsg_len) - NLMSG_ALIGN(min_len); - - nlh->nlmsg_len = ntohl(nlh->nlmsg_len); - nlh->nlmsg_type = ntohs(nlh->nlmsg_type); - nlh->nlmsg_flags = ntohs(nlh->nlmsg_flags); - nlh->nlmsg_seq = ntohl(nlh->nlmsg_seq); - nlh->nlmsg_pid = ntohl(nlh->nlmsg_pid); - - nfhdr->res_id = ntohs(nfhdr->res_id); - - return nlh_payload_network2host(NFM_NFA(NLMSG_DATA(nlh)), len); -} diff --git a/daemon/src/read_config_lex.l b/daemon/src/read_config_lex.l deleted file mode 100644 index dee90c9..0000000 --- a/daemon/src/read_config_lex.l +++ /dev/null @@ -1,125 +0,0 @@ -%{ -/* - * (C) 2006 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Description: configuration file syntax - */ - -#include "read_config_yy.h" -#include "conntrackd.h" -%} - -%option yylineno -%option nounput - -ws [ \t]+ -comment #.*$ -nl [\n\r] - -is_on [o|O][n|N] -is_off [o|O][f|F][f|F] -integer [0-9]+ -path \/[^\"\n ]* -ip4_end [0-9]*[0-9]+ -ip4_part [0-2]*{ip4_end} -ip4 {ip4_part}\.{ip4_part}\.{ip4_part}\.{ip4_part} -hex_255 [0-9a-fA-F]{1,4} -ip6_part {hex_255}":"? -ip6_form1 {ip6_part}{0,16}"::"{ip6_part}{0,16} -ip6_form2 ({hex_255}":"){16}{hex_255} -ip6 {ip6_form1}|{ip6_form2} -string [a-zA-Z]* -persistent [P|p][E|e][R|r][S|s][I|i][S|s][T|t][E|e][N|n][T|T] -nack [N|n][A|a][C|c][K|k] - -%% -"UNIX" { return T_UNIX; } -"IPv4_address" { return T_IPV4_ADDR; } -"IPv6_address" { return T_IPV6_ADDR; } -"IPv4_interface" { return T_IPV4_IFACE; } -"IPv6_interface" { return T_IPV6_IFACE; } -"Port" { return T_PORT; } -"Multicast" { return T_MULTICAST; } -"HashSize" { return T_HASHSIZE; } -"RefreshTime" { return T_REFRESH; } -"CacheTimeout" { return T_EXPIRE; } -"CommitTimeout" { return T_TIMEOUT; } -"DelayDestroyMessages" { return T_DELAY; } -"HashLimit" { return T_HASHLIMIT; } -"Path" { return T_PATH; } -"IgnoreProtocol" { return T_IGNORE_PROTOCOL; } -"UDP" { return T_UDP; } -"ICMP" { return T_ICMP; } -"VRRP" { return T_VRRP; } -"IGMP" { return T_IGMP; } -"TCP" { return T_TCP; } -"IgnoreTrafficFor" { return T_IGNORE_TRAFFIC; } -"StripNAT" { return T_STRIP_NAT; } -"Backlog" { return T_BACKLOG; } -"Group" { return T_GROUP; } -"LogFile" { return T_LOG; } -"LockFile" { return T_LOCK; } -"General" { return T_GENERAL; } -"Sync" { return T_SYNC; } -"Stats" { return T_STATS; } -"RelaxTransitions" { return T_RELAX_TRANSITIONS; } -"SocketBufferSize" { return T_BUFFER_SIZE; } -"SocketBufferSizeMaxGrown" { return T_BUFFER_SIZE_MAX_GROWN; } -"SocketBufferSizeMaxGrowth" { return T_BUFFER_SIZE_MAX_GROWN; } -"Mode" { return T_SYNC_MODE; } -"ListenTo" { return T_LISTEN_TO; } -"Family" { return T_FAMILY; } -"ResendBufferSize" { return T_RESEND_BUFFER_SIZE; } -"Checksum" { return T_CHECKSUM; } -"ACKWindowSize" { return T_WINDOWSIZE; } -"Replicate" { return T_REPLICATE; } -"for" { return T_FOR; } -"SYN_SENT" { return T_SYN_SENT; } -"SYN_RECV" { return T_SYN_RECV; } -"ESTABLISHED" { return T_ESTABLISHED; } -"FIN_WAIT" { return T_FIN_WAIT; } -"CLOSE_WAIT" { return T_CLOSE_WAIT; } -"LAST_ACK" { return T_LAST_ACK; } -"TIME_WAIT" { return T_TIME_WAIT; } -"CLOSE" { return T_CLOSE; } -"LISTEN" { return T_LISTEN; } - -{is_on} { return T_ON; } -{is_off} { return T_OFF; } -{integer} { yylval.val = atoi(yytext); return T_NUMBER; } -{ip4} { yylval.string = strdup(yytext); return T_IP; } -{ip6} { yylval.string = strdup(yytext); return T_IP; } -{path} { yylval.string = strdup(yytext); return T_PATH_VAL; } -{persistent} { return T_PERSISTENT; } -{nack} { return T_NACK; } -{string} { yylval.string = strdup(yytext); return T_STRING; } - -{comment} ; -{ws} ; -{nl} ; - -<> { yyterminate(); } - -. { return yytext[0]; } - -%% - -int -yywrap() -{ - return 1; -} diff --git a/daemon/src/read_config_yy.y b/daemon/src/read_config_yy.y deleted file mode 100644 index 1668919..0000000 --- a/daemon/src/read_config_yy.y +++ /dev/null @@ -1,550 +0,0 @@ -%{ -/* - * (C) 2006 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Description: configuration file abstract grammar - */ - -#include -#include -#include -#include -#include "conntrackd.h" -#include "ignore.h" - -extern char *yytext; -extern int yylineno; - -struct ct_conf conf; -%} - -%union { - int val; - char *string; -} - -%token T_IPV4_ADDR T_IPV4_IFACE T_PORT T_HASHSIZE T_HASHLIMIT T_MULTICAST -%token T_PATH T_UNIX T_REFRESH T_IPV6_ADDR T_IPV6_IFACE -%token T_IGNORE_UDP T_IGNORE_ICMP T_IGNORE_TRAFFIC T_BACKLOG T_GROUP -%token T_LOG T_UDP T_ICMP T_IGMP T_VRRP T_TCP T_IGNORE_PROTOCOL -%token T_LOCK T_STRIP_NAT T_BUFFER_SIZE_MAX_GROWN T_EXPIRE T_TIMEOUT -%token T_GENERAL T_SYNC T_STATS T_RELAX_TRANSITIONS T_BUFFER_SIZE T_DELAY -%token T_SYNC_MODE T_LISTEN_TO T_FAMILY T_RESEND_BUFFER_SIZE -%token T_PERSISTENT T_NACK T_CHECKSUM T_WINDOWSIZE T_ON T_OFF -%token T_REPLICATE T_FOR -%token T_ESTABLISHED T_SYN_SENT T_SYN_RECV T_FIN_WAIT -%token T_CLOSE_WAIT T_LAST_ACK T_TIME_WAIT T_CLOSE T_LISTEN - - -%token T_IP T_PATH_VAL -%token T_NUMBER -%token T_STRING - -%% - -configfile : - | lines - ; - -lines : line - | lines line - ; - -line : ignore_protocol - | ignore_traffic - | strip_nat - | general - | sync - | stats - ; - -log : T_LOG T_PATH_VAL -{ - strncpy(conf.logfile, $2, FILENAME_MAXLEN); -}; - -lock : T_LOCK T_PATH_VAL -{ - strncpy(conf.lockfile, $2, FILENAME_MAXLEN); -}; - -strip_nat: T_STRIP_NAT -{ - conf.flags |= STRIP_NAT; -}; - -refreshtime : T_REFRESH T_NUMBER -{ - conf.refresh = $2; -}; - -expiretime: T_EXPIRE T_NUMBER -{ - conf.cache_timeout = $2; -}; - -timeout: T_TIMEOUT T_NUMBER -{ - conf.commit_timeout = $2; -}; - -checksum: T_CHECKSUM T_ON -{ -}; - -checksum: T_CHECKSUM T_OFF -{ - conf.flags |= DONT_CHECKSUM; -}; - -ignore_traffic : T_IGNORE_TRAFFIC '{' ignore_traffic_options '}'; - -ignore_traffic_options : - | ignore_traffic_options ignore_traffic_option; - -ignore_traffic_option : T_IPV4_ADDR T_IP -{ - union inet_address ip; - int family = 0; - - memset(&ip, 0, sizeof(union inet_address)); - - if (inet_aton($2, &ip.ipv4)) - family = AF_INET; -#ifdef HAVE_INET_PTON_IPV6 - else if (inet_pton(AF_INET6, $2, &ip.ipv6) > 0) - family = AF_INET6; -#endif - - if (!family) { - fprintf(stdout, "%s is not a valid IP, ignoring", $2); - return; - } - - if (!STATE(ignore_pool)) { - STATE(ignore_pool) = ignore_pool_create(family); - if (!STATE(ignore_pool)) { - fprintf(stdout, "Can't create ignore pool!\n"); - exit(EXIT_FAILURE); - } - } - - if (!ignore_pool_add(STATE(ignore_pool), &ip)) { - if (errno == EEXIST) - fprintf(stdout, "IP %s is repeated " - "in the ignore pool\n", $2); - if (errno == ENOSPC) - fprintf(stdout, "Too many IP in the ignore pool!\n"); - } -}; - -multicast_line : T_MULTICAST '{' multicast_options '}'; - -multicast_options : - | multicast_options multicast_option; - -multicast_option : T_IPV4_ADDR T_IP -{ - if (!inet_aton($2, &conf.mcast.in)) { - fprintf(stderr, "%s is not a valid IPv4 address\n"); - return; - } - - if (conf.mcast.ipproto == AF_INET6) { - fprintf(stderr, "Your multicast address is IPv4 but " - "is binded to an IPv6 interface? Surely " - "this is not what you want\n"); - return; - } - - conf.mcast.ipproto = AF_INET; -}; - -multicast_option : T_IPV6_ADDR T_IP -{ -#ifdef HAVE_INET_PTON_IPV6 - if (inet_pton(AF_INET6, $2, &conf.mcast.in) <= 0) - fprintf(stderr, "%s is not a valid IPv6 address\n", $2); -#endif - - if (conf.mcast.ipproto == AF_INET) { - fprintf(stderr, "Your multicast address is IPv6 but " - "is binded to an IPv4 interface? Surely " - "this is not what you want\n"); - return; - } - - conf.mcast.ipproto = AF_INET6; -}; - -multicast_option : T_IPV4_IFACE T_IP -{ - if (!inet_aton($2, &conf.mcast.ifa)) { - fprintf(stderr, "%s is not a valid IPv4 address\n"); - return; - } - - if (conf.mcast.ipproto == AF_INET6) { - fprintf(stderr, "Your multicast interface is IPv4 but " - "is binded to an IPv6 interface? Surely " - "this is not what you want\n"); - return; - } - - conf.mcast.ipproto = AF_INET; -}; - -multicast_option : T_IPV6_IFACE T_IP -{ -#ifdef HAVE_INET_PTON_IPV6 - if (inet_pton(AF_INET6, $2, &conf.mcast.ifa) <= 0) - fprintf(stderr, "%s is not a valid IPv6 address\n", $2); -#endif - - if (conf.mcast.ipproto == AF_INET) { - fprintf(stderr, "Your multicast interface is IPv6 but " - "is binded to an IPv4 interface? Surely " - "this is not what you want\n"); - return; - } - - conf.mcast.ipproto = AF_INET6; -}; - -multicast_option : T_BACKLOG T_NUMBER -{ - conf.mcast.backlog = $2; -}; - -multicast_option : T_GROUP T_NUMBER -{ - conf.mcast.port = $2; -}; - -hashsize : T_HASHSIZE T_NUMBER -{ - conf.hashsize = $2; -}; - -hashlimit: T_HASHLIMIT T_NUMBER -{ - conf.limit = $2; -}; - -unix_line: T_UNIX '{' unix_options '}'; - -unix_options: - | unix_options unix_option - ; - -unix_option : T_PATH T_PATH_VAL -{ - strcpy(conf.local.path, $2); -}; - -unix_option : T_BACKLOG T_NUMBER -{ - conf.local.backlog = $2; -}; - -ignore_protocol: T_IGNORE_PROTOCOL '{' ignore_proto_list '}'; - -ignore_proto_list: - | ignore_proto_list ignore_proto - ; - -ignore_proto: T_NUMBER -{ - if ($1 < IPPROTO_MAX) - conf.ignore_protocol[$1] = 1; - else - fprintf(stdout, "Protocol number `%d' is freak\n", $1); -}; - -ignore_proto: T_UDP -{ - conf.ignore_protocol[IPPROTO_UDP] = 1; -}; - -ignore_proto: T_ICMP -{ - conf.ignore_protocol[IPPROTO_ICMP] = 1; -}; - -ignore_proto: T_VRRP -{ - conf.ignore_protocol[IPPROTO_VRRP] = 1; -}; - -ignore_proto: T_IGMP -{ - conf.ignore_protocol[IPPROTO_IGMP] = 1; -}; - -sync: T_SYNC '{' sync_list '}'; - -sync_list: - | sync_list sync_line; - -sync_line: refreshtime - | expiretime - | timeout - | checksum - | multicast_line - | relax_transitions - | delay_destroy_msgs - | sync_mode_persistent - | sync_mode_nack - | listen_to - | state_replication - ; - -sync_mode_persistent: T_SYNC_MODE T_PERSISTENT '{' sync_mode_persistent_list '}' -{ - conf.flags |= SYNC_MODE_PERSISTENT; -}; - -sync_mode_nack: T_SYNC_MODE T_NACK '{' sync_mode_nack_list '}' -{ - conf.flags |= SYNC_MODE_NACK; -}; - -sync_mode_persistent_list: - | sync_mode_persistent_list sync_mode_persistent_line; - -sync_mode_persistent_line: refreshtime - | expiretime - | timeout - | relax_transitions - | delay_destroy_msgs - ; - -sync_mode_nack_list: - | sync_mode_nack_list sync_mode_nack_line; - -sync_mode_nack_line: resend_buffer_size - | timeout - | window_size - ; - -resend_buffer_size: T_RESEND_BUFFER_SIZE T_NUMBER -{ - conf.resend_buffer_size = $2; -}; - -window_size: T_WINDOWSIZE T_NUMBER -{ - conf.window_size = $2; -}; - -relax_transitions: T_RELAX_TRANSITIONS -{ - conf.flags |= RELAX_TRANSITIONS; -}; - -delay_destroy_msgs: T_DELAY -{ - conf.flags |= DELAY_DESTROY_MSG; -}; - -listen_to: T_LISTEN_TO T_IP -{ - union inet_address addr; - -#ifdef HAVE_INET_PTON_IPV6 - if (inet_pton(AF_INET6, $2, &addr.ipv6) <= 0) -#endif - if (inet_aton($2, &addr.ipv4) <= 0) { - fprintf(stderr, "%s is not a valid IP address\n", $2); - exit(EXIT_FAILURE); - } - - if (CONFIG(listen_to_len) == 0 || CONFIG(listen_to_len) % 16) { - CONFIG(listen_to) = realloc(CONFIG(listen_to), - sizeof(union inet_address) * - (CONFIG(listen_to_len) + 16)); - if (CONFIG(listen_to) == NULL) { - fprintf(stderr, "cannot init listen_to array\n"); - exit(EXIT_FAILURE); - } - - memset(CONFIG(listen_to) + - (CONFIG(listen_to_len) * sizeof(union inet_address)), - 0, sizeof(union inet_address) * 16); - - } -}; - -state_replication: T_REPLICATE states T_FOR state_proto; - -states: - | states state; - -state_proto: T_TCP; -state: tcp_state; - -tcp_state: T_SYN_SENT -{ - extern struct state_replication_helper tcp_state_helper; - state_helper_register(&tcp_state_helper, TCP_CONNTRACK_SYN_SENT); -}; -tcp_state: T_SYN_RECV -{ - extern struct state_replication_helper tcp_state_helper; - state_helper_register(&tcp_state_helper, TCP_CONNTRACK_SYN_RECV); -}; -tcp_state: T_ESTABLISHED -{ - extern struct state_replication_helper tcp_state_helper; - state_helper_register(&tcp_state_helper, TCP_CONNTRACK_ESTABLISHED); -}; -tcp_state: T_FIN_WAIT -{ - extern struct state_replication_helper tcp_state_helper; - state_helper_register(&tcp_state_helper, TCP_CONNTRACK_FIN_WAIT); -}; -tcp_state: T_CLOSE_WAIT -{ - extern struct state_replication_helper tcp_state_helper; - state_helper_register(&tcp_state_helper, TCP_CONNTRACK_CLOSE_WAIT); -}; -tcp_state: T_LAST_ACK -{ - extern struct state_replication_helper tcp_state_helper; - state_helper_register(&tcp_state_helper, TCP_CONNTRACK_LAST_ACK); -}; -tcp_state: T_TIME_WAIT -{ - extern struct state_replication_helper tcp_state_helper; - state_helper_register(&tcp_state_helper, TCP_CONNTRACK_TIME_WAIT); -}; -tcp_state: T_CLOSE -{ - extern struct state_replication_helper tcp_state_helper; - state_helper_register(&tcp_state_helper, TCP_CONNTRACK_CLOSE); -}; -tcp_state: T_LISTEN -{ - extern struct state_replication_helper tcp_state_helper; - state_helper_register(&tcp_state_helper, TCP_CONNTRACK_LISTEN); -}; - -general: T_GENERAL '{' general_list '}'; - -general_list: - | general_list general_line - ; - -general_line: hashsize - | hashlimit - | log - | lock - | unix_line - | netlink_buffer_size - | netlink_buffer_size_max_grown - | family - ; - -netlink_buffer_size: T_BUFFER_SIZE T_NUMBER -{ - conf.netlink_buffer_size = $2; -}; - -netlink_buffer_size_max_grown : T_BUFFER_SIZE_MAX_GROWN T_NUMBER -{ - conf.netlink_buffer_size_max_grown = $2; -}; - -family : T_FAMILY T_STRING -{ - if (strncmp($2, "IPv6", strlen("IPv6")) == 0) - conf.family = AF_INET6; - else - conf.family = AF_INET; -}; - -stats: T_SYNC '{' stats_list '}'; - -stats_list: - | stats_list stat_line - ; - -stat_line: - | - ; - -%% - -int -yyerror(char *msg) -{ - printf("Error parsing config file: "); - printf("line (%d), symbol '%s': %s\n", yylineno, yytext, msg); - exit(EXIT_FAILURE); -} - -int -init_config(char *filename) -{ - FILE *fp; - - fp = fopen(filename, "r"); - if (!fp) - return -1; - - yyrestart(fp); - yyparse(); - fclose(fp); - - /* default to IPv4 */ - if (CONFIG(family) == 0) - CONFIG(family) = AF_INET; - - /* set to default is not specified */ - if (strcmp(CONFIG(lockfile), "") == 0) - strncpy(CONFIG(lockfile), DEFAULT_LOCKFILE, FILENAME_MAXLEN); - - /* default to 180 seconds of expiration time: cache entries */ - if (CONFIG(cache_timeout) == 0) - CONFIG(cache_timeout) = 180; - - /* default to 180 seconds: committed entries */ - if (CONFIG(commit_timeout) == 0) - CONFIG(commit_timeout) = 180; - - /* default to 60 seconds of refresh time */ - if (CONFIG(refresh) == 0) - CONFIG(refresh) = 60; - - if (CONFIG(resend_buffer_size) == 0) - CONFIG(resend_buffer_size) = 262144; - - /* create empty pool */ - if (!STATE(ignore_pool)) { - STATE(ignore_pool) = ignore_pool_create(CONFIG(family)); - if (!STATE(ignore_pool)) { - fprintf(stdout, "Can't create ignore pool!\n"); - exit(EXIT_FAILURE); - } - } - - /* default to a window size of 20 packets */ - if (CONFIG(window_size) == 0) - CONFIG(window_size) = 20; - - return 0; -} diff --git a/daemon/src/run.c b/daemon/src/run.c deleted file mode 100644 index 67437d8..0000000 --- a/daemon/src/run.c +++ /dev/null @@ -1,227 +0,0 @@ -/* - * (C) 2006-2007 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Description: run and init functions - */ - -#include "conntrackd.h" -#include -#include -#include "us-conntrack.h" -#include -#include - -void killer(int foo) -{ - /* no signals while handling signals */ - sigprocmask(SIG_BLOCK, &STATE(block), NULL); - - nfnl_subsys_close(STATE(subsys_event)); - nfnl_subsys_close(STATE(subsys_dump)); - nfnl_subsys_close(STATE(subsys_sync)); - nfnl_close(STATE(event)); - nfnl_close(STATE(dump)); - nfnl_close(STATE(sync)); - - ignore_pool_destroy(STATE(ignore_pool)); - local_server_destroy(STATE(local)); - STATE(mode)->kill(); - unlink(CONFIG(lockfile)); - dlog(STATE(log), "------- shutdown received ----"); - close_log(STATE(log)); - - sigprocmask(SIG_UNBLOCK, &STATE(block), NULL); - - exit(0); -} - -void local_handler(int fd, void *data) -{ - int ret; - int type; - - ret = read(fd, &type, sizeof(type)); - if (ret == -1) { - dlog(STATE(log), "can't read from unix socket\n"); - return; - } - if (ret == 0) { - debug("nothing to process\n"); - return; - } - - switch(type) { - case FLUSH_MASTER: - dlog(STATE(log), "[REQ] flushing master table"); - nl_flush_master_conntrack_table(); - return; - case RESYNC_MASTER: - dlog(STATE(log), "[REQ] resync with master table"); - nl_dump_conntrack_table(STATE(dump), STATE(subsys_dump)); - return; - } - - if (!STATE(mode)->local(fd, type, data)) - dlog(STATE(log), "[FAIL] unknown local request %d", type); -} - -int init(int mode) -{ - switch(mode) { - case STATS_MODE: - STATE(mode) = &stats_mode; - break; - case SYNC_MODE: - STATE(mode) = &sync_mode; - break; - default: - fprintf(stderr, "Unknown running mode! default " - "to synchronization mode\n"); - STATE(mode) = &sync_mode; - break; - } - - /* Initialization */ - if (STATE(mode)->init() == -1) { - dlog(STATE(log), "[FAIL] initialization failed"); - return -1; - } - - /* local UNIX socket */ - STATE(local) = local_server_create(&CONFIG(local)); - if (!STATE(local)) { - dlog(STATE(log), "[FAIL] can't open unix socket!"); - return -1; - } - - if (nl_init_event_handler() == -1) { - dlog(STATE(log), "[FAIL] can't open netlink handler! " - "no ctnetlink kernel support?"); - return -1; - } - - if (nl_init_dump_handler() == -1) { - dlog(STATE(log), "[FAIL] can't open netlink handler! " - "no ctnetlink kernel support?"); - return -1; - } - - if (nl_init_overrun_handler() == -1) { - dlog(STATE(log), "[FAIL] can't open netlink handler! " - "no ctnetlink kernel support?"); - return -1; - } - - /* Signals handling */ - sigemptyset(&STATE(block)); - sigaddset(&STATE(block), SIGTERM); - sigaddset(&STATE(block), SIGINT); - - if (signal(SIGINT, killer) == SIG_ERR) - return -1; - - if (signal(SIGTERM, killer) == SIG_ERR) - return -1; - - /* ignore connection reset by peer */ - if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) - return -1; - - dlog(STATE(log), "[OK] initialization completed"); - - return 0; -} - -#define POLL_NSECS 1 - -static void __run(void) -{ - int max, ret; - fd_set readfds; - struct timeval tv = { - .tv_sec = POLL_NSECS, - .tv_usec = 0 - }; - - FD_ZERO(&readfds); - FD_SET(STATE(local), &readfds); - FD_SET(nfnl_fd(STATE(event)), &readfds); - - max = MAX(STATE(local), nfnl_fd(STATE(event))); - - if (STATE(mode)->add_fds_to_set) - max = MAX(max, STATE(mode)->add_fds_to_set(&readfds)); - - ret = select(max+1, &readfds, NULL, NULL, &tv); - if (ret == -1) { - /* interrupted syscall, retry */ - if (errno == EINTR) - return; - - dlog(STATE(log), "select() failed: %s", strerror(errno)); - return; - } - - /* signals are racy */ - sigprocmask(SIG_BLOCK, &STATE(block), NULL); - - /* order received via UNIX socket */ - if (FD_ISSET(STATE(local), &readfds)) - do_local_server_step(STATE(local), NULL, local_handler); - - /* conntrack event has happened */ - if (FD_ISSET(nfnl_fd(STATE(event)), &readfds)) { - ret = nfnl_catch(STATE(event)); - if (ret == -1) { - switch(errno) { - case ENOBUFS: - /* - * It seems that ctnetlink can't back off, - * it's likely that we're losing events. - * Solution: duplicate the socket buffer - * size and resync with master conntrack table. - */ - nl_resize_socket_buffer(STATE(event)); - nl_dump_conntrack_table(STATE(sync), - STATE(subsys_sync)); - break; - case ENOENT: - /* - * We received a message from another - * netfilter subsystem that we are not - * interested in. Just ignore it. - */ - break; - default: - dlog(STATE(log), "event catch says: %s", - strerror(errno)); - break; - } - } - } - - if (STATE(mode)->step) - STATE(mode)->step(&readfds); - - sigprocmask(SIG_UNBLOCK, &STATE(block), NULL); -} - -void run(void) -{ - while(1) - __run(); -} diff --git a/daemon/src/state_helper.c b/daemon/src/state_helper.c deleted file mode 100644 index 81b0d09..0000000 --- a/daemon/src/state_helper.c +++ /dev/null @@ -1,44 +0,0 @@ -/* - * (C) 2006-2007 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "conntrackd.h" -#include "state_helper.h" - -static struct state_replication_helper *helper[IPPROTO_MAX]; - -int state_helper_verdict(int type, struct nf_conntrack *ct) -{ - u_int8_t l4proto; - - if (type == NFCT_T_DESTROY) - return ST_H_REPLICATE; - - l4proto = nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO); - if (helper[l4proto]) - return helper[l4proto]->verdict(helper[l4proto], ct); - - return ST_H_REPLICATE; -} - -void state_helper_register(struct state_replication_helper *h, int state) -{ - if (helper[h->proto] == NULL) - helper[h->proto] = h; - - helper[h->proto]->state |= (1 << state); -} diff --git a/daemon/src/state_helper_tcp.c b/daemon/src/state_helper_tcp.c deleted file mode 100644 index af714dc..0000000 --- a/daemon/src/state_helper_tcp.c +++ /dev/null @@ -1,35 +0,0 @@ -/* - * (C) 2006-2007 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "conntrackd.h" -#include "state_helper.h" - -static int tcp_verdict(const struct state_replication_helper *h, - const struct nf_conntrack *ct) -{ - u_int8_t state = nfct_get_attr_u8(ct, ATTR_TCP_STATE); - if (h->state & (1 << state)) - return ST_H_REPLICATE; - - return ST_H_SKIP; -} - -struct state_replication_helper tcp_state_helper = { - .proto = IPPROTO_TCP, - .verdict = tcp_verdict, -}; diff --git a/daemon/src/stats-mode.c b/daemon/src/stats-mode.c deleted file mode 100644 index 9647bbf..0000000 --- a/daemon/src/stats-mode.c +++ /dev/null @@ -1,151 +0,0 @@ -/* - * (C) 2006 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include "cache.h" -#include "conntrackd.h" -#include -#include -#include -#include "us-conntrack.h" -#include -#include - -static int init_stats(void) -{ - int ret; - - state.stats = malloc(sizeof(struct ct_stats_state)); - if (!state.stats) { - dlog(STATE(log), "[FAIL] can't allocate memory for stats sync"); - return -1; - } - memset(state.stats, 0, sizeof(struct ct_stats_state)); - - STATE_STATS(cache) = cache_create("stats", - LIFETIME, - CONFIG(family), - NULL); - if (!STATE_STATS(cache)) { - dlog(STATE(log), "[FAIL] can't allocate memory for the " - "external cache"); - return -1; - } - - return 0; -} - -static void kill_stats() -{ - cache_destroy(STATE_STATS(cache)); -} - -/* handler for requests coming via UNIX socket */ -static int local_handler_stats(int fd, int type, void *data) -{ - int ret = 1; - - switch(type) { - case DUMP_INTERNAL: - cache_dump(STATE_STATS(cache), fd, NFCT_O_PLAIN); - break; - case DUMP_INT_XML: - cache_dump(STATE_SYNC(internal), fd, NFCT_O_XML); - break; - case FLUSH_CACHE: - dlog(STATE(log), "[REQ] flushing caches"); - cache_flush(STATE_STATS(cache)); - break; - case KILL: - killer(); - break; - case STATS: - cache_stats(STATE_STATS(cache), fd); - dump_traffic_stats(fd); - break; - default: - ret = 0; - break; - } - - return ret; -} - -static void dump_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh) -{ - if (cache_update_force(STATE_STATS(cache), ct)) - debug_ct(ct, "resync entry"); -} - -static void event_new_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh) -{ - debug_ct(ct, "debug event"); - if (cache_add(STATE_STATS(cache), ct)) { - debug_ct(ct, "cache new"); - } else { - dlog(STATE(log), "can't add to cache cache: " - "%s\n", strerror(errno)); - debug_ct(ct, "can't add"); - } -} - -static void event_update_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh) -{ - debug_ct(ct, "update"); - - if (!cache_update(STATE_STATS(cache), ct)) { - /* - * Perhaps we are losing events. If we are working - * in relax mode then add a new entry to the cache. - * - * FIXME: relax transitions not implemented yet - */ - if ((CONFIG(flags) & RELAX_TRANSITIONS) - && cache_add(STATE_STATS(cache), ct)) { - debug_ct(ct, "forcing cache update"); - } else { - debug_ct(ct, "can't update"); - return; - } - } - debug_ct(ct, "update"); -} - -static int event_destroy_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh) -{ - if (cache_del(STATE_STATS(cache), ct)) { - debug_ct(ct, "cache destroy"); - return 1; - } else { - debug_ct(ct, "can't destroy!"); - return 0; - } -} - -struct ct_mode stats_mode = { - .init = init_stats, - .add_fds_to_set = NULL, - .step = NULL, - .local = local_handler_stats, - .kill = kill_stats, - .dump = dump_stats, - .overrun = dump_stats, - .event_new = event_new_stats, - .event_upd = event_update_stats, - .event_dst = event_destroy_stats -}; diff --git a/daemon/src/sync-mode.c b/daemon/src/sync-mode.c deleted file mode 100644 index b32bef7..0000000 --- a/daemon/src/sync-mode.c +++ /dev/null @@ -1,416 +0,0 @@ -/* - * (C) 2006 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include "cache.h" -#include "conntrackd.h" -#include -#include -#include -#include "us-conntrack.h" -#include -#include -#include "sync.h" -#include "network.h" - -/* handler for multicast messages received */ -static void mcast_handler() -{ - int ret; - char buf[4096], tmp[256]; - struct mcast_sock *m = STATE_SYNC(mcast_server); - unsigned int type; - struct nlnetwork *net = (struct nlnetwork *) buf; - unsigned int size = sizeof(struct nlnetwork); - struct nlmsghdr *nlh = (struct nlmsghdr *) (buf + size); - struct nf_conntrack *ct = (struct nf_conntrack *) tmp; - struct us_conntrack *u = NULL; - - memset(tmp, 0, sizeof(tmp)); - - ret = mcast_recv_netmsg(m, buf, sizeof(buf)); - if (ret <= 0) { - STATE(malformed)++; - return; - } - - if (STATE_SYNC(mcast_sync)->pre_recv(net)) - return; - - if ((type = parse_network_msg(ct, nlh)) == NFCT_T_ERROR) { - STATE(malformed)++; - return; - } - - nfct_attr_unset(ct, ATTR_TIMEOUT); - nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES); - nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS); - nfct_attr_unset(ct, ATTR_REPL_COUNTER_BYTES); - nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); - - switch(type) { - case NFCT_T_NEW: -retry: - if ((u = cache_add(STATE_SYNC(external), ct))) { - debug_ct(u->ct, "external new"); - } else { - /* - * One certain connection A arrives to the cache but - * another existing connection B in the cache has - * the same configuration, therefore B clashes with A. - */ - if (errno == EEXIST) { - cache_del(STATE_SYNC(external), ct); - goto retry; - } - debug_ct(ct, "can't add"); - } - break; - case NFCT_T_UPDATE: - if ((u = cache_update_force(STATE_SYNC(external), ct))) { - debug_ct(u->ct, "external update"); - } else - debug_ct(ct, "can't update"); - break; - case NFCT_T_DESTROY: - if (cache_del(STATE_SYNC(external), ct)) - debug_ct(ct, "external destroy"); - else - debug_ct(ct, "can't destroy"); - break; - default: - debug("unknown type %d\n", type); - break; - } -} - -static int init_sync(void) -{ - int ret; - - state.sync = malloc(sizeof(struct ct_sync_state)); - if (!state.sync) { - dlog(STATE(log), "[FAIL] can't allocate memory for state sync"); - return -1; - } - memset(state.sync, 0, sizeof(struct ct_sync_state)); - - if (CONFIG(flags) & SYNC_MODE_NACK) - STATE_SYNC(mcast_sync) = &nack; - else - /* default to persistent mode */ - STATE_SYNC(mcast_sync) = ¬rack; - - if (STATE_SYNC(mcast_sync)->init) - STATE_SYNC(mcast_sync)->init(); - - STATE_SYNC(internal) = - cache_create("internal", - STATE_SYNC(mcast_sync)->internal_cache_flags, - CONFIG(family), - STATE_SYNC(mcast_sync)->internal_cache_extra); - - if (!STATE_SYNC(internal)) { - dlog(STATE(log), "[FAIL] can't allocate memory for " - "the internal cache"); - return -1; - } - - STATE_SYNC(external) = - cache_create("external", - STATE_SYNC(mcast_sync)->external_cache_flags, - CONFIG(family), - NULL); - - if (!STATE_SYNC(external)) { - dlog(STATE(log), "[FAIL] can't allocate memory for the " - "external cache"); - return -1; - } - - /* multicast server to receive events from the wire */ - STATE_SYNC(mcast_server) = mcast_server_create(&CONFIG(mcast)); - if (STATE_SYNC(mcast_server) == NULL) { - dlog(STATE(log), "[FAIL] can't open multicast server!"); - return -1; - } - - /* multicast client to send events on the wire */ - STATE_SYNC(mcast_client) = mcast_client_create(&CONFIG(mcast)); - if (STATE_SYNC(mcast_client) == NULL) { - dlog(STATE(log), "[FAIL] can't open client multicast socket!"); - return -1; - } - - /* initialization of multicast sequence generation */ - STATE_SYNC(last_seq_sent) = time(NULL); - - if (create_alarm_thread() == -1) { - dlog(STATE(log), "[FAIL] can't initialize alarm thread"); - return -1; - } - - return 0; -} - -static int add_fds_to_set_sync(fd_set *readfds) -{ - FD_SET(STATE_SYNC(mcast_server->fd), readfds); - - return STATE_SYNC(mcast_server->fd); -} - -static void step_sync(fd_set *readfds) -{ - /* multicast packet has been received */ - if (FD_ISSET(STATE_SYNC(mcast_server->fd), readfds)) - mcast_handler(); -} - -static void kill_sync() -{ - cache_destroy(STATE_SYNC(internal)); - cache_destroy(STATE_SYNC(external)); - - mcast_server_destroy(STATE_SYNC(mcast_server)); - mcast_client_destroy(STATE_SYNC(mcast_client)); - - destroy_alarm_thread(); - - if (STATE_SYNC(mcast_sync)->kill) - STATE_SYNC(mcast_sync)->kill(); -} - -static dump_stats_sync(int fd) -{ - char buf[512]; - int size; - - size = sprintf(buf, "multicast sequence tracking:\n" - "%20llu Pckts mfrm " - "%20llu Pckts lost\n\n", - STATE(malformed), - STATE_SYNC(packets_lost)); - - send(fd, buf, size, 0); -} - -/* handler for requests coming via UNIX socket */ -static int local_handler_sync(int fd, int type, void *data) -{ - int ret = 1; - - switch(type) { - case DUMP_INTERNAL: - cache_dump(STATE_SYNC(internal), fd, NFCT_O_PLAIN); - break; - case DUMP_EXTERNAL: - cache_dump(STATE_SYNC(external), fd, NFCT_O_PLAIN); - break; - case DUMP_INT_XML: - cache_dump(STATE_SYNC(internal), fd, NFCT_O_XML); - break; - case DUMP_EXT_XML: - cache_dump(STATE_SYNC(external), fd, NFCT_O_XML); - break; - case COMMIT: - dlog(STATE(log), "[REQ] commit external cache to master table"); - cache_commit(STATE_SYNC(external)); - break; - case FLUSH_CACHE: - dlog(STATE(log), "[REQ] flushing caches"); - cache_flush(STATE_SYNC(internal)); - cache_flush(STATE_SYNC(external)); - break; - case KILL: - killer(); - break; - case STATS: - cache_stats(STATE_SYNC(internal), fd); - cache_stats(STATE_SYNC(external), fd); - dump_traffic_stats(fd); - mcast_dump_stats(fd, STATE_SYNC(mcast_client), - STATE_SYNC(mcast_server)); - dump_stats_sync(fd); - break; - case SEND_BULK: - dlog(STATE(log), "[REQ] sending bulk update"); - cache_bulk(STATE_SYNC(internal)); - break; - default: - if (STATE_SYNC(mcast_sync)->local) - ret = STATE_SYNC(mcast_sync)->local(fd, type, data); - break; - } - - return ret; -} - -static void dump_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) -{ - /* This is required by kernels < 2.6.20 */ - nfct_attr_unset(ct, ATTR_TIMEOUT); - nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES); - nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS); - nfct_attr_unset(ct, ATTR_REPL_COUNTER_BYTES); - nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); - nfct_attr_unset(ct, ATTR_USE); - - if (cache_update_force(STATE_SYNC(internal), ct)) - debug_ct(ct, "resync"); -} - -static void mcast_send_sync(struct nlmsghdr *nlh, - struct us_conntrack *u, - struct nf_conntrack *ct, - int type) -{ - char buf[4096]; - struct nlnetwork *net = (struct nlnetwork *) buf; - int mangled = 0; - - memset(buf, 0, sizeof(buf)); - - if (!state_helper_verdict(type, ct)) - return; - - if (!mangled) - memcpy(buf + sizeof(struct nlnetwork), nlh, nlh->nlmsg_len); - - mcast_send_netmsg(STATE_SYNC(mcast_client), net); - STATE_SYNC(mcast_sync)->post_send(net, u); -} - -static void overrun_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) -{ - struct us_conntrack *u; - - /* This is required by kernels < 2.6.20 */ - nfct_attr_unset(ct, ATTR_TIMEOUT); - nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES); - nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS); - nfct_attr_unset(ct, ATTR_REPL_COUNTER_BYTES); - nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); - nfct_attr_unset(ct, ATTR_USE); - - if (!cache_test(STATE_SYNC(internal), ct)) { - if ((u = cache_update_force(STATE_SYNC(internal), ct))) { - debug_ct(ct, "overrun resync"); - mcast_send_sync(nlh, u, ct, NFCT_T_UPDATE); - } - } -} - -static void event_new_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) -{ - struct us_conntrack *u; - - /* required by linux kernel <= 2.6.20 */ - nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES); - nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS); - nfct_attr_unset(ct, ATTR_REPL_COUNTER_BYTES); - nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); - nfct_attr_unset(ct, ATTR_TIMEOUT); -retry: - if ((u = cache_add(STATE_SYNC(internal), ct))) { - mcast_send_sync(nlh, u, ct, NFCT_T_NEW); - debug_ct(u->ct, "internal new"); - } else { - if (errno == EEXIST) { - char buf[4096]; - struct nlmsghdr *nlh = (struct nlmsghdr *) buf; - - int ret = build_network_msg(NFCT_Q_DESTROY, - STATE(subsys_event), - ct, - buf, - sizeof(buf)); - if (ret == -1) - return; - - cache_del(STATE_SYNC(internal), ct); - mcast_send_sync(nlh, NULL, ct, NFCT_T_NEW); - goto retry; - } - dlog(STATE(log), "can't add to internal cache: " - "%s\n", strerror(errno)); - debug_ct(ct, "can't add"); - } -} - -static void event_update_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) -{ - struct us_conntrack *u; - - nfct_attr_unset(ct, ATTR_TIMEOUT); - - if ((u = cache_update(STATE_SYNC(internal), ct)) == NULL) { - /* - * Perhaps we are losing events. If we are working - * in relax mode then add a new entry to the cache. - * - * FIXME: relax transitions not implemented yet - */ - if ((CONFIG(flags) & RELAX_TRANSITIONS) - && (u = cache_add(STATE_SYNC(internal), ct))) { - debug_ct(u->ct, "forcing internal update"); - } else { - debug_ct(ct, "can't update"); - return; - } - } - debug_ct(u->ct, "internal update"); - mcast_send_sync(nlh, u, ct, NFCT_T_UPDATE); -} - -static int event_destroy_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) -{ - nfct_attr_unset(ct, ATTR_TIMEOUT); - - if (CONFIG(flags) & DELAY_DESTROY_MSG) { - - nfct_set_attr_u32(ct, ATTR_STATUS, IPS_DYING); - - if (cache_update(STATE_SYNC(internal), ct)) { - debug_ct(ct, "delay internal destroy"); - return 1; - } else { - debug_ct(ct, "can't delay destroy!"); - return 0; - } - } else { - if (cache_del(STATE_SYNC(internal), ct)) { - mcast_send_sync(nlh, NULL, ct, NFCT_T_DESTROY); - debug_ct(ct, "internal destroy"); - } else - debug_ct(ct, "can't destroy"); - } -} - -struct ct_mode sync_mode = { - .init = init_sync, - .add_fds_to_set = add_fds_to_set_sync, - .step = step_sync, - .local = local_handler_sync, - .kill = kill_sync, - .dump = dump_sync, - .overrun = overrun_sync, - .event_new = event_new_sync, - .event_upd = event_update_sync, - .event_dst = event_destroy_sync -}; diff --git a/daemon/src/sync-nack.c b/daemon/src/sync-nack.c deleted file mode 100644 index 288dba4..0000000 --- a/daemon/src/sync-nack.c +++ /dev/null @@ -1,309 +0,0 @@ -/* - * (C) 2006-2007 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include "conntrackd.h" -#include "sync.h" -#include "linux_list.h" -#include "us-conntrack.h" -#include "buffer.h" -#include "debug.h" -#include "network.h" -#include -#include - -#if 0 -#define dp printf -#else -#define dp -#endif - -static LIST_HEAD(queue); - -struct cache_nack { - struct list_head head; - u_int32_t seq; -}; - -static void cache_nack_add(struct us_conntrack *u, void *data) -{ - struct cache_nack *cn = data; - - INIT_LIST_HEAD(&cn->head); - list_add(&cn->head, &queue); -} - -static void cache_nack_update(struct us_conntrack *u, void *data) -{ - struct cache_nack *cn = data; - - if (cn->head.next != LIST_POISON1 && - cn->head.prev != LIST_POISON2) - list_del(&cn->head); - - INIT_LIST_HEAD(&cn->head); - list_add(&cn->head, &queue); -} - -static void cache_nack_destroy(struct us_conntrack *u, void *data) -{ - struct cache_nack *cn = data; - - if (cn->head.next != LIST_POISON1 && - cn->head.prev != LIST_POISON2) - list_del(&cn->head); -} - -static struct cache_extra cache_nack_extra = { - .size = sizeof(struct cache_nack), - .add = cache_nack_add, - .update = cache_nack_update, - .destroy = cache_nack_destroy -}; - -static int nack_init() -{ - STATE_SYNC(buffer) = buffer_create(CONFIG(resend_buffer_size)); - if (STATE_SYNC(buffer) == NULL) - return -1; - - return 0; -} - -static void nack_kill() -{ - buffer_destroy(STATE_SYNC(buffer)); -} - -static void mcast_send_nack(u_int32_t expt_seq, u_int32_t recv_seq) -{ - struct nlnetwork_ack nack = { - .flags = NET_NACK, - .from = expt_seq, - .to = recv_seq, - }; - - mcast_send_error(STATE_SYNC(mcast_client), &nack); - buffer_add(STATE_SYNC(buffer), &nack, sizeof(struct nlnetwork_ack)); -} - -static void mcast_send_ack(u_int32_t from, u_int32_t to) -{ - struct nlnetwork_ack ack = { - .flags = NET_ACK, - .from = from, - .to = to, - }; - - mcast_send_error(STATE_SYNC(mcast_client), &ack); - buffer_add(STATE_SYNC(buffer), &ack, sizeof(struct nlnetwork_ack)); -} - -static void mcast_send_resync() -{ - struct nlnetwork net = { - .flags = NET_RESYNC, - }; - - mcast_send_error(STATE_SYNC(mcast_client), &net); - buffer_add(STATE_SYNC(buffer), &net, sizeof(struct nlnetwork)); -} - -int nack_local(int fd, int type, void *data) -{ - int ret = 1; - - switch(type) { - case REQUEST_DUMP: - mcast_send_resync(); - dlog(STATE(log), "[REQ] request resync"); - break; - default: - ret = 0; - break; - } - - return ret; -} - -static int buffer_compare(void *data1, void *data2) -{ - struct nlnetwork *net = data1; - struct nlnetwork_ack *nack = data2; - struct nlmsghdr *nlh = data1 + sizeof(struct nlnetwork); - - unsigned old_seq = ntohl(net->seq); - - if (ntohl(net->seq) >= nack->from && ntohl(net->seq) <= nack->to) { - if (mcast_resend_netmsg(STATE_SYNC(mcast_client), net)) - dp("resend destroy (old seq=%u) (seq=%u)\n", - old_seq, ntohl(net->seq)); - } - return 0; -} - -static int buffer_remove(void *data1, void *data2) -{ - struct nlnetwork *net = data1; - struct nlnetwork_ack *h = data2; - - if (ntohl(net->seq) >= h->from && ntohl(net->seq) <= h->to) { - dp("remove from buffer (seq=%u)\n", ntohl(net->seq)); - __buffer_del(STATE_SYNC(buffer), data1); - } - return 0; -} - -static void queue_resend(struct cache *c, unsigned int from, unsigned int to) -{ - struct list_head *n; - struct us_conntrack *u; - unsigned int *seq; - - lock(); - list_for_each(n, &queue) { - struct cache_nack *cn = (struct cache_nack *) n; - struct us_conntrack *u; - - u = cache_get_conntrack(STATE_SYNC(internal), cn); - - if (cn->seq >= from && cn->seq <= to) { - debug_ct(u->ct, "resend nack"); - dp("resending nack'ed (oldseq=%u) ", cn->seq); - - char buf[4096]; - struct nlnetwork *net = (struct nlnetwork *) buf; - - int ret = build_network_msg(NFCT_Q_UPDATE, - STATE(subsys_event), - u->ct, - buf, - sizeof(buf)); - if (ret == -1) { - unlock(); - break; - } - - mcast_send_netmsg(STATE_SYNC(mcast_client), buf); - STATE_SYNC(mcast_sync)->post_send(net, u); - dp("(newseq=%u)\n", *seq); - } - } - unlock(); -} - -static void queue_empty(struct cache *c, unsigned int from, unsigned int to) -{ - struct list_head *n, *tmp; - struct us_conntrack *u; - unsigned int *seq; - - lock(); - dp("ACK from %u to %u\n", from, to); - list_for_each_safe(n, tmp, &queue) { - struct cache_nack *cn = (struct cache_nack *) n; - - u = cache_get_conntrack(STATE_SYNC(internal), cn); - if (cn->seq >= from && cn->seq <= to) { - dp("remove %u\n", cn->seq); - debug_ct(u->ct, "ack received: empty queue"); - dp("queue: deleting from queue (seq=%u)\n", cn->seq); - list_del(&cn->head); - } - } - unlock(); -} - -static int nack_pre_recv(const struct nlnetwork *net) -{ - static unsigned int window = 0; - unsigned int exp_seq; - - if (window == 0) - window = CONFIG(window_size); - - if (!mcast_track_seq(net->seq, &exp_seq)) { - dp("OOS: sending nack (seq=%u)\n", exp_seq); - mcast_send_nack(exp_seq, net->seq - 1); - window = CONFIG(window_size); - } else { - /* received a window, send an acknowledgement */ - if (--window == 0) { - dp("sending ack (seq=%u)\n", net->seq); - mcast_send_ack(net->seq-CONFIG(window_size), net->seq); - } - } - - if (net->flags & NET_NACK) { - struct nlnetwork_ack *nack = (struct nlnetwork_ack *) net; - - dp("NACK: from seq=%u to seq=%u\n", nack->from, nack->to); - queue_resend(STATE_SYNC(internal), nack->from, nack->to); - buffer_iterate(STATE_SYNC(buffer), nack, buffer_compare); - return 1; - } else if (net->flags & NET_RESYNC) { - dp("RESYNC ALL\n"); - cache_bulk(STATE_SYNC(internal)); - return 1; - } else if (net->flags & NET_ACK) { - struct nlnetwork_ack *h = (struct nlnetwork_ack *) net; - - dp("ACK: from seq=%u to seq=%u\n", h->from, h->to); - queue_empty(STATE_SYNC(internal), h->from, h->to); - buffer_iterate(STATE_SYNC(buffer), h, buffer_remove); - return 1; - } - - return 0; -} - -static void nack_post_send(const struct nlnetwork *net, struct us_conntrack *u) -{ - unsigned int size = sizeof(struct nlnetwork); - struct nlmsghdr *nlh = (struct nlmsghdr *) ((void *) net + size); - - if (NFNL_MSG_TYPE(ntohs(nlh->nlmsg_type)) == IPCTNL_MSG_CT_DELETE) { - buffer_add(STATE_SYNC(buffer), net, - ntohl(nlh->nlmsg_len) + size); - } else if (u != NULL) { - unsigned int *seq; - struct list_head *n; - struct cache_nack *cn; - - cn = (struct cache_nack *) - cache_get_extra(STATE_SYNC(internal), u); - cn->seq = ntohl(net->seq); - if (cn->head.next != LIST_POISON1 && - cn->head.prev != LIST_POISON2) - list_del(&cn->head); - - INIT_LIST_HEAD(&cn->head); - list_add(&cn->head, &queue); - } -} - -struct sync_mode nack = { - .internal_cache_flags = LIFETIME, - .external_cache_flags = LIFETIME, - .internal_cache_extra = &cache_nack_extra, - .init = nack_init, - .kill = nack_kill, - .local = nack_local, - .pre_recv = nack_pre_recv, - .post_send = nack_post_send, -}; diff --git a/daemon/src/sync-notrack.c b/daemon/src/sync-notrack.c deleted file mode 100644 index 2b5ae38..0000000 --- a/daemon/src/sync-notrack.c +++ /dev/null @@ -1,127 +0,0 @@ -/* - * (C) 2006-2007 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "conntrackd.h" -#include "sync.h" -#include "network.h" -#include "us-conntrack.h" -#include "alarm.h" - -static void refresher(struct alarm_list *a, void *data) -{ - struct us_conntrack *u = data; - char buf[8192]; - int size; - - if (nfct_get_attr_u32(u->ct, ATTR_STATUS) & IPS_DYING) { - - debug_ct(u->ct, "persistence destroy"); - - size = build_network_msg(NFCT_Q_DESTROY, - STATE(subsys_event), - u->ct, - buf, - sizeof(buf)); - - __cache_del(u->cache, u->ct); - mcast_send_netmsg(STATE_SYNC(mcast_client), buf); - } else { - - debug_ct(u->ct, "persistence update"); - - a->expires = random() % CONFIG(refresh) + 1; - size = build_network_msg(NFCT_Q_UPDATE, - STATE(subsys_event), - u->ct, - buf, - sizeof(buf)); - mcast_send_netmsg(STATE_SYNC(mcast_client), buf); - } -} - -static void cache_notrack_add(struct us_conntrack *u, void *data) -{ - struct alarm_list *alarm = data; - - init_alarm(alarm); - set_alarm_expiration(alarm, (random() % conf.refresh) + 1); - set_alarm_data(alarm, u); - set_alarm_function(alarm, refresher); - add_alarm(alarm); -} - -static void cache_notrack_update(struct us_conntrack *u, void *data) -{ - struct alarm_list *alarm = data; - mod_alarm(alarm, (random() % conf.refresh) + 1); -} - -static void cache_notrack_destroy(struct us_conntrack *u, void *data) -{ - struct alarm_list *alarm = data; - del_alarm(alarm); -} - -static struct cache_extra cache_notrack_extra = { - .size = sizeof(struct alarm_list), - .add = cache_notrack_add, - .update = cache_notrack_update, - .destroy = cache_notrack_destroy -}; - -static int notrack_pre_recv(const struct nlnetwork *net) -{ - unsigned int exp_seq; - - /* - * Ignore error messages: Although this message type is not ever - * generated in notrack mode, we don't want to crash the daemon - * if someone nuts mixes nack and notrack. - */ - if (net->flags & (NET_RESYNC | NET_NACK)) - return 1; - - /* - * Multicast sequence tracking: we keep track of multicast messages - * although we don't do any explicit message recovery. So, why do - * we do sequence tracking? Just to let know the sysadmin. - * - * Let t be 1 < t < RefreshTime. To ensure consistency, conntrackd - * retransmit every t seconds a message with the state of a certain - * entry even if such entry did not change. This mechanism also - * provides passive resynchronization, in other words, there is - * no facility to request a full synchronization from new nodes that - * just joined the cluster, instead they just get resynchronized in - * RefreshTime seconds at worst case. - */ - mcast_track_seq(net->seq, &exp_seq); - - return 0; -} - -static void notrack_post_send(const struct nlnetwork *n, struct us_conntrack *u) -{ -} - -struct sync_mode notrack = { - .internal_cache_flags = LIFETIME, - .external_cache_flags = TIMER | LIFETIME, - .internal_cache_extra = &cache_notrack_extra, - .pre_recv = notrack_pre_recv, - .post_send = notrack_post_send, -}; diff --git a/daemon/src/traffic_stats.c b/daemon/src/traffic_stats.c deleted file mode 100644 index b510b77..0000000 --- a/daemon/src/traffic_stats.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - * (C) 2006 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "cache.h" -#include "hash.h" -#include "conntrackd.h" -#include -#include -#include -#include "us-conntrack.h" -#include - -void update_traffic_stats(struct nf_conntrack *ct) -{ - STATE(bytes)[NFCT_DIR_ORIGINAL] += - nfct_get_attr_u32(ct, ATTR_ORIG_COUNTER_BYTES); - STATE(bytes)[NFCT_DIR_REPLY] += - nfct_get_attr_u32(ct, ATTR_REPL_COUNTER_BYTES); - STATE(packets)[NFCT_DIR_ORIGINAL] += - nfct_get_attr_u32(ct, ATTR_ORIG_COUNTER_PACKETS); - STATE(packets)[NFCT_DIR_REPLY] += - nfct_get_attr_u32(ct, ATTR_REPL_COUNTER_PACKETS); -} - -void dump_traffic_stats(int fd) -{ - char buf[512]; - int size; - u_int64_t bytes = STATE(bytes)[NFCT_DIR_ORIGINAL] + - STATE(bytes)[NFCT_DIR_REPLY]; - u_int64_t packets = STATE(packets)[NFCT_DIR_ORIGINAL] + - STATE(packets)[NFCT_DIR_REPLY]; - - size = sprintf(buf, "traffic processed:\n"); - size += sprintf(buf+size, "%20llu Bytes ", bytes); - size += sprintf(buf+size, "%20llu Pckts\n\n", packets); - - send(fd, buf, size, 0); -} diff --git a/examples/Makefile.am b/examples/Makefile.am new file mode 100644 index 0000000..be83d42 --- /dev/null +++ b/examples/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = stats sync diff --git a/examples/debian.conntrackd.init.d b/examples/debian.conntrackd.init.d new file mode 100644 index 0000000..ba847dd --- /dev/null +++ b/examples/debian.conntrackd.init.d @@ -0,0 +1,48 @@ +#!/bin/sh +# +# /etc/init.d/conntrackd +# +# Maximilian Wilhelm +# -- Mon, 06 Nov 2006 18:39:07 +0100 +# + +export PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin + +NAME="conntrackd" +DAEMON=`command -v conntrackd` +CONFIG="/etc/conntrack/conntrackd.conf" +PIDFILE="/var/run/${NAME}.pid" + + +# Gracefully exit if there is no daemon (debian way of life) +if [ ! -x "${DAEMON}" ]; then + exit 0 +fi + +# Check for config file +if [ ! -f /etc/conntrackd/conntrackd.conf ]; then + echo "Error: There is no config file for $NAME" >&2 + exit 1; +fi + +case "$1" in + start) + echo -n "Starting $NAME: " + start-stop-daemon --start --quiet --make-pidfile --pidfile "/var/run/${NAME}.pid" --background --exec "${DAEMON}" && echo "done." || echo "FAILED!" + ;; + stop) + echo -n "Stopping $NAME:" + start-stop-daemon --stop --quiet --oknodo --pidfile "/var/run/${NAME}.pid" && echo "done." || echo "FAILED!" + ;; + + restart) + $0 start + $0 stop + ;; + + *) + echo "Usage: /etc/init.d/conntrackd {start|stop|restart}" + exit 1 +esac + +exit 0 diff --git a/examples/stats/Makefile.am b/examples/stats/Makefile.am new file mode 100644 index 0000000..b43c3b8 --- /dev/null +++ b/examples/stats/Makefile.am @@ -0,0 +1 @@ +EXTRA_DIST = conntrackd.conf diff --git a/examples/stats/conntrackd.conf b/examples/stats/conntrackd.conf new file mode 100644 index 0000000..e514ac0 --- /dev/null +++ b/examples/stats/conntrackd.conf @@ -0,0 +1,69 @@ +# +# General settings +# +General { + # + # Number of buckets in the caches: hash table + # + HashSize 8192 + + # + # Maximum number of conntracks: + # it must be >= $ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max + # + HashLimit 65535 + + # + # Logfile + # + LogFile /var/log/conntrackd.log + + # + # Lockfile + # + LockFile /var/lock/conntrack.lock + + # + # Unix socket configuration + # + UNIX { + Path /tmp/sync.sock + Backlog 20 + } + + # + # Netlink socket buffer size + # + SocketBufferSize 262142 + + # + # Increase the socket buffer up to maximun if required + # + SocketBufferSizeMaxGrown 655355 +} + +# +# Ignore traffic for a certain set of IP's: Usually +# all the IP assigned to the firewall since local +# traffic must be ignored, just forwarded connections +# are worth to replicate +# +IgnoreTrafficFor { + IPv4_address 127.0.0.1 # loopback +} + +# +# Do not replicate certain protocol traffic +# +IgnoreProtocol { + UDP +# ICMP +# IGMP +# VRRP + # numeric numbers also valid +} + +# +# Strip NAT traffic +# +StripNAT diff --git a/examples/sync/Makefile.am b/examples/sync/Makefile.am new file mode 100644 index 0000000..28e7643 --- /dev/null +++ b/examples/sync/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = persistent nack diff --git a/examples/sync/nack/Makefile.am b/examples/sync/nack/Makefile.am new file mode 100644 index 0000000..6fd99b1 --- /dev/null +++ b/examples/sync/nack/Makefile.am @@ -0,0 +1,2 @@ +EXTRA_DIST = script_backup.sh script_master.sh +SUBDIRS = node1 node2 diff --git a/examples/sync/nack/README b/examples/sync/nack/README new file mode 100644 index 0000000..66987f7 --- /dev/null +++ b/examples/sync/nack/README @@ -0,0 +1 @@ +This directory contains the files for the NACK based protocol diff --git a/examples/sync/nack/node1/Makefile.am b/examples/sync/nack/node1/Makefile.am new file mode 100644 index 0000000..edc0ed7 --- /dev/null +++ b/examples/sync/nack/node1/Makefile.am @@ -0,0 +1 @@ +EXTRA_DIST = conntrackd.conf keepalived.conf diff --git a/examples/sync/nack/node1/conntrackd.conf b/examples/sync/nack/node1/conntrackd.conf new file mode 100644 index 0000000..f24fa7e --- /dev/null +++ b/examples/sync/nack/node1/conntrackd.conf @@ -0,0 +1,125 @@ +# +# Synchronizer settings +# +Sync { + Mode NACK { + # + # Size of the buffer that hold destroy messages for + # possible resends (in bytes) + # + ResendBufferSize 262144 + + # + # Entries committed to the connection tracking table + # starts with a limited timeout of N seconds until the + # takeover process is completed. + # + CommitTimeout 180 + + # Set Acknowledgement window size + ACKWindowSize 20 + } + + # + # Multicast IP and interface where messages are + # broadcasted (dedicated link). IMPORTANT: Make sure + # that iptables accepts traffic for destination + # 225.0.0.50, eg: + # + # iptables -I INPUT -d 225.0.0.50 -j ACCEPT + # iptables -I OUTPUT -d 225.0.0.50 -j ACCEPT + # + Multicast { + IPv4_address 225.0.0.50 + IPv4_interface 192.168.100.100 # IP of dedicated link + Group 3780 + Backlog 20 + } + + # Enable/Disable message checksumming + Checksum on + + # Uncomment this if you want to replicate just certain TCP states. + # This option introduces a tradeoff in the replication: it reduces + # CPU consumption and lost messages rate at the cost of having + # backup replicas that don't contain the current state that the active + # replica holds. TCP states are: SYN_SENT, SYN_RECV, ESTABLISHED, + # FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN. + # + # Replicate ESTABLISHED TIME_WAIT for TCP +} + +# +# General settings +# +General { + # + # Number of buckets in the caches: hash table + # + HashSize 8192 + + # + # Maximum number of conntracks: + # it must be >= $ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max + # + HashLimit 65535 + + # + # Logfile + # + LogFile /var/log/conntrackd.log + + # + # Lockfile + # + LockFile /var/lock/conntrack.lock + + # + # Unix socket configuration + # + UNIX { + Path /tmp/sync.sock + Backlog 20 + } + + # + # Netlink socket buffer size + # + SocketBufferSize 262142 + + # + # Increase the socket buffer up to maximum if required + # + SocketBufferSizeMaxGrown 655355 +} + +# +# Ignore traffic for a certain set of IP's: Usually +# all the IP assigned to the firewall since local +# traffic must be ignored, just forwarded connections +# are worth to replicate +# +IgnoreTrafficFor { + IPv4_address 127.0.0.1 # loopback + IPv4_address 192.168.0.1 + IPv4_address 192.168.1.1 + IPv4_address 192.168.100.100 # dedicated link ip + IPv4_address 192.168.0.100 # virtual IP 1 + IPv4_address 192.168.1.100 # virtual IP 2 +} + +# +# Do not replicate certain protocol traffic +# +IgnoreProtocol { + UDP + ICMP + IGMP + VRRP + # numeric numbers also valid +} + +# +# Strip NAT traffic +# +StripNAT diff --git a/examples/sync/nack/node1/keepalived.conf b/examples/sync/nack/node1/keepalived.conf new file mode 100644 index 0000000..41aa35b --- /dev/null +++ b/examples/sync/nack/node1/keepalived.conf @@ -0,0 +1,38 @@ +vrrp_sync_group G1 { # must be before vrrp_instance declaration + group { + VI_1 + VI_2 + } + notify_master /etc/conntrackd/script_master.sh + notify_backup /etc/conntrackd/script_backup.sh +} + +vrrp_instance VI_1 { + interface eth1 + state SLAVE + virtual_router_id 61 + priority 80 + advert_int 3 + authentication { + auth_type PASS + auth_pass papas_con_tomate + } + virtual_ipaddress { + 192.168.0.100 # default CIDR mask is /32 + } +} + +vrrp_instance VI_2 { + interface eth0 + state SLAVE + virtual_router_id 62 + priority 80 + advert_int 3 + authentication { + auth_type PASS + auth_pass papas_con_tomate + } + virtual_ipaddress { + 192.168.1.100 + } +} diff --git a/examples/sync/nack/node2/Makefile.am b/examples/sync/nack/node2/Makefile.am new file mode 100644 index 0000000..edc0ed7 --- /dev/null +++ b/examples/sync/nack/node2/Makefile.am @@ -0,0 +1 @@ +EXTRA_DIST = conntrackd.conf keepalived.conf diff --git a/examples/sync/nack/node2/conntrackd.conf b/examples/sync/nack/node2/conntrackd.conf new file mode 100644 index 0000000..4f15773 --- /dev/null +++ b/examples/sync/nack/node2/conntrackd.conf @@ -0,0 +1,124 @@ +# +# Synchronizer settings +# +Sync { + Mode NACK { + # + # Size of the buffer that hold destroy messages for + # possible resends (in bytes) + # + ResendBufferSize 262144 + + # Entries committed to the connection tracking table + # starts with a limited timeout of N seconds until the + # takeover process is completed. + # + CommitTimeout 180 + + # Set Acknowledgement window size + ACKWindowSize 20 + } + + # + # Multicast IP and interface where messages are + # broadcasted (dedicated link). IMPORTANT: Make sure + # that iptables accepts traffic for destination + # 225.0.0.50, eg: + # + # iptables -I INPUT -d 225.0.0.50 -j ACCEPT + # iptables -I OUTPUT -d 225.0.0.50 -j ACCEPT + # + Multicast { + IPv4_address 225.0.0.50 + IPv4_interface 192.168.100.200 # IP of dedicated link + Group 3780 + Backlog 20 + } + + # Enable/Disable message checksumming + Checksum on + + # Uncomment this if you want to replicate just certain TCP states. + # This option introduces a tradeoff in the replication: it reduces + # CPU consumption and lost messages rate at the cost of having + # backup replicas that don't contain the current state that the active + # replica holds. TCP states are: SYN_SENT, SYN_RECV, ESTABLISHED, + # FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN. + # + # Replicate ESTABLISHED TIME_WAIT for TCP +} + +# +# General settings +# +General { + # + # Number of buckets in the caches: hash table + # + HashSize 8192 + + # + # Maximum number of conntracks: + # it must be >= $ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max + # + HashLimit 65535 + + # + # Logfile + # + LogFile /var/log/conntrackd.log + + # + # Lockfile + # + LockFile /var/lock/conntrack.lock + + # + # Unix socket configuration + # + UNIX { + Path /tmp/sync.sock + Backlog 20 + } + + # + # Netlink socket buffer size + # + SocketBufferSize 262142 + + # + # Increase the socket buffer up to maximum if required + # + SocketBufferSizeMaxGrown 655355 +} + +# +# Ignore traffic for a certain set of IP's: Usually +# all the IP assigned to the firewall since local +# traffic must be ignored, just forwarded connections +# are worth to replicate +# +IgnoreTrafficFor { + IPv4_address 127.0.0.1 # loopback + IPv4_address 192.168.0.2 + IPv4_address 192.168.1.2 + IPv4_address 192.168.100.200 # dedicated link ip + IPv4_address 192.168.0.200 # virtual IP 1 + IPv4_address 192.168.1.200 # virtual IP 2 +} + +# +# Do not replicate certain protocol traffic +# +IgnoreProtocol { + UDP + ICMP + IGMP + VRRP + # numeric numbers also valid +} + +# +# Strip NAT traffic +# +StripNAT diff --git a/examples/sync/nack/node2/keepalived.conf b/examples/sync/nack/node2/keepalived.conf new file mode 100644 index 0000000..41aa35b --- /dev/null +++ b/examples/sync/nack/node2/keepalived.conf @@ -0,0 +1,38 @@ +vrrp_sync_group G1 { # must be before vrrp_instance declaration + group { + VI_1 + VI_2 + } + notify_master /etc/conntrackd/script_master.sh + notify_backup /etc/conntrackd/script_backup.sh +} + +vrrp_instance VI_1 { + interface eth1 + state SLAVE + virtual_router_id 61 + priority 80 + advert_int 3 + authentication { + auth_type PASS + auth_pass papas_con_tomate + } + virtual_ipaddress { + 192.168.0.100 # default CIDR mask is /32 + } +} + +vrrp_instance VI_2 { + interface eth0 + state SLAVE + virtual_router_id 62 + priority 80 + advert_int 3 + authentication { + auth_type PASS + auth_pass papas_con_tomate + } + virtual_ipaddress { + 192.168.1.100 + } +} diff --git a/examples/sync/nack/script_backup.sh b/examples/sync/nack/script_backup.sh new file mode 100755 index 0000000..813e375 --- /dev/null +++ b/examples/sync/nack/script_backup.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +/usr/sbin/conntrackd -n # request a resync from other nodes via multicast diff --git a/examples/sync/nack/script_master.sh b/examples/sync/nack/script_master.sh new file mode 100755 index 0000000..ff1dbc0 --- /dev/null +++ b/examples/sync/nack/script_master.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +/usr/sbin/conntrackd -c # commit the cache +/usr/sbin/conntrackd -f # flush the caches +/usr/sbin/conntrackd -R # resync with kernel conntrack table diff --git a/examples/sync/persistent/Makefile.am b/examples/sync/persistent/Makefile.am new file mode 100644 index 0000000..6fd99b1 --- /dev/null +++ b/examples/sync/persistent/Makefile.am @@ -0,0 +1,2 @@ +EXTRA_DIST = script_backup.sh script_master.sh +SUBDIRS = node1 node2 diff --git a/examples/sync/persistent/README b/examples/sync/persistent/README new file mode 100644 index 0000000..36b5989 --- /dev/null +++ b/examples/sync/persistent/README @@ -0,0 +1 @@ +This directory contains the files for the PERSISTENT based protocol diff --git a/examples/sync/persistent/node1/Makefile.am b/examples/sync/persistent/node1/Makefile.am new file mode 100644 index 0000000..edc0ed7 --- /dev/null +++ b/examples/sync/persistent/node1/Makefile.am @@ -0,0 +1 @@ +EXTRA_DIST = conntrackd.conf keepalived.conf diff --git a/examples/sync/persistent/node1/conntrackd.conf b/examples/sync/persistent/node1/conntrackd.conf new file mode 100644 index 0000000..90afeb7 --- /dev/null +++ b/examples/sync/persistent/node1/conntrackd.conf @@ -0,0 +1,130 @@ +# +# Synchronizer settings +# +Sync { + Mode PERSISTENT { + # + # If a conntrack entry is not modified in <= 15 seconds, then + # a message is broadcasted. This mechanism is used to + # resynchronize nodes that just joined the multicast group + # + RefreshTime 15 + + # + # If we don't receive a notification about the state of + # an entry in the external cache after N seconds, then + # remove it. + # + CacheTimeout 180 + + # + # Entries committed to the connection tracking table + # starts with a limited timeout of N seconds until the + # takeover process is completed. + # + CommitTimeout 180 + } + + # + # Multicast IP and interface where messages are + # broadcasted (dedicated link). IMPORTANT: Make sure + # that iptables accepts traffic for destination + # 225.0.0.50, eg: + # + # iptables -I INPUT -d 225.0.0.50 -j ACCEPT + # iptables -I OUTPUT -d 225.0.0.50 -j ACCEPT + # + Multicast { + IPv4_address 225.0.0.50 + IPv4_interface 192.168.100.100 # IP of dedicated link + Group 3780 + Backlog 20 + } + + # Enable/Disable message checksumming + Checksum on + + # Uncomment this if you want to replicate just certain TCP states. + # This option introduces a tradeoff in the replication: it reduces + # CPU consumption and lost messages rate at the cost of having + # backup replicas that don't contain the current state that the active + # replica holds. TCP states are: SYN_SENT, SYN_RECV, ESTABLISHED, + # FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN. + # + # Replicate ESTABLISHED TIME_WAIT for TCP +} + +# +# General settings +# +General { + # + # Number of buckets in the caches: hash table + # + HashSize 8192 + + # + # Maximum number of conntracks: + # it must be >= $ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max + # + HashLimit 65535 + + # + # Logfile + # + LogFile /var/log/conntrackd.log + + # + # Lockfile + # + LockFile /var/lock/conntrack.lock + + # + # Unix socket configuration + # + UNIX { + Path /tmp/sync.sock + Backlog 20 + } + + # + # Netlink socket buffer size + # + SocketBufferSize 262142 + + # + # Increase the socket buffer up to maximum if required + # + SocketBufferSizeMaxGrown 655355 +} + +# +# Ignore traffic for a certain set of IP's: Usually +# all the IP assigned to the firewall since local +# traffic must be ignored, just forwarded connections +# are worth to replicate +# +IgnoreTrafficFor { + IPv4_address 127.0.0.1 # loopback + IPv4_address 192.168.0.1 + IPv4_address 192.168.1.1 + IPv4_address 192.168.100.100 # dedicated link ip + IPv4_address 192.168.0.100 # virtual IP 1 + IPv4_address 192.168.1.100 # virtual IP 2 +} + +# +# Do not replicate certain protocol traffic +# +IgnoreProtocol { + UDP + ICMP + IGMP + VRRP + # numeric numbers also valid +} + +# +# Strip NAT traffic +# +StripNAT diff --git a/examples/sync/persistent/node1/keepalived.conf b/examples/sync/persistent/node1/keepalived.conf new file mode 100644 index 0000000..41aa35b --- /dev/null +++ b/examples/sync/persistent/node1/keepalived.conf @@ -0,0 +1,38 @@ +vrrp_sync_group G1 { # must be before vrrp_instance declaration + group { + VI_1 + VI_2 + } + notify_master /etc/conntrackd/script_master.sh + notify_backup /etc/conntrackd/script_backup.sh +} + +vrrp_instance VI_1 { + interface eth1 + state SLAVE + virtual_router_id 61 + priority 80 + advert_int 3 + authentication { + auth_type PASS + auth_pass papas_con_tomate + } + virtual_ipaddress { + 192.168.0.100 # default CIDR mask is /32 + } +} + +vrrp_instance VI_2 { + interface eth0 + state SLAVE + virtual_router_id 62 + priority 80 + advert_int 3 + authentication { + auth_type PASS + auth_pass papas_con_tomate + } + virtual_ipaddress { + 192.168.1.100 + } +} diff --git a/examples/sync/persistent/node2/Makefile.am b/examples/sync/persistent/node2/Makefile.am new file mode 100644 index 0000000..edc0ed7 --- /dev/null +++ b/examples/sync/persistent/node2/Makefile.am @@ -0,0 +1 @@ +EXTRA_DIST = conntrackd.conf keepalived.conf diff --git a/examples/sync/persistent/node2/conntrackd.conf b/examples/sync/persistent/node2/conntrackd.conf new file mode 100644 index 0000000..aee4a29 --- /dev/null +++ b/examples/sync/persistent/node2/conntrackd.conf @@ -0,0 +1,130 @@ +# +# Synchronizer settings +# +Sync { + Mode PERSISTENT { + # + # If a conntrack entry is not modified in <= 15 seconds, then + # a message is broadcasted. This mechanism is used to + # resynchronize nodes that just joined the multicast group + # + RefreshTime 15 + + # + # If we don't receive a notification about the state of + # an entry in the external cache after N seconds, then + # remove it. + # + CacheTimeout 180 + + # + # Entries committed to the connection tracking table + # starts with a limited timeout of N seconds until the + # takeover process is completed. + # + CommitTimeout 180 + } + + # + # Multicast IP and interface where messages are + # broadcasted (dedicated link). IMPORTANT: Make sure + # that iptables accepts traffic for destination + # 225.0.0.50, eg: + # + # iptables -I INPUT -d 225.0.0.50 -j ACCEPT + # iptables -I OUTPUT -d 225.0.0.50 -j ACCEPT + # + Multicast { + IPv4_address 225.0.0.50 + IPv4_interface 192.168.100.200 # IP of dedicated link + Group 3780 + Backlog 20 + } + + # Enable/Disable message checksumming + Checksum on + + # Uncomment this if you want to replicate just certain TCP states. + # This option introduces a tradeoff in the replication: it reduces + # CPU consumption and lost messages rate at the cost of having + # backup replicas that don't contain the current state that the active + # replica holds. TCP states are: SYN_SENT, SYN_RECV, ESTABLISHED, + # FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN. + # + # Replicate ESTABLISHED TIME_WAIT for TCP +} + +# +# General settings +# +General { + # + # Number of buckets in the caches: hash table + # + HashSize 8192 + + # + # Maximum number of conntracks: + # it must be >= $ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max + # + HashLimit 65535 + + # + # Logfile + # + LogFile /var/log/conntrackd.log + + # + # Lockfile + # + LockFile /var/lock/conntrack.lock + + # + # Unix socket configuration + # + UNIX { + Path /tmp/sync.sock + Backlog 20 + } + + # + # Netlink socket buffer size + # + SocketBufferSize 262142 + + # + # Increase the socket buffer up to maximum if required + # + SocketBufferSizeMaxGrown 655355 +} + +# +# Ignore traffic for a certain set of IP's: Usually +# all the IP assigned to the firewall since local +# traffic must be ignored, just forwarded connections +# are worth to replicate +# +IgnoreTrafficFor { + IPv4_address 127.0.0.1 # loopback + IPv4_address 192.168.0.2 + IPv4_address 192.168.1.2 + IPv4_address 192.168.100.200 # dedicated link ip + IPv4_address 192.168.0.200 # virtual IP 1 + IPv4_address 192.168.1.200 # virtual IP 2 +} + +# +# Do not replicate certain protocol traffic +# +IgnoreProtocol { + UDP + ICMP + IGMP + VRRP + # numeric numbers also valid +} + +# +# Strip NAT traffic +# +StripNAT diff --git a/examples/sync/persistent/node2/keepalived.conf b/examples/sync/persistent/node2/keepalived.conf new file mode 100644 index 0000000..41aa35b --- /dev/null +++ b/examples/sync/persistent/node2/keepalived.conf @@ -0,0 +1,38 @@ +vrrp_sync_group G1 { # must be before vrrp_instance declaration + group { + VI_1 + VI_2 + } + notify_master /etc/conntrackd/script_master.sh + notify_backup /etc/conntrackd/script_backup.sh +} + +vrrp_instance VI_1 { + interface eth1 + state SLAVE + virtual_router_id 61 + priority 80 + advert_int 3 + authentication { + auth_type PASS + auth_pass papas_con_tomate + } + virtual_ipaddress { + 192.168.0.100 # default CIDR mask is /32 + } +} + +vrrp_instance VI_2 { + interface eth0 + state SLAVE + virtual_router_id 62 + priority 80 + advert_int 3 + authentication { + auth_type PASS + auth_pass papas_con_tomate + } + virtual_ipaddress { + 192.168.1.100 + } +} diff --git a/examples/sync/persistent/script_backup.sh b/examples/sync/persistent/script_backup.sh new file mode 100755 index 0000000..8ea2ad8 --- /dev/null +++ b/examples/sync/persistent/script_backup.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +/usr/sbin/conntrackd -B diff --git a/examples/sync/persistent/script_master.sh b/examples/sync/persistent/script_master.sh new file mode 100755 index 0000000..70c26c9 --- /dev/null +++ b/examples/sync/persistent/script_master.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +/usr/sbin/conntrackd -c +/usr/sbin/conntrackd -R diff --git a/extensions/Makefile.am b/extensions/Makefile.am new file mode 100644 index 0000000..5366ee3 --- /dev/null +++ b/extensions/Makefile.am @@ -0,0 +1,16 @@ +include $(top_srcdir)/Make_global.am + +AM_CFLAGS=-fPIC -Wall +LIBS= + +pkglib_LTLIBRARIES = ct_proto_tcp.la ct_proto_udp.la \ + ct_proto_icmp.la ct_proto_sctp.la + +ct_proto_tcp_la_SOURCES = libct_proto_tcp.c +ct_proto_tcp_la_LDFLAGS = -module -avoid-version +ct_proto_udp_la_SOURCES = libct_proto_udp.c +ct_proto_udp_la_LDFLAGS = -module -avoid-version +ct_proto_icmp_la_SOURCES = libct_proto_icmp.c +ct_proto_icmp_la_LDFLAGS = -module -avoid-version +ct_proto_sctp_la_SOURCES = libct_proto_sctp.c +ct_proto_sctp_la_LDFLAGS = -module -avoid-version diff --git a/extensions/libct_proto_icmp.c b/extensions/libct_proto_icmp.c new file mode 100644 index 0000000..e7cb04d --- /dev/null +++ b/extensions/libct_proto_icmp.c @@ -0,0 +1,108 @@ +/* + * (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 /* For htons */ +#include +#include +#include +#include "conntrack.h" + +static struct option opts[] = { + {"icmp-type", 1, 0, '1'}, + {"icmp-code", 1, 0, '2'}, + {"icmp-id", 1, 0, '3'}, + {0, 0, 0, 0} +}; + +static void help() +{ + fprintf(stdout, "--icmp-type icmp type\n"); + fprintf(stdout, "--icmp-code icmp code\n"); + fprintf(stdout, "--icmp-id icmp id\n"); +} + +/* Add 1; spaces filled with 0. */ +static u_int8_t invmap[] + = { [ICMP_ECHO] = ICMP_ECHOREPLY + 1, + [ICMP_ECHOREPLY] = ICMP_ECHO + 1, + [ICMP_TIMESTAMP] = ICMP_TIMESTAMPREPLY + 1, + [ICMP_TIMESTAMPREPLY] = ICMP_TIMESTAMP + 1, + [ICMP_INFO_REQUEST] = ICMP_INFO_REPLY + 1, + [ICMP_INFO_REPLY] = ICMP_INFO_REQUEST + 1, + [ICMP_ADDRESS] = ICMP_ADDRESSREPLY + 1, + [ICMP_ADDRESSREPLY] = ICMP_ADDRESS + 1}; + +static int parse(char c, char *argv[], + struct nfct_tuple *orig, + struct nfct_tuple *reply, + struct nfct_tuple *exptuple, + struct nfct_tuple *mask, + union nfct_protoinfo *proto, + unsigned int *flags) +{ + switch(c) { + case '1': + if (optarg) { + orig->l4dst.icmp.type = atoi(optarg); + reply->l4dst.icmp.type = + invmap[orig->l4dst.icmp.type] - 1; + *flags |= ICMP_TYPE; + } + break; + case '2': + if (optarg) { + orig->l4dst.icmp.code = atoi(optarg); + reply->l4dst.icmp.code = 0; + *flags |= ICMP_CODE; + } + break; + case '3': + if (optarg) { + orig->l4src.icmp.id = htons(atoi(optarg)); + reply->l4dst.icmp.id = 0; + *flags |= ICMP_ID; + } + break; + } + return 1; +} + +static int final_check(unsigned int flags, + unsigned int command, + struct nfct_tuple *orig, + struct nfct_tuple *reply) +{ + if (!(flags & ICMP_TYPE)) + return 0; + else if (!(flags & ICMP_CODE)) + return 0; + + return 1; +} + +static struct ctproto_handler icmp = { + .name = "icmp", + .protonum = IPPROTO_ICMP, + .parse_opts = parse, + .final_check = final_check, + .help = help, + .opts = opts, + .version = VERSION, +}; + +static void __attribute__ ((constructor)) init(void); + +static void init(void) +{ + register_proto(&icmp); +} diff --git a/extensions/libct_proto_icmp.man b/extensions/libct_proto_icmp.man new file mode 100644 index 0000000..3b860d0 --- /dev/null +++ b/extensions/libct_proto_icmp.man @@ -0,0 +1,10 @@ +This module matches on ICMP-specific fields. +.TP +.BI "--icmp-type " "TYPE" +ICMP Type. Has to be specified numerically. +.TP +.BI "--icmp-code " "CODE" +ICMP Code. Has to be specified numerically. +.TP +.BI "--icmp-id " "ID" +ICMP Id. Has to be specified numerically. diff --git a/extensions/libct_proto_sctp.c b/extensions/libct_proto_sctp.c new file mode 100644 index 0000000..1c8f0d1 --- /dev/null +++ b/extensions/libct_proto_sctp.c @@ -0,0 +1,164 @@ +/* + * (C) 2005 by Harald Welte + * 2006 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 +#include +#include +#include +#include /* For htons */ +#include "conntrack.h" +#include +#include + +static struct option opts[] = { + {"orig-port-src", 1, 0, '1'}, + {"orig-port-dst", 1, 0, '2'}, + {"reply-port-src", 1, 0, '3'}, + {"reply-port-dst", 1, 0, '4'}, + {"state", 1, 0, '5'}, + {"tuple-port-src", 1, 0, '6'}, + {"tuple-port-dst", 1, 0, '7'}, + {0, 0, 0, 0} +}; + +static const char *states[] = { + "NONE", + "CLOSED", + "COOKIE_WAIT", + "COOKIE_ECHOED", + "ESTABLISHED", + "SHUTDOWN_SENT", + "SHUTDOWN_RECV", + "SHUTDOWN_ACK_SENT", +}; + +static void help() +{ + fprintf(stdout, "--orig-port-src original source port\n"); + fprintf(stdout, "--orig-port-dst original destination port\n"); + fprintf(stdout, "--reply-port-src reply source port\n"); + fprintf(stdout, "--reply-port-dst reply destination port\n"); + fprintf(stdout, "--state SCTP state, fe. ESTABLISHED\n"); + fprintf(stdout, "--tuple-port-src expectation tuple src port\n"); + fprintf(stdout, "--tuple-port-src expectation tuple dst port\n"); +} + +static int parse_options(char c, char *argv[], + struct nfct_tuple *orig, + struct nfct_tuple *reply, + struct nfct_tuple *exptuple, + struct nfct_tuple *mask, + union nfct_protoinfo *proto, + unsigned int *flags) +{ + switch(c) { + case '1': + if (optarg) { + orig->l4src.sctp.port = htons(atoi(optarg)); + *flags |= SCTP_ORIG_SPORT; + } + break; + case '2': + if (optarg) { + orig->l4dst.sctp.port = htons(atoi(optarg)); + *flags |= SCTP_ORIG_DPORT; + } + break; + case '3': + if (optarg) { + reply->l4src.sctp.port = htons(atoi(optarg)); + *flags |= SCTP_REPL_SPORT; + } + break; + case '4': + if (optarg) { + reply->l4dst.sctp.port = htons(atoi(optarg)); + *flags |= SCTP_REPL_DPORT; + } + break; + case '5': + if (optarg) { + int i; + for (i=0; i<10; i++) { + if (strcmp(optarg, states[i]) == 0) { + /* FIXME: Add state to + * nfct_protoinfo + proto->sctp.state = i; */ + break; + } + } + if (i == 10) { + printf("doh?\n"); + return 0; + } + *flags |= SCTP_STATE; + } + break; + case '6': + if (optarg) { + exptuple->l4src.sctp.port = htons(atoi(optarg)); + *flags |= SCTP_EXPTUPLE_SPORT; + } + break; + case '7': + if (optarg) { + exptuple->l4dst.sctp.port = htons(atoi(optarg)); + *flags |= SCTP_EXPTUPLE_DPORT; + } + + } + return 1; +} + +static int final_check(unsigned int flags, + unsigned int command, + struct nfct_tuple *orig, + struct nfct_tuple *reply) +{ + int ret = 0; + + if ((flags & (SCTP_ORIG_SPORT|SCTP_ORIG_DPORT)) + && !(flags & (SCTP_REPL_SPORT|SCTP_REPL_DPORT))) { + reply->l4src.sctp.port = orig->l4dst.sctp.port; + reply->l4dst.sctp.port = orig->l4src.sctp.port; + ret = 1; + } else if (!(flags & (SCTP_ORIG_SPORT|SCTP_ORIG_DPORT)) + && (flags & (SCTP_REPL_SPORT|SCTP_REPL_DPORT))) { + orig->l4src.sctp.port = reply->l4dst.sctp.port; + orig->l4dst.sctp.port = reply->l4src.sctp.port; + ret = 1; + } + if ((flags & (SCTP_ORIG_SPORT|SCTP_ORIG_DPORT)) + && ((flags & (SCTP_REPL_SPORT|SCTP_REPL_DPORT)))) + ret = 1; + + /* --state is missing and we are trying to create a conntrack */ + if (ret && (command & CT_CREATE) && (!(flags & SCTP_STATE))) + ret = 0; + + return ret; +} + +static struct ctproto_handler sctp = { + .name = "sctp", + .protonum = IPPROTO_SCTP, + .parse_opts = parse_options, + .final_check = final_check, + .help = help, + .opts = opts, + .version = VERSION, +}; + +static void __attribute__ ((constructor)) init(void); + +static void init(void) +{ + register_proto(&sctp); +} diff --git a/extensions/libct_proto_tcp.c b/extensions/libct_proto_tcp.c new file mode 100644 index 0000000..ee24206 --- /dev/null +++ b/extensions/libct_proto_tcp.c @@ -0,0 +1,180 @@ +/* + * (C) 2005 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 +#include +#include +#include +#include /* For htons */ +#include +#include + +#include "conntrack.h" + +static struct option opts[] = { + {"orig-port-src", 1, 0, '1'}, + {"orig-port-dst", 1, 0, '2'}, + {"reply-port-src", 1, 0, '3'}, + {"reply-port-dst", 1, 0, '4'}, + {"mask-port-src", 1, 0, '5'}, + {"mask-port-dst", 1, 0, '6'}, + {"state", 1, 0, '7'}, + {"tuple-port-src", 1, 0, '8'}, + {"tuple-port-dst", 1, 0, '9'}, + {0, 0, 0, 0} +}; + +static const char *states[] = { + "NONE", + "SYN_SENT", + "SYN_RECV", + "ESTABLISHED", + "FIN_WAIT", + "CLOSE_WAIT", + "LAST_ACK", + "TIME_WAIT", + "CLOSE", + "LISTEN" +}; + +static void help() +{ + fprintf(stdout, "--orig-port-src original source port\n"); + fprintf(stdout, "--orig-port-dst original destination port\n"); + fprintf(stdout, "--reply-port-src reply source port\n"); + fprintf(stdout, "--reply-port-dst reply destination port\n"); + fprintf(stdout, "--mask-port-src mask source port\n"); + fprintf(stdout, "--mask-port-dst mask destination port\n"); + fprintf(stdout, "--tuple-port-src expectation tuple src port\n"); + fprintf(stdout, "--tuple-port-src expectation tuple dst port\n"); + fprintf(stdout, "--state TCP state, fe. ESTABLISHED\n"); +} + +static int parse_options(char c, char *argv[], + struct nfct_tuple *orig, + struct nfct_tuple *reply, + struct nfct_tuple *exptuple, + struct nfct_tuple *mask, + union nfct_protoinfo *proto, + unsigned int *flags) +{ + switch(c) { + case '1': + if (optarg) { + orig->l4src.tcp.port = htons(atoi(optarg)); + *flags |= TCP_ORIG_SPORT; + } + break; + case '2': + if (optarg) { + orig->l4dst.tcp.port = htons(atoi(optarg)); + *flags |= TCP_ORIG_DPORT; + } + break; + case '3': + if (optarg) { + reply->l4src.tcp.port = htons(atoi(optarg)); + *flags |= TCP_REPL_SPORT; + } + break; + case '4': + if (optarg) { + reply->l4dst.tcp.port = htons(atoi(optarg)); + *flags |= TCP_REPL_DPORT; + } + break; + case '5': + if (optarg) { + mask->l4src.tcp.port = htons(atoi(optarg)); + *flags |= TCP_MASK_SPORT; + } + break; + case '6': + if (optarg) { + mask->l4dst.tcp.port = htons(atoi(optarg)); + *flags |= TCP_MASK_DPORT; + } + break; + case '7': + if (optarg) { + int i; + for (i=0; i<10; i++) { + if (strcmp(optarg, states[i]) == 0) { + proto->tcp.state = i; + break; + } + } + if (i == 10) { + printf("doh?\n"); + return 0; + } + *flags |= TCP_STATE; + } + break; + case '8': + if (optarg) { + exptuple->l4src.tcp.port = htons(atoi(optarg)); + *flags |= TCP_EXPTUPLE_SPORT; + } + break; + case '9': + if (optarg) { + exptuple->l4dst.tcp.port = htons(atoi(optarg)); + *flags |= TCP_EXPTUPLE_DPORT; + } + break; + } + return 1; +} + +static int final_check(unsigned int flags, + unsigned int command, + struct nfct_tuple *orig, + struct nfct_tuple *reply) +{ + int ret = 0; + + if ((flags & (TCP_ORIG_SPORT|TCP_ORIG_DPORT)) + && !(flags & (TCP_REPL_SPORT|TCP_REPL_DPORT))) { + reply->l4src.tcp.port = orig->l4dst.tcp.port; + reply->l4dst.tcp.port = orig->l4src.tcp.port; + ret = 1; + } else if (!(flags & (TCP_ORIG_SPORT|TCP_ORIG_DPORT)) + && (flags & (TCP_REPL_SPORT|TCP_REPL_DPORT))) { + orig->l4src.tcp.port = reply->l4dst.tcp.port; + orig->l4dst.tcp.port = reply->l4src.tcp.port; + ret = 1; + } + if ((flags & (TCP_ORIG_SPORT|TCP_ORIG_DPORT)) + && ((flags & (TCP_REPL_SPORT|TCP_REPL_DPORT)))) + ret = 1; + + /* --state is missing and we are trying to create a conntrack */ + if (ret && (command & CT_CREATE) && (!(flags & TCP_STATE))) + ret = 0; + + return ret; +} + +static struct ctproto_handler tcp = { + .name = "tcp", + .protonum = IPPROTO_TCP, + .parse_opts = parse_options, + .final_check = final_check, + .help = help, + .opts = opts, + .version = VERSION, +}; + +static void __attribute__ ((constructor)) init(void); + +static void init(void) +{ + register_proto(&tcp); +} diff --git a/extensions/libct_proto_tcp.man b/extensions/libct_proto_tcp.man new file mode 100644 index 0000000..41783f8 --- /dev/null +++ b/extensions/libct_proto_tcp.man @@ -0,0 +1,16 @@ +This module matches on TCP-specific fields. +.TP +.BI "--orig-port-src " "PORT" +Source port in original direction +.TP +.BI "--orig-port-dst " "PORT" +Destination port in original direction +.TP +.BI "--reply-port-src " "PORT" +Source port in reply direction +.TP +.BI "--reply-port-dst " "PORT" +Destination port in reply direction +.TP +.BI "--state " "[NONE|SYN_SENT|SYN_RECV|ESTABLISHED|FIN_WAIT|CLOSE_WAIT|LAST_ACK|TIME_WAIT|CLOSE|LISTEN]" +TCP state diff --git a/extensions/libct_proto_udp.c b/extensions/libct_proto_udp.c new file mode 100644 index 0000000..48079e0 --- /dev/null +++ b/extensions/libct_proto_udp.c @@ -0,0 +1,141 @@ +/* + * (C) 2005 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 +#include +#include +#include /* For htons */ +#include "conntrack.h" +#include +#include + +static struct option opts[] = { + {"orig-port-src", 1, 0, '1'}, + {"orig-port-dst", 1, 0, '2'}, + {"reply-port-src", 1, 0, '3'}, + {"reply-port-dst", 1, 0, '4'}, + {"mask-port-src", 1, 0, '5'}, + {"mask-port-dst", 1, 0, '6'}, + {"tuple-port-src", 1, 0, '7'}, + {"tuple-port-dst", 1, 0, '8'}, + {0, 0, 0, 0} +}; + +static void help() +{ + fprintf(stdout, "--orig-port-src original source port\n"); + fprintf(stdout, "--orig-port-dst original destination port\n"); + fprintf(stdout, "--reply-port-src reply source port\n"); + fprintf(stdout, "--reply-port-dst reply destination port\n"); + fprintf(stdout, "--mask-port-src mask source port\n"); + fprintf(stdout, "--mask-port-dst mask destination port\n"); + fprintf(stdout, "--tuple-port-src expectation tuple src port\n"); + fprintf(stdout, "--tuple-port-src expectation tuple dst port\n"); +} + +static int parse_options(char c, char *argv[], + struct nfct_tuple *orig, + struct nfct_tuple *reply, + struct nfct_tuple *exptuple, + struct nfct_tuple *mask, + union nfct_protoinfo *proto, + unsigned int *flags) +{ + switch(c) { + case '1': + if (optarg) { + orig->l4src.udp.port = htons(atoi(optarg)); + *flags |= UDP_ORIG_SPORT; + } + break; + case '2': + if (optarg) { + orig->l4dst.udp.port = htons(atoi(optarg)); + *flags |= UDP_ORIG_DPORT; + } + break; + case '3': + if (optarg) { + reply->l4src.udp.port = htons(atoi(optarg)); + *flags |= UDP_REPL_SPORT; + } + break; + case '4': + if (optarg) { + reply->l4dst.udp.port = htons(atoi(optarg)); + *flags |= UDP_REPL_DPORT; + } + break; + case '5': + if (optarg) { + mask->l4src.udp.port = htons(atoi(optarg)); + *flags |= UDP_MASK_SPORT; + } + break; + case '6': + if (optarg) { + mask->l4dst.udp.port = htons(atoi(optarg)); + *flags |= UDP_MASK_DPORT; + } + break; + case '7': + if (optarg) { + exptuple->l4src.udp.port = htons(atoi(optarg)); + *flags |= UDP_EXPTUPLE_SPORT; + } + break; + case '8': + if (optarg) { + exptuple->l4dst.udp.port = htons(atoi(optarg)); + *flags |= UDP_EXPTUPLE_DPORT; + } + + } + return 1; +} + +static int final_check(unsigned int flags, + unsigned int command, + struct nfct_tuple *orig, + struct nfct_tuple *reply) +{ + if ((flags & (UDP_ORIG_SPORT|UDP_ORIG_DPORT)) + && !(flags & (UDP_REPL_SPORT|UDP_REPL_DPORT))) { + reply->l4src.udp.port = orig->l4dst.udp.port; + reply->l4dst.udp.port = orig->l4src.udp.port; + return 1; + } else if (!(flags & (UDP_ORIG_SPORT|UDP_ORIG_DPORT)) + && (flags & (UDP_REPL_SPORT|UDP_REPL_DPORT))) { + orig->l4src.udp.port = reply->l4dst.udp.port; + orig->l4dst.udp.port = reply->l4src.udp.port; + return 1; + } + if ((flags & (UDP_ORIG_SPORT|UDP_ORIG_DPORT)) + && ((flags & (UDP_REPL_SPORT|UDP_REPL_DPORT)))) + return 1; + + return 0; +} + +static struct ctproto_handler udp = { + .name = "udp", + .protonum = IPPROTO_UDP, + .parse_opts = parse_options, + .final_check = final_check, + .help = help, + .opts = opts, + .version = VERSION, +}; + +static void __attribute__ ((constructor)) init(void); + +static void init(void) +{ + register_proto(&udp); +} diff --git a/extensions/libct_proto_udp.man b/extensions/libct_proto_udp.man new file mode 100644 index 0000000..c67fedf --- /dev/null +++ b/extensions/libct_proto_udp.man @@ -0,0 +1,13 @@ +This module matches on UDP-specific fields. +.TP +.BI "--orig-port-src " "PORT" +Source port in original direction +.TP +.BI "--orig-port-dst " "PORT" +Destination port in original direction +.TP +.BI "--reply-port-src " "PORT" +Source port in reply direction +.TP +.BI "--reply-port-dst " "PORT" +Destination port in reply direction diff --git a/include/Makefile.am b/include/Makefile.am new file mode 100644 index 0000000..e669d73 --- /dev/null +++ b/include/Makefile.am @@ -0,0 +1,5 @@ + +noinst_HEADERS = alarm.h jhash.h slist.h cache.h linux_list.h \ + sync.h conntrackd.h local.h us-conntrack.h \ + debug.h log.h hash.h mcast.h buffer.h + diff --git a/include/alarm.h b/include/alarm.h new file mode 100644 index 0000000..93e6482 --- /dev/null +++ b/include/alarm.h @@ -0,0 +1,13 @@ +#ifndef _TIMER_H_ +#define _TIMER_H_ + +#include "linux_list.h" + +struct alarm_list { + struct list_head head; + unsigned long expires; + void *data; + void (*function)(struct alarm_list *a, void *data); +}; + +#endif diff --git a/include/buffer.h b/include/buffer.h new file mode 100644 index 0000000..8d72dfb --- /dev/null +++ b/include/buffer.h @@ -0,0 +1,32 @@ +#ifndef _BUFFER_H_ +#define _BUFFER_H_ + +#include +#include +#include +#include +#include "linux_list.h" + +struct buffer { + pthread_mutex_t lock; + size_t max_size; + size_t cur_size; + struct list_head head; +}; + +struct buffer_node { + struct list_head head; + size_t size; + char data[0]; +}; + +struct buffer *buffer_create(size_t max_size); +void buffer_destroy(struct buffer *b); +int buffer_add(struct buffer *b, const void *data, size_t size); +void buffer_del(struct buffer *b, void *data); +void __buffer_del(struct buffer *b, void *data); +void buffer_iterate(struct buffer *b, + void *data, + int (*iterate)(void *data1, void *data2)); + +#endif diff --git a/include/cache.h b/include/cache.h new file mode 100644 index 0000000..7d9559a --- /dev/null +++ b/include/cache.h @@ -0,0 +1,92 @@ +#ifndef _CACHE_H_ +#define _CACHE_H_ + +#include +#include + +/* cache features */ +enum { + NO_FEATURES = 0, + + TIMER_FEATURE = 0, + TIMER = (1 << TIMER_FEATURE), + + LIFETIME_FEATURE = 2, + LIFETIME = (1 << LIFETIME_FEATURE), + + __CACHE_MAX_FEATURE +}; +#define CACHE_MAX_FEATURE __CACHE_MAX_FEATURE + +struct cache; +struct us_conntrack; + +struct cache_feature { + size_t size; + void (*add)(struct us_conntrack *u, void *data); + void (*update)(struct us_conntrack *u, void *data); + void (*destroy)(struct us_conntrack *u, void *data); + int (*dump)(struct us_conntrack *u, void *data, char *buf, int type); +}; + +extern struct cache_feature lifetime_feature; +extern struct cache_feature timer_feature; + +#define CACHE_MAX_NAMELEN 32 + +struct cache { + char name[CACHE_MAX_NAMELEN]; + struct hashtable *h; + + unsigned int num_features; + struct cache_feature **features; + unsigned int feature_type[CACHE_MAX_FEATURE]; + unsigned int *feature_offset; + struct cache_extra *extra; + unsigned int extra_offset; + + /* statistics */ + unsigned int add_ok; + unsigned int del_ok; + unsigned int upd_ok; + + unsigned int add_fail; + unsigned int del_fail; + unsigned int upd_fail; + + unsigned int commit_ok; + unsigned int commit_exist; + unsigned int commit_fail; + + unsigned int flush; +}; + +struct cache_extra { + unsigned int size; + + void (*add)(struct us_conntrack *u, void *data); + void (*update)(struct us_conntrack *u, void *data); + void (*destroy)(struct us_conntrack *u, void *data); +}; + +struct nf_conntrack; + +struct cache *cache_create(char *name, unsigned int features, u_int8_t proto, struct cache_extra *extra); +void cache_destroy(struct cache *e); + +struct us_conntrack *cache_add(struct cache *c, struct nf_conntrack *ct); +struct us_conntrack *cache_update(struct cache *c, struct nf_conntrack *ct); +struct us_conntrack *cache_update_force(struct cache *c, struct nf_conntrack *ct); +int cache_del(struct cache *c, struct nf_conntrack *ct); +int cache_test(struct cache *c, struct nf_conntrack *ct); +void cache_stats(struct cache *c, int fd); +struct us_conntrack *cache_get_conntrack(struct cache *, void *); +void *cache_get_extra(struct cache *, void *); + +/* iterators */ +void cache_dump(struct cache *c, int fd, int type); +void cache_commit(struct cache *c); +void cache_flush(struct cache *c); +void cache_bulk(struct cache *c); + +#endif diff --git a/include/conntrack.h b/include/conntrack.h new file mode 100644 index 0000000..fb3b9b6 --- /dev/null +++ b/include/conntrack.h @@ -0,0 +1,160 @@ +#ifndef _CONNTRACK_H +#define _CONNTRACK_H + +#ifdef HAVE_CONFIG_H +#include "../config.h" +#endif + +#include "linux_list.h" +#include +#include + +#define PROGNAME "conntrack" + +#include +#ifndef IPPROTO_SCTP +#define IPPROTO_SCTP 132 +#endif + +enum action { + CT_NONE = 0, + + CT_LIST_BIT = 0, + CT_LIST = (1 << CT_LIST_BIT), + + CT_CREATE_BIT = 1, + CT_CREATE = (1 << CT_CREATE_BIT), + + CT_UPDATE_BIT = 2, + CT_UPDATE = (1 << CT_UPDATE_BIT), + + CT_DELETE_BIT = 3, + CT_DELETE = (1 << CT_DELETE_BIT), + + CT_GET_BIT = 4, + CT_GET = (1 << CT_GET_BIT), + + CT_FLUSH_BIT = 5, + CT_FLUSH = (1 << CT_FLUSH_BIT), + + CT_EVENT_BIT = 6, + CT_EVENT = (1 << CT_EVENT_BIT), + + CT_VERSION_BIT = 7, + CT_VERSION = (1 << CT_VERSION_BIT), + + CT_HELP_BIT = 8, + CT_HELP = (1 << CT_HELP_BIT), + + EXP_LIST_BIT = 9, + EXP_LIST = (1 << EXP_LIST_BIT), + + EXP_CREATE_BIT = 10, + EXP_CREATE = (1 << EXP_CREATE_BIT), + + EXP_DELETE_BIT = 11, + EXP_DELETE = (1 << EXP_DELETE_BIT), + + EXP_GET_BIT = 12, + EXP_GET = (1 << EXP_GET_BIT), + + EXP_FLUSH_BIT = 13, + EXP_FLUSH = (1 << EXP_FLUSH_BIT), + + EXP_EVENT_BIT = 14, + EXP_EVENT = (1 << EXP_EVENT_BIT), +}; +#define NUMBER_OF_CMD 15 + +enum options { + CT_OPT_ORIG_SRC_BIT = 0, + CT_OPT_ORIG_SRC = (1 << CT_OPT_ORIG_SRC_BIT), + + CT_OPT_ORIG_DST_BIT = 1, + CT_OPT_ORIG_DST = (1 << CT_OPT_ORIG_DST_BIT), + + CT_OPT_ORIG = (CT_OPT_ORIG_SRC | CT_OPT_ORIG_DST), + + CT_OPT_REPL_SRC_BIT = 2, + CT_OPT_REPL_SRC = (1 << CT_OPT_REPL_SRC_BIT), + + CT_OPT_REPL_DST_BIT = 3, + CT_OPT_REPL_DST = (1 << CT_OPT_REPL_DST_BIT), + + CT_OPT_REPL = (CT_OPT_REPL_SRC | CT_OPT_REPL_DST), + + CT_OPT_PROTO_BIT = 4, + CT_OPT_PROTO = (1 << CT_OPT_PROTO_BIT), + + CT_OPT_TIMEOUT_BIT = 5, + CT_OPT_TIMEOUT = (1 << CT_OPT_TIMEOUT_BIT), + + CT_OPT_STATUS_BIT = 6, + CT_OPT_STATUS = (1 << CT_OPT_STATUS_BIT), + + CT_OPT_ZERO_BIT = 7, + CT_OPT_ZERO = (1 << CT_OPT_ZERO_BIT), + + CT_OPT_EVENT_MASK_BIT = 8, + CT_OPT_EVENT_MASK = (1 << CT_OPT_EVENT_MASK_BIT), + + CT_OPT_EXP_SRC_BIT = 9, + CT_OPT_EXP_SRC = (1 << CT_OPT_EXP_SRC_BIT), + + CT_OPT_EXP_DST_BIT = 10, + CT_OPT_EXP_DST = (1 << CT_OPT_EXP_DST_BIT), + + CT_OPT_MASK_SRC_BIT = 11, + CT_OPT_MASK_SRC = (1 << CT_OPT_MASK_SRC_BIT), + + CT_OPT_MASK_DST_BIT = 12, + CT_OPT_MASK_DST = (1 << CT_OPT_MASK_DST_BIT), + + CT_OPT_NATRANGE_BIT = 13, + CT_OPT_NATRANGE = (1 << CT_OPT_NATRANGE_BIT), + + CT_OPT_MARK_BIT = 14, + CT_OPT_MARK = (1 << CT_OPT_MARK_BIT), + + CT_OPT_ID_BIT = 15, + CT_OPT_ID = (1 << CT_OPT_ID_BIT), + + CT_OPT_FAMILY_BIT = 16, + CT_OPT_FAMILY = (1 << CT_OPT_FAMILY_BIT), + + CT_OPT_MAX_BIT = CT_OPT_FAMILY_BIT +}; +#define NUMBER_OF_OPT CT_OPT_MAX_BIT+1 + +struct ctproto_handler { + struct list_head head; + + char *name; + u_int16_t protonum; + char *version; + + enum ctattr_protoinfo protoinfo_attr; + + int (*parse_opts)(char c, char *argv[], + struct nfct_tuple *orig, + struct nfct_tuple *reply, + struct nfct_tuple *exptuple, + struct nfct_tuple *mask, + union nfct_protoinfo *proto, + unsigned int *flags); + + int (*final_check)(unsigned int flags, + unsigned int command, + struct nfct_tuple *orig, + struct nfct_tuple *reply); + + void (*help)(); + + struct option *opts; + + unsigned int option_offset; +}; + +extern void register_proto(struct ctproto_handler *h); + +#endif diff --git a/include/conntrackd.h b/include/conntrackd.h new file mode 100644 index 0000000..a5f7a3a --- /dev/null +++ b/include/conntrackd.h @@ -0,0 +1,174 @@ +#ifndef _CONNTRACKD_H_ +#define _CONNTRACKD_H_ + +#include "mcast.h" +#include "local.h" + +#include +#include +#include "cache.h" +#include "debug.h" +#include +#include "state_helper.h" +#include + +/* UNIX facilities */ +#define FLUSH_MASTER 0 /* flush kernel conntrack table */ +#define RESYNC_MASTER 1 /* resync with kernel conntrack table */ +#define DUMP_INTERNAL 16 /* dump internal cache */ +#define DUMP_EXTERNAL 17 /* dump external cache */ +#define COMMIT 18 /* commit external cache */ +#define FLUSH_CACHE 19 /* flush cache */ +#define KILL 20 /* kill conntrackd */ +#define STATS 21 /* dump statistics */ +#define SEND_BULK 22 /* send a bulk */ +#define REQUEST_DUMP 23 /* request dump */ +#define DUMP_INT_XML 24 /* dump internal cache in XML */ +#define DUMP_EXT_XML 25 /* dump external cache in XML */ + +#define DEFAULT_CONFIGFILE "/etc/conntrackd/conntrackd.conf" +#define DEFAULT_LOCKFILE "/var/lock/conntrackd.lock" + +enum { + STRIP_NAT_BIT = 0, + STRIP_NAT = (1 << STRIP_NAT_BIT), + + DELAY_DESTROY_MSG_BIT = 1, + DELAY_DESTROY_MSG = (1 << DELAY_DESTROY_MSG_BIT), + + RELAX_TRANSITIONS_BIT = 2, + RELAX_TRANSITIONS = (1 << RELAX_TRANSITIONS_BIT), + + SYNC_MODE_PERSISTENT_BIT = 3, + SYNC_MODE_PERSISTENT = (1 << SYNC_MODE_PERSISTENT_BIT), + + SYNC_MODE_NACK_BIT = 4, + SYNC_MODE_NACK = (1 << SYNC_MODE_NACK_BIT), + + DONT_CHECKSUM_BIT = 5, + DONT_CHECKSUM = (1 << DONT_CHECKSUM_BIT), +}; + +/* daemon/request modes */ +#define NOT_SET 0 +#define DAEMON 1 +#define REQUEST 2 + +/* conntrackd modes */ +#define SYNC_MODE 0 +#define STATS_MODE 1 + +/* FILENAME_MAX is 4096 on my system, perhaps too much? */ +#ifndef FILENAME_MAXLEN +#define FILENAME_MAXLEN 256 +#endif + +union inet_address { + u_int32_t ipv4; + u_int32_t ipv6[4]; + u_int32_t all[4]; +}; + +#define CONFIG(x) conf.x + +struct ct_conf { + char logfile[FILENAME_MAXLEN]; + char lockfile[FILENAME_MAXLEN]; + int hashsize; /* hashtable size */ + struct mcast_conf mcast; /* multicast settings */ + struct local_conf local; /* unix socket facilities */ + int limit; + int refresh; + int cache_timeout; /* cache entries timeout */ + int commit_timeout; /* committed entries timeout */ + unsigned int netlink_buffer_size; + unsigned int netlink_buffer_size_max_grown; + unsigned char ignore_protocol[IPPROTO_MAX]; + union inet_address *listen_to; + unsigned int listen_to_len; + unsigned int flags; + int family; /* protocol family */ + unsigned int resend_buffer_size;/* NACK protocol */ + unsigned int window_size; +}; + +#define STATE(x) st.x + +struct ct_general_state { + sigset_t block; + FILE *log; + int local; + struct ct_mode *mode; + struct ignore_pool *ignore_pool; + + struct nfnl_handle *event; /* event handler */ + struct nfnl_handle *sync; /* sync handler */ + struct nfnl_handle *dump; /* dump handler */ + + struct nfnl_subsys_handle *subsys_event; /* events */ + struct nfnl_subsys_handle *subsys_sync; /* resync */ + struct nfnl_subsys_handle *subsys_dump; /* dump */ + + /* statistics */ + u_int64_t malformed; + u_int64_t bytes[NFCT_DIR_MAX]; + u_int64_t packets[NFCT_DIR_MAX]; +}; + +#define STATE_SYNC(x) state.sync->x + +struct ct_sync_state { + struct cache *internal; /* internal events cache (netlink) */ + struct cache *external; /* external events cache (mcast) */ + + struct mcast_sock *mcast_server; /* multicast socket: incoming */ + struct mcast_sock *mcast_client; /* multicast socket: outgoing */ + + struct sync_mode *mcast_sync; + struct buffer *buffer; + + u_int32_t last_seq_sent; /* last sequence number sent */ + u_int32_t last_seq_recv; /* last sequence number recv */ + u_int64_t packets_replayed; /* number of replayed packets */ + u_int64_t packets_lost; /* lost packets: sequence tracking */ +}; + +#define STATE_STATS(x) state.stats->x + +struct ct_stats_state { + struct cache *cache; /* internal events cache (netlink) */ +}; + +union ct_state { + struct ct_sync_state *sync; + struct ct_stats_state *stats; +}; + +extern struct ct_conf conf; +extern union ct_state state; +extern struct ct_general_state st; + +#ifndef IPPROTO_VRRP +#define IPPROTO_VRRP 112 +#endif + +struct ct_mode { + int (*init)(void); + int (*add_fds_to_set)(fd_set *readfds); + void (*step)(fd_set *readfds); + int (*local)(int fd, int type, void *data); + void (*kill)(void); + void (*dump)(struct nf_conntrack *ct, struct nlmsghdr *nlh); + void (*overrun)(struct nf_conntrack *ct, struct nlmsghdr *nlh); + void (*event_new)(struct nf_conntrack *ct, struct nlmsghdr *nlh); + void (*event_upd)(struct nf_conntrack *ct, struct nlmsghdr *nlh); + int (*event_dst)(struct nf_conntrack *ct, struct nlmsghdr *nlh); +}; + +/* conntrackd modes */ +extern struct ct_mode sync_mode; +extern struct ct_mode stats_mode; + +#define MAX(x, y) x > y ? x : y + +#endif diff --git a/include/debug.h b/include/debug.h new file mode 100644 index 0000000..67f2c71 --- /dev/null +++ b/include/debug.h @@ -0,0 +1,53 @@ +#ifndef _DEBUG_H +#define _DEBUG_H + +#if 0 +#define debug printf +#else +#define debug +#endif + +#include +#include +#include + +static inline void debug_ct(struct nf_conntrack *ct, char *msg) +{ + struct in_addr addr, addr2, addr3, addr4; + + debug("----%s (%p) ----\n", msg, ct); + memcpy(&addr, + nfct_get_attr(ct, ATTR_ORIG_IPV4_SRC), + sizeof(u_int32_t)); + memcpy(&addr2, + nfct_get_attr(ct, ATTR_ORIG_IPV4_DST), + sizeof(u_int32_t)); + memcpy(&addr3, + nfct_get_attr(ct, ATTR_REPL_IPV4_SRC), + sizeof(u_int32_t)); + memcpy(&addr4, + nfct_get_attr(ct, ATTR_REPL_IPV4_DST), + sizeof(u_int32_t)); + + debug("status: %x\n", nfct_get_attr_u32(ct, ATTR_STATUS)); + debug("l3:%d l4:%d ", + nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO), + nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO)); + debug("%s:%hu ->", inet_ntoa(addr), + ntohs(nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC))); + debug("%s:%hu\n", + inet_ntoa(addr2), + ntohs(nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST))); + debug("l3:%d l4:%d ", + nfct_get_attr_u8(ct, ATTR_REPL_L3PROTO), + nfct_get_attr_u8(ct, ATTR_REPL_L4PROTO)); + debug("%s:%hu ->", + inet_ntoa(addr3), + ntohs(nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC))); + debug("%s:%hu\n", + inet_ntoa(addr4), + ntohs(nfct_get_attr_u16(ct, ATTR_REPL_PORT_DST))); + debug("-------------------------\n"); +} + +#endif diff --git a/include/hash.h b/include/hash.h new file mode 100644 index 0000000..fd971e7 --- /dev/null +++ b/include/hash.h @@ -0,0 +1,47 @@ +#ifndef _NF_SET_HASH_H_ +#define _NF_SET_HASH_H_ + +#include +#include +#include "slist.h" +#include "linux_list.h" + +struct hashtable; +struct hashtable_node; + +struct hashtable { + u_int32_t hashsize; + u_int32_t limit; + u_int32_t count; + u_int32_t initval; + u_int32_t datasize; + + u_int32_t (*hash)(const void *data, struct hashtable *table); + int (*compare)(const void *data1, const void *data2); + + struct slist_head members[0]; +}; + +struct hashtable_node { + struct slist_head head; + char data[0]; +}; + +struct hashtable_node *hashtable_alloc_node(int datasize, void *data); +void hashtable_destroy_node(struct hashtable_node *h); + +struct hashtable * +hashtable_create(int hashsize, int limit, int datasize, + u_int32_t (*hash)(const void *data, struct hashtable *table), + int (*compare)(const void *data1, const void *data2)); +void hashtable_destroy(struct hashtable *h); + +void *hashtable_add(struct hashtable *table, void *data); +void *hashtable_test(struct hashtable *table, const void *data); +int hashtable_del(struct hashtable *table, void *data); +int hashtable_flush(struct hashtable *table); +int hashtable_iterate(struct hashtable *table, void *data, + int (*iterate)(void *data1, void *data2)); +unsigned int hashtable_counter(struct hashtable *table); + +#endif diff --git a/include/ignore.h b/include/ignore.h new file mode 100644 index 0000000..40cb02d --- /dev/null +++ b/include/ignore.h @@ -0,0 +1,12 @@ +#ifndef _IGNORE_H_ +#define _IGNORE_H_ + +struct ignore_pool { + struct hashtable *h; +}; + +struct ignore_pool *ignore_pool_create(u_int8_t family); +void ignore_pool_destroy(struct ignore_pool *ip); +int ignore_pool_add(struct ignore_pool *ip, void *data); + +#endif diff --git a/include/jhash.h b/include/jhash.h new file mode 100644 index 0000000..38b8780 --- /dev/null +++ b/include/jhash.h @@ -0,0 +1,146 @@ +#ifndef _LINUX_JHASH_H +#define _LINUX_JHASH_H + +#define u32 unsigned int +#define u8 char + +/* jhash.h: Jenkins hash support. + * + * Copyright (C) 1996 Bob Jenkins (bob_jenkins@burtleburtle.net) + * + * http://burtleburtle.net/bob/hash/ + * + * These are the credits from Bob's sources: + * + * lookup2.c, by Bob Jenkins, December 1996, Public Domain. + * hash(), hash2(), hash3, and mix() are externally useful functions. + * Routines to test the hash are included if SELF_TEST is defined. + * You can use this free for any purpose. It has no warranty. + * + * Copyright (C) 2003 David S. Miller (davem@redhat.com) + * + * I've modified Bob's hash to be useful in the Linux kernel, and + * any bugs present are surely my fault. -DaveM + */ + +/* NOTE: Arguments are modified. */ +#define __jhash_mix(a, b, c) \ +{ \ + a -= b; a -= c; a ^= (c>>13); \ + b -= c; b -= a; b ^= (a<<8); \ + c -= a; c -= b; c ^= (b>>13); \ + a -= b; a -= c; a ^= (c>>12); \ + b -= c; b -= a; b ^= (a<<16); \ + c -= a; c -= b; c ^= (b>>5); \ + a -= b; a -= c; a ^= (c>>3); \ + b -= c; b -= a; b ^= (a<<10); \ + c -= a; c -= b; c ^= (b>>15); \ +} + +/* The golden ration: an arbitrary value */ +#define JHASH_GOLDEN_RATIO 0x9e3779b9 + +/* The most generic version, hashes an arbitrary sequence + * of bytes. No alignment or length assumptions are made about + * the input key. + */ +static inline u32 jhash(const void *key, u32 length, u32 initval) +{ + u32 a, b, c, len; + const u8 *k = key; + + len = length; + a = b = JHASH_GOLDEN_RATIO; + c = initval; + + while (len >= 12) { + a += (k[0] +((u32)k[1]<<8) +((u32)k[2]<<16) +((u32)k[3]<<24)); + b += (k[4] +((u32)k[5]<<8) +((u32)k[6]<<16) +((u32)k[7]<<24)); + c += (k[8] +((u32)k[9]<<8) +((u32)k[10]<<16)+((u32)k[11]<<24)); + + __jhash_mix(a,b,c); + + k += 12; + len -= 12; + } + + c += length; + switch (len) { + case 11: c += ((u32)k[10]<<24); + case 10: c += ((u32)k[9]<<16); + case 9 : c += ((u32)k[8]<<8); + case 8 : b += ((u32)k[7]<<24); + case 7 : b += ((u32)k[6]<<16); + case 6 : b += ((u32)k[5]<<8); + case 5 : b += k[4]; + case 4 : a += ((u32)k[3]<<24); + case 3 : a += ((u32)k[2]<<16); + case 2 : a += ((u32)k[1]<<8); + case 1 : a += k[0]; + }; + + __jhash_mix(a,b,c); + + return c; +} + +/* A special optimized version that handles 1 or more of u32s. + * The length parameter here is the number of u32s in the key. + */ +static inline u32 jhash2(u32 *k, u32 length, u32 initval) +{ + u32 a, b, c, len; + + a = b = JHASH_GOLDEN_RATIO; + c = initval; + len = length; + + while (len >= 3) { + a += k[0]; + b += k[1]; + c += k[2]; + __jhash_mix(a, b, c); + k += 3; len -= 3; + } + + c += length * 4; + + switch (len) { + case 2 : b += k[1]; + case 1 : a += k[0]; + }; + + __jhash_mix(a,b,c); + + return c; +} + + +/* A special ultra-optimized versions that knows they are hashing exactly + * 3, 2 or 1 word(s). + * + * NOTE: In partilar the "c += length; __jhash_mix(a,b,c);" normally + * done at the end is not done here. + */ +static inline u32 jhash_3words(u32 a, u32 b, u32 c, u32 initval) +{ + a += JHASH_GOLDEN_RATIO; + b += JHASH_GOLDEN_RATIO; + c += initval; + + __jhash_mix(a, b, c); + + return c; +} + +static inline u32 jhash_2words(u32 a, u32 b, u32 initval) +{ + return jhash_3words(a, b, 0, initval); +} + +static inline u32 jhash_1word(u32 a, u32 initval) +{ + return jhash_3words(a, 0, 0, initval); +} + +#endif /* _LINUX_JHASH_H */ diff --git a/include/linux_list.h b/include/linux_list.h new file mode 100644 index 0000000..57b56d7 --- /dev/null +++ b/include/linux_list.h @@ -0,0 +1,725 @@ +#ifndef _LINUX_LIST_H +#define _LINUX_LIST_H + +#undef offsetof +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) + +/** + * container_of - cast a member of a structure out to the containing structure + * + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + * + */ +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +/* + * Check at compile time that something is of a particular type. + * Always evaluates to 1 so you may use it easily in comparisons. + */ +#define typecheck(type,x) \ +({ type __dummy; \ + typeof(x) __dummy2; \ + (void)(&__dummy == &__dummy2); \ + 1; \ +}) + +#define prefetch(x) 1 + +/* empty define to make this work in userspace -HW */ +#ifndef smp_wmb +#define smp_wmb() +#endif + +/* + * These are non-NULL pointers that will result in page faults + * under normal circumstances, used to verify that nobody uses + * non-initialized list entries. + */ +#define LIST_POISON1 ((void *) 0x00100100) +#define LIST_POISON2 ((void *) 0x00200200) + +/* + * Simple doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +struct list_head { + struct list_head *next, *prev; +}; + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +#define INIT_LIST_HEAD(ptr) do { \ + (ptr)->next = (ptr); (ptr)->prev = (ptr); \ +} while (0) + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +/** + * list_add - add a new entry + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} + +/** + * list_add_tail - add a new entry + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static inline void list_add_tail(struct list_head *new, struct list_head *head) +{ + __list_add(new, head->prev, head); +} + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_add_rcu(struct list_head * new, + struct list_head * prev, struct list_head * next) +{ + new->next = next; + new->prev = prev; + smp_wmb(); + next->prev = new; + prev->next = new; +} + +/** + * list_add_rcu - add a new entry to rcu-protected list + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + * + * The caller must take whatever precautions are necessary + * (such as holding appropriate locks) to avoid racing + * with another list-mutation primitive, such as list_add_rcu() + * or list_del_rcu(), running on this same list. + * However, it is perfectly legal to run concurrently with + * the _rcu list-traversal primitives, such as + * list_for_each_entry_rcu(). + */ +static inline void list_add_rcu(struct list_head *new, struct list_head *head) +{ + __list_add_rcu(new, head, head->next); +} + +/** + * list_add_tail_rcu - add a new entry to rcu-protected list + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + * + * The caller must take whatever precautions are necessary + * (such as holding appropriate locks) to avoid racing + * with another list-mutation primitive, such as list_add_tail_rcu() + * or list_del_rcu(), running on this same list. + * However, it is perfectly legal to run concurrently with + * the _rcu list-traversal primitives, such as + * list_for_each_entry_rcu(). + */ +static inline void list_add_tail_rcu(struct list_head *new, + struct list_head *head) +{ + __list_add_rcu(new, head->prev, head); +} + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head * prev, struct list_head * next) +{ + next->prev = prev; + prev->next = next; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty on entry does not return true after this, the entry is + * in an undefined state. + */ +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->next = LIST_POISON1; + entry->prev = LIST_POISON2; +} + +/** + * list_del_rcu - deletes entry from list without re-initialization + * @entry: the element to delete from the list. + * + * Note: list_empty on entry does not return true after this, + * the entry is in an undefined state. It is useful for RCU based + * lockfree traversal. + * + * In particular, it means that we can not poison the forward + * pointers that may still be used for walking the list. + * + * The caller must take whatever precautions are necessary + * (such as holding appropriate locks) to avoid racing + * with another list-mutation primitive, such as list_del_rcu() + * or list_add_rcu(), running on this same list. + * However, it is perfectly legal to run concurrently with + * the _rcu list-traversal primitives, such as + * list_for_each_entry_rcu(). + * + * Note that the caller is not permitted to immediately free + * the newly deleted entry. Instead, either synchronize_kernel() + * or call_rcu() must be used to defer freeing until an RCU + * grace period has elapsed. + */ +static inline void list_del_rcu(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->prev = LIST_POISON2; +} + +/** + * list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list. + */ +static inline void list_del_init(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + INIT_LIST_HEAD(entry); +} + +/** + * list_move - delete from one list and add as another's head + * @list: the entry to move + * @head: the head that will precede our entry + */ +static inline void list_move(struct list_head *list, struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add(list, head); +} + +/** + * list_move_tail - delete from one list and add as another's tail + * @list: the entry to move + * @head: the head that will follow our entry + */ +static inline void list_move_tail(struct list_head *list, + struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add_tail(list, head); +} + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static inline int list_empty(const struct list_head *head) +{ + return head->next == head; +} + +/** + * list_empty_careful - tests whether a list is + * empty _and_ checks that no other CPU might be + * in the process of still modifying either member + * + * NOTE: using list_empty_careful() without synchronization + * can only be safe if the only activity that can happen + * to the list entry is list_del_init(). Eg. it cannot be used + * if another CPU could re-list_add() it. + * + * @head: the list to test. + */ +static inline int list_empty_careful(const struct list_head *head) +{ + struct list_head *next = head->next; + return (next == head) && (next == head->prev); +} + +static inline void __list_splice(struct list_head *list, + struct list_head *head) +{ + struct list_head *first = list->next; + struct list_head *last = list->prev; + struct list_head *at = head->next; + + first->prev = head; + head->next = first; + + last->next = at; + at->prev = last; +} + +/** + * list_splice - join two lists + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static inline void list_splice(struct list_head *list, struct list_head *head) +{ + if (!list_empty(list)) + __list_splice(list, head); +} + +/** + * list_splice_init - join two lists and reinitialise the emptied list. + * @list: the new list to add. + * @head: the place to add it in the first list. + * + * The list at @list is reinitialised + */ +static inline void list_splice_init(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) { + __list_splice(list, head); + INIT_LIST_HEAD(list); + } +} + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +/** + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next, prefetch(pos->next); pos != (head); \ + pos = pos->next, prefetch(pos->next)) + +/** + * __list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + * + * This variant differs from list_for_each() in that it's the + * simplest possible list iteration code, no prefetching is done. + * Use this for code that knows the list to be very short (empty + * or 1 entry) most of the time. + */ +#define __list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_for_each_prev - iterate over a list backwards + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + */ +#define list_for_each_prev(pos, head) \ + for (pos = (head)->prev, prefetch(pos->prev); pos != (head); \ + pos = pos->prev, prefetch(pos->prev)) + +/** + * list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the &struct list_head to use as a loop counter. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + prefetch(pos->member.next); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member), \ + prefetch(pos->member.next)) + +/** + * list_for_each_entry_reverse - iterate backwards over list of given type. + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_reverse(pos, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member), \ + prefetch(pos->member.prev); \ + &pos->member != (head); \ + pos = list_entry(pos->member.prev, typeof(*pos), member), \ + prefetch(pos->member.prev)) + +/** + * list_prepare_entry - prepare a pos entry for use as a start point in + * list_for_each_entry_continue + * @pos: the type * to use as a start point + * @head: the head of the list + * @member: the name of the list_struct within the struct. + */ +#define list_prepare_entry(pos, head, member) \ + ((pos) ? : list_entry(head, typeof(*pos), member)) + +/** + * list_for_each_entry_continue - iterate over list of given type + * continuing after existing point + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_continue(pos, head, member) \ + for (pos = list_entry(pos->member.next, typeof(*pos), member), \ + prefetch(pos->member.next); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member), \ + prefetch(pos->member.next)) + +/** + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos: the type * to use as a loop counter. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_rcu - iterate over an rcu-protected list + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + * + * This list-traversal primitive may safely run concurrently with + * the _rcu list-mutation primitives such as list_add_rcu() + * as long as the traversal is guarded by rcu_read_lock(). + */ +#define list_for_each_rcu(pos, head) \ + for (pos = (head)->next, prefetch(pos->next); pos != (head); \ + pos = pos->next, ({ smp_read_barrier_depends(); 0;}), prefetch(pos->next)) + +#define __list_for_each_rcu(pos, head) \ + for (pos = (head)->next; pos != (head); \ + pos = pos->next, ({ smp_read_barrier_depends(); 0;})) + +/** + * list_for_each_safe_rcu - iterate over an rcu-protected list safe + * against removal of list entry + * @pos: the &struct list_head to use as a loop counter. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + * + * This list-traversal primitive may safely run concurrently with + * the _rcu list-mutation primitives such as list_add_rcu() + * as long as the traversal is guarded by rcu_read_lock(). + */ +#define list_for_each_safe_rcu(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, ({ smp_read_barrier_depends(); 0;}), n = pos->next) + +/** + * list_for_each_entry_rcu - iterate over rcu list of given type + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * This list-traversal primitive may safely run concurrently with + * the _rcu list-mutation primitives such as list_add_rcu() + * as long as the traversal is guarded by rcu_read_lock(). + */ +#define list_for_each_entry_rcu(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + prefetch(pos->member.next); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member), \ + ({ smp_read_barrier_depends(); 0;}), \ + prefetch(pos->member.next)) + + +/** + * list_for_each_continue_rcu - iterate over an rcu-protected list + * continuing after existing point. + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + * + * This list-traversal primitive may safely run concurrently with + * the _rcu list-mutation primitives such as list_add_rcu() + * as long as the traversal is guarded by rcu_read_lock(). + */ +#define list_for_each_continue_rcu(pos, head) \ + for ((pos) = (pos)->next, prefetch((pos)->next); (pos) != (head); \ + (pos) = (pos)->next, ({ smp_read_barrier_depends(); 0;}), prefetch((pos)->next)) + +/* + * Double linked lists with a single pointer list head. + * Mostly useful for hash tables where the two pointer list head is + * too wasteful. + * You lose the ability to access the tail in O(1). + */ + +struct hlist_head { + struct hlist_node *first; +}; + +struct hlist_node { + struct hlist_node *next, **pprev; +}; + +#define HLIST_HEAD_INIT { .first = NULL } +#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL } +#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) +#define INIT_HLIST_NODE(ptr) ((ptr)->next = NULL, (ptr)->pprev = NULL) + +static inline int hlist_unhashed(const struct hlist_node *h) +{ + return !h->pprev; +} + +static inline int hlist_empty(const struct hlist_head *h) +{ + return !h->first; +} + +static inline void __hlist_del(struct hlist_node *n) +{ + struct hlist_node *next = n->next; + struct hlist_node **pprev = n->pprev; + *pprev = next; + if (next) + next->pprev = pprev; +} + +static inline void hlist_del(struct hlist_node *n) +{ + __hlist_del(n); + n->next = LIST_POISON1; + n->pprev = LIST_POISON2; +} + +/** + * hlist_del_rcu - deletes entry from hash list without re-initialization + * @n: the element to delete from the hash list. + * + * Note: list_unhashed() on entry does not return true after this, + * the entry is in an undefined state. It is useful for RCU based + * lockfree traversal. + * + * In particular, it means that we can not poison the forward + * pointers that may still be used for walking the hash list. + * + * The caller must take whatever precautions are necessary + * (such as holding appropriate locks) to avoid racing + * with another list-mutation primitive, such as hlist_add_head_rcu() + * or hlist_del_rcu(), running on this same list. + * However, it is perfectly legal to run concurrently with + * the _rcu list-traversal primitives, such as + * hlist_for_each_entry(). + */ +static inline void hlist_del_rcu(struct hlist_node *n) +{ + __hlist_del(n); + n->pprev = LIST_POISON2; +} + +static inline void hlist_del_init(struct hlist_node *n) +{ + if (n->pprev) { + __hlist_del(n); + INIT_HLIST_NODE(n); + } +} + +#define hlist_del_rcu_init hlist_del_init + +static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) +{ + struct hlist_node *first = h->first; + n->next = first; + if (first) + first->pprev = &n->next; + h->first = n; + n->pprev = &h->first; +} + + +/** + * hlist_add_head_rcu - adds the specified element to the specified hlist, + * while permitting racing traversals. + * @n: the element to add to the hash list. + * @h: the list to add to. + * + * The caller must take whatever precautions are necessary + * (such as holding appropriate locks) to avoid racing + * with another list-mutation primitive, such as hlist_add_head_rcu() + * or hlist_del_rcu(), running on this same list. + * However, it is perfectly legal to run concurrently with + * the _rcu list-traversal primitives, such as + * hlist_for_each_entry(), but only if smp_read_barrier_depends() + * is used to prevent memory-consistency problems on Alpha CPUs. + * Regardless of the type of CPU, the list-traversal primitive + * must be guarded by rcu_read_lock(). + * + * OK, so why don't we have an hlist_for_each_entry_rcu()??? + */ +static inline void hlist_add_head_rcu(struct hlist_node *n, + struct hlist_head *h) +{ + struct hlist_node *first = h->first; + n->next = first; + n->pprev = &h->first; + smp_wmb(); + if (first) + first->pprev = &n->next; + h->first = n; +} + +/* next must be != NULL */ +static inline void hlist_add_before(struct hlist_node *n, + struct hlist_node *next) +{ + n->pprev = next->pprev; + n->next = next; + next->pprev = &n->next; + *(n->pprev) = n; +} + +static inline void hlist_add_after(struct hlist_node *n, + struct hlist_node *next) +{ + next->next = n->next; + n->next = next; + next->pprev = &n->next; + + if(next->next) + next->next->pprev = &next->next; +} + +#define hlist_entry(ptr, type, member) container_of(ptr,type,member) + +#define hlist_for_each(pos, head) \ + for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \ + pos = pos->next) + +#define hlist_for_each_safe(pos, n, head) \ + for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \ + pos = n) + +/** + * hlist_for_each_entry - iterate over list of given type + * @tpos: the type * to use as a loop counter. + * @pos: the &struct hlist_node to use as a loop counter. + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry(tpos, pos, head, member) \ + for (pos = (head)->first; \ + pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) + +/** + * hlist_for_each_entry_continue - iterate over a hlist continuing after existing point + * @tpos: the type * to use as a loop counter. + * @pos: the &struct hlist_node to use as a loop counter. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_continue(tpos, pos, member) \ + for (pos = (pos)->next; \ + pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) + +/** + * hlist_for_each_entry_from - iterate over a hlist continuing from existing point + * @tpos: the type * to use as a loop counter. + * @pos: the &struct hlist_node to use as a loop counter. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_from(tpos, pos, member) \ + for (; pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) + +/** + * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @tpos: the type * to use as a loop counter. + * @pos: the &struct hlist_node to use as a loop counter. + * @n: another &struct hlist_node to use as temporary storage + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ + for (pos = (head)->first; \ + pos && ({ n = pos->next; 1; }) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = n) + +/** + * hlist_for_each_entry_rcu - iterate over rcu list of given type + * @pos: the type * to use as a loop counter. + * @pos: the &struct hlist_node to use as a loop counter. + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + * + * This list-traversal primitive may safely run concurrently with + * the _rcu list-mutation primitives such as hlist_add_rcu() + * as long as the traversal is guarded by rcu_read_lock(). + */ +#define hlist_for_each_entry_rcu(tpos, pos, head, member) \ + for (pos = (head)->first; \ + pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next, ({ smp_read_barrier_depends(); 0; }) ) + +#endif diff --git a/include/local.h b/include/local.h new file mode 100644 index 0000000..350b8bf --- /dev/null +++ b/include/local.h @@ -0,0 +1,29 @@ +#ifndef _LOCAL_SOCKET_H_ +#define _LOCAL_SOCKET_H_ + +#include + +#ifndef UNIX_PATH_MAX +#define UNIX_PATH_MAX 108 +#endif + +struct local_conf { + int backlog; + int reuseaddr; + char path[UNIX_PATH_MAX]; +}; + +/* local server */ +int local_server_create(struct local_conf *conf); +void local_server_destroy(int fd); +int do_local_server_step(int fd, void *data, + void (*process)(int fd, void *data)); + +/* local client */ +int local_client_create(struct local_conf *conf); +void local_client_destroy(int fd); +int do_local_client_step(int fd, void (*process)(char *buf)); +int do_local_request(int, struct local_conf *,void (*step)(char *buf)); +void local_step(char *buf); + +#endif diff --git a/include/log.h b/include/log.h new file mode 100644 index 0000000..9ecff30 --- /dev/null +++ b/include/log.h @@ -0,0 +1,10 @@ +#ifndef _LOG_H_ +#define _LOG_H_ + +#include + +FILE *init_log(char *filename); +void dlog(FILE *fd, char *format, ...); +void close_log(FILE *fd); + +#endif diff --git a/include/mcast.h b/include/mcast.h new file mode 100644 index 0000000..0f3e3cd --- /dev/null +++ b/include/mcast.h @@ -0,0 +1,48 @@ +#ifndef _MCAST_H_ +#define _MCAST_H_ + +#include + +struct mcast_conf { + int ipproto; + int backlog; + int reuseaddr; + unsigned short port; + union { + struct in_addr inet_addr; + struct in6_addr inet_addr6; + } in; + union { + struct in_addr interface_addr; + struct in6_addr interface_addr6; + } ifa; +}; + +struct mcast_stats { + u_int64_t bytes; + u_int64_t messages; + u_int64_t error; +}; + +struct mcast_sock { + int fd; + union { + struct sockaddr_in ipv4; + struct sockaddr_in6 ipv6; + } addr; + struct mcast_stats stats; +}; + +struct mcast_sock *mcast_server_create(struct mcast_conf *conf); +void mcast_server_destroy(struct mcast_sock *m); + +struct mcast_sock *mcast_client_create(struct mcast_conf *conf); +void mcast_client_destroy(struct mcast_sock *m); + +int mcast_send(struct mcast_sock *m, void *data, int size); +int mcast_recv(struct mcast_sock *m, void *data, int size); + +struct mcast_stats *mcast_get_stats(struct mcast_sock *m); +void mcast_dump_stats(int fd, struct mcast_sock *s, struct mcast_sock *r); + +#endif diff --git a/include/network.h b/include/network.h new file mode 100644 index 0000000..dab50db --- /dev/null +++ b/include/network.h @@ -0,0 +1,34 @@ +#ifndef _NETWORK_H_ +#define _NETWORK_H_ + +#include + +struct nlnetwork { + u_int16_t flags; + u_int16_t checksum; + u_int32_t seq; +}; + +struct nlnetwork_ack { + u_int16_t flags; + u_int16_t checksum; + u_int32_t seq; + u_int32_t from; + u_int32_t to; +}; + +enum { + NET_HELLO_BIT = 0, + NET_HELLO = (1 << NET_HELLO_BIT), + + NET_RESYNC_BIT = 1, + NET_RESYNC = (1 << NET_RESYNC_BIT), + + NET_NACK_BIT = 2, + NET_NACK = (1 << NET_NACK_BIT), + + NET_ACK_BIT = 3, + NET_ACK = (1 << NET_ACK_BIT), +}; + +#endif diff --git a/include/slist.h b/include/slist.h new file mode 100644 index 0000000..ab7fa34 --- /dev/null +++ b/include/slist.h @@ -0,0 +1,41 @@ +#ifndef _SLIST_H_ +#define _SLIST_H_ + +#include "linux_list.h" + +#define INIT_SLIST_HEAD(ptr) ((ptr).next = NULL) + +struct slist_head { + struct slist_head *next; +}; + +static inline int slist_empty(const struct slist_head *h) +{ + return !h->next; +} + +static inline void slist_del(struct slist_head *t, struct slist_head *prev) +{ + prev->next = t->next; + t->next = LIST_POISON1; +} + +static inline void slist_add(struct slist_head *head, struct slist_head *t) +{ + struct slist_head *tmp = head->next; + head->next = t; + t->next = tmp; +} + +#define slist_entry(ptr, type, member) container_of(ptr,type,member) + +#define slist_for_each(pos, head) \ + for (pos = (head)->next; pos && ({ prefetch(pos.next); 1; }); \ + pos = pos->next) + +#define slist_for_each_safe(pos, prev, next, head) \ + for (pos = (head)->next, prev = (head); \ + pos && ({ next = pos->next; 1; }); \ + ({ prev = (prev->next != next) ? prev->next : prev; }), pos = next) + +#endif diff --git a/include/state_helper.h b/include/state_helper.h new file mode 100644 index 0000000..1ed0b79 --- /dev/null +++ b/include/state_helper.h @@ -0,0 +1,20 @@ +#ifndef _STATE_HELPER_H_ +#define _STATE_HELPER_H_ + +enum { + ST_H_SKIP, + ST_H_REPLICATE +}; + +struct state_replication_helper { + u_int8_t proto; + unsigned int state; + + int (*verdict)(const struct state_replication_helper *h, + const struct nf_conntrack *ct); +}; + +int state_helper_verdict(int type, struct nf_conntrack *ct); +void state_helper_register(struct state_replication_helper *h, int state); + +#endif diff --git a/include/sync.h b/include/sync.h new file mode 100644 index 0000000..7756c87 --- /dev/null +++ b/include/sync.h @@ -0,0 +1,23 @@ +#ifndef _SYNC_HOOKS_H_ +#define _SYNC_HOOKS_H_ + +struct nlnetwork; +struct us_conntrack; + +struct sync_mode { + int internal_cache_flags; + int external_cache_flags; + struct cache_extra *internal_cache_extra; + struct cache_extra *external_cache_extra; + + int (*init)(void); + void (*kill)(void); + int (*local)(int fd, int type, void *data); + int (*pre_recv)(const struct nlnetwork *net); + void (*post_send)(const struct nlnetwork *net, struct us_conntrack *u); +}; + +extern struct sync_mode notrack; +extern struct sync_mode nack; + +#endif diff --git a/include/us-conntrack.h b/include/us-conntrack.h new file mode 100644 index 0000000..3d71e22 --- /dev/null +++ b/include/us-conntrack.h @@ -0,0 +1,13 @@ +#ifndef _US_CONNTRACK_H_ +#define _US_CONNTRACK_H_ + +#include + +/* be careful, do not modify the layout */ +struct us_conntrack { + struct nf_conntrack *ct; + struct cache *cache; /* add new attributes here */ + char data[0]; +}; + +#endif diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..381f8ac --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,26 @@ +include $(top_srcdir)/Make_global.am + +YACC=@YACC@ -d + +CLEANFILES = read_config_yy.c read_config_lex.c + +sbin_PROGRAMS = conntrack conntrackd + +conntrack_SOURCES = conntrack.c +conntrack_LDFLAGS = -rdynamic + +conntrackd_SOURCES = alarm.c main.c run.c hash.c buffer.c \ + local.c log.c mcast.c netlink.c proxy.c lock.c \ + ignore_pool.c \ + cache.c cache_iterators.c \ + cache_lifetime.c cache_timer.c \ + sync-mode.c sync-notrack.c sync-nack.c \ + traffic_stats.c stats-mode.c \ + network.c checksum.c \ + state_helper.c state_helper_tcp.c \ + read_config_yy.y read_config_lex.l + +conntrackd_LDFLAGS = $(all_libraries) -lnfnetlink -lnetfilter_conntrack \ + -lpthread + +EXTRA_DIST = read_config_yy.h diff --git a/src/alarm.c b/src/alarm.c new file mode 100644 index 0000000..1a465c2 --- /dev/null +++ b/src/alarm.c @@ -0,0 +1,141 @@ +/* + * (C) 2006 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include "linux_list.h" +#include "conntrackd.h" +#include "alarm.h" +#include "jhash.h" +#include +#include +#include + +/* alarm cascade */ +#define ALARM_CASCADE_SIZE 10 +static struct list_head *alarm_cascade; + +/* thread stuff */ +static pthread_t alarm_thread; + +struct alarm_list *create_alarm() +{ + return (struct alarm_list *) malloc(sizeof(struct alarm_list)); +} + +void destroy_alarm(struct alarm_list *t) +{ + free(t); +} + +void set_alarm_expiration(struct alarm_list *t, unsigned long expires) +{ + t->expires = expires; +} + +void set_alarm_function(struct alarm_list *t, + void (*fcn)(struct alarm_list *a, void *data)) +{ + t->function = fcn; +} + +void set_alarm_data(struct alarm_list *t, void *data) +{ + t->data = data; +} + +void init_alarm(struct alarm_list *t) +{ + INIT_LIST_HEAD(&t->head); + + t->expires = 0; + t->data = 0; + t->function = NULL; +} + +void add_alarm(struct alarm_list *alarm) +{ + unsigned int pos = jhash(alarm, sizeof(alarm), 0) % ALARM_CASCADE_SIZE; + + list_add(&alarm->head, &alarm_cascade[pos]); +} + +void del_alarm(struct alarm_list *alarm) +{ + list_del(&alarm->head); +} + +int mod_alarm(struct alarm_list *alarm, unsigned long expires) +{ + alarm->expires = expires; + return 0; +} + +void __run_alarms() +{ + struct list_head *i, *tmp; + struct alarm_list *t; + struct timespec req = {0, 1000000000 / ALARM_CASCADE_SIZE}; + struct timespec rem; + static int step = 0; + +retry: + if (nanosleep(&req, &rem) == -1) { + /* interrupted syscall: retry with remaining time */ + if (errno == EINTR) { + memcpy(&req, &rem, sizeof(struct timespec)); + goto retry; + } + } + + lock(); + list_for_each_safe(i, tmp, &alarm_cascade[step]) { + t = (struct alarm_list *) i; + + t->expires--; + if (t->expires == 0) + t->function(t, t->data); + } + step = (step + 1) < ALARM_CASCADE_SIZE ? step + 1 : 0; + unlock(); +} + +void *run_alarms(void *foo) +{ + while(1) + __run_alarms(); +} + +int create_alarm_thread() +{ + int i; + + alarm_cascade = malloc(sizeof(struct list_head) * ALARM_CASCADE_SIZE); + if (alarm_cascade == NULL) + return -1; + + for (i=0; i + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "buffer.h" + +struct buffer *buffer_create(size_t max_size) +{ + struct buffer *b; + + b = malloc(sizeof(struct buffer)); + if (b == NULL) + return NULL; + memset(b, 0, sizeof(struct buffer)); + + b->max_size = max_size; + INIT_LIST_HEAD(&b->head); + pthread_mutex_init(&b->lock, NULL); + + return b; +} + +void buffer_destroy(struct buffer *b) +{ + struct list_head *i, *tmp; + struct buffer_node *node; + + pthread_mutex_lock(&b->lock); + list_for_each_safe(i, tmp, &b->head) { + node = (struct buffer_node *) i; + list_del(i); + free(node); + } + pthread_mutex_unlock(&b->lock); + pthread_mutex_destroy(&b->lock); + free(b); +} + +static struct buffer_node *buffer_node_create(const void *data, size_t size) +{ + struct buffer_node *n; + + n = malloc(sizeof(struct buffer_node) + size); + if (n == NULL) + return NULL; + + INIT_LIST_HEAD(&n->head); + n->size = size; + memcpy(n->data, data, size); + + return n; +} + +int buffer_add(struct buffer *b, const void *data, size_t size) +{ + int ret = 0; + struct buffer_node *n; + + pthread_mutex_lock(&b->lock); + + /* does it fit this buffer? */ + if (size > b->max_size) { + errno = ENOSPC; + ret = -1; + goto err; + } + +retry: + /* buffer is full: kill the oldest entry */ + if (b->cur_size + size > b->max_size) { + n = (struct buffer_node *) b->head.prev; + list_del(b->head.prev); + b->cur_size -= n->size; + free(n); + goto retry; + } + + n = buffer_node_create(data, size); + if (n == NULL) { + ret = -1; + goto err; + } + + list_add(&n->head, &b->head); + b->cur_size += size; + +err: + pthread_mutex_unlock(&b->lock); + return ret; +} + +void __buffer_del(struct buffer *b, void *data) +{ + struct buffer_node *n = container_of(data, struct buffer_node, data); + + list_del(&n->head); + b->cur_size -= n->size; + free(n); +} + +void buffer_del(struct buffer *b, void *data) +{ + pthread_mutex_lock(&b->lock); + buffer_del(b, data); + pthread_mutex_unlock(&b->lock); +} + +void buffer_iterate(struct buffer *b, + void *data, + int (*iterate)(void *data1, void *data2)) +{ + struct list_head *i, *tmp; + struct buffer_node *n; + + pthread_mutex_lock(&b->lock); + list_for_each_safe(i, tmp, &b->head) { + n = (struct buffer_node *) i; + if (iterate(n->data, data)) + break; + } + pthread_mutex_unlock(&b->lock); +} diff --git a/src/cache.c b/src/cache.c new file mode 100644 index 0000000..6f7442b --- /dev/null +++ b/src/cache.c @@ -0,0 +1,446 @@ +/* + * (C) 2006-2007 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "jhash.h" +#include "hash.h" +#include "conntrackd.h" +#include +#include +#include "us-conntrack.h" +#include "cache.h" +#include "debug.h" + +static u_int32_t hash(const void *data, struct hashtable *table) +{ + unsigned int a, b; + const struct us_conntrack *u = data; + struct nf_conntrack *ct = u->ct; + + a = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV4_SRC), sizeof(u_int32_t), + ((nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO) << 16) | + (nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO)))); + + b = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV4_DST), sizeof(u_int32_t), + ((nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC) << 16) | + (nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST)))); + + return jhash_2words(a, b, 0) % table->hashsize; +} + +static u_int32_t hash6(const void *data, struct hashtable *table) +{ + unsigned int a, b; + const struct us_conntrack *u = data; + struct nf_conntrack *ct = u->ct; + + a = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV6_SRC), sizeof(u_int32_t), + ((nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO) << 16) | + (nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO)))); + + b = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV6_DST), sizeof(u_int32_t), + ((nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC) << 16) | + (nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST)))); + + return jhash_2words(a, b, 0) % table->hashsize; +} + +static int __compare(const struct nf_conntrack *ct1, + const struct nf_conntrack *ct2) +{ + return ((nfct_get_attr_u8(ct1, ATTR_ORIG_L3PROTO) == + nfct_get_attr_u8(ct2, ATTR_ORIG_L3PROTO)) && + (nfct_get_attr_u8(ct1, ATTR_ORIG_L4PROTO) == + nfct_get_attr_u8(ct2, ATTR_ORIG_L4PROTO)) && + (nfct_get_attr_u16(ct1, ATTR_ORIG_PORT_SRC) == + nfct_get_attr_u16(ct2, ATTR_ORIG_PORT_SRC)) && + (nfct_get_attr_u16(ct1, ATTR_ORIG_PORT_DST) == + nfct_get_attr_u16(ct2, ATTR_ORIG_PORT_DST)) && + (nfct_get_attr_u16(ct1, ATTR_REPL_PORT_SRC) == + nfct_get_attr_u16(ct2, ATTR_REPL_PORT_SRC)) && + (nfct_get_attr_u16(ct1, ATTR_REPL_PORT_DST) == + nfct_get_attr_u16(ct2, ATTR_REPL_PORT_DST))); +} + +static int compare(const void *data1, const void *data2) +{ + const struct us_conntrack *u1 = data1; + const struct us_conntrack *u2 = data2; + + return ((nfct_get_attr_u32(u1->ct, ATTR_ORIG_IPV4_SRC) == + nfct_get_attr_u32(u2->ct, ATTR_ORIG_IPV4_SRC)) && + (nfct_get_attr_u32(u1->ct, ATTR_ORIG_IPV4_DST) == + nfct_get_attr_u32(u2->ct, ATTR_ORIG_IPV4_DST)) && + (nfct_get_attr_u32(u1->ct, ATTR_REPL_IPV4_SRC) == + nfct_get_attr_u32(u2->ct, ATTR_REPL_IPV4_SRC)) && + (nfct_get_attr_u32(u1->ct, ATTR_REPL_IPV4_DST) == + nfct_get_attr_u32(u2->ct, ATTR_REPL_IPV4_DST)) && + __compare(u1->ct, u2->ct)); +} + +static int compare6(const void *data1, const void *data2) +{ + const struct us_conntrack *u1 = data1; + const struct us_conntrack *u2 = data2; + + return ((nfct_get_attr_u32(u1->ct, ATTR_ORIG_IPV6_SRC) == + nfct_get_attr_u32(u2->ct, ATTR_ORIG_IPV6_SRC)) && + (nfct_get_attr_u32(u1->ct, ATTR_ORIG_IPV6_DST) == + nfct_get_attr_u32(u2->ct, ATTR_ORIG_IPV6_DST)) && + (nfct_get_attr_u32(u1->ct, ATTR_REPL_IPV6_SRC) == + nfct_get_attr_u32(u2->ct, ATTR_REPL_IPV6_SRC)) && + (nfct_get_attr_u32(u1->ct, ATTR_REPL_IPV6_DST) == + nfct_get_attr_u32(u2->ct, ATTR_REPL_IPV6_DST)) && + __compare(u1->ct, u2->ct)); +} + +struct cache_feature *cache_feature[CACHE_MAX_FEATURE] = { + [TIMER_FEATURE] = &timer_feature, + [LIFETIME_FEATURE] = &lifetime_feature, +}; + +struct cache *cache_create(char *name, + unsigned int features, + u_int8_t proto, + struct cache_extra *extra) +{ + size_t size = sizeof(struct us_conntrack); + int i, j = 0; + struct cache *c; + struct cache_feature *feature_array[CACHE_MAX_FEATURE] = {}; + unsigned int feature_offset[CACHE_MAX_FEATURE] = {}; + unsigned int feature_type[CACHE_MAX_FEATURE] = {}; + + c = malloc(sizeof(struct cache)); + if (!c) + return NULL; + memset(c, 0, sizeof(struct cache)); + + strcpy(c->name, name); + + for (i = 0; i < CACHE_MAX_FEATURE; i++) { + if ((1 << i) & features) { + feature_array[j] = cache_feature[i]; + feature_offset[j] = size; + feature_type[i] = j; + size += cache_feature[i]->size; + j++; + } + } + + memcpy(c->feature_type, feature_type, sizeof(feature_type)); + + c->features = malloc(sizeof(struct cache_feature) * j); + if (!c->features) { + free(c); + return NULL; + } + memcpy(c->features, feature_array, sizeof(struct cache_feature) * j); + c->num_features = j; + + c->extra_offset = size; + c->extra = extra; + if (extra) + size += extra->size; + + c->feature_offset = malloc(sizeof(unsigned int) * j); + if (!c->feature_offset) { + free(c->features); + free(c); + return NULL; + } + memcpy(c->feature_offset, feature_offset, sizeof(unsigned int) * j); + + switch(proto) { + case AF_INET: + c->h = hashtable_create(CONFIG(hashsize), + CONFIG(limit), + size, + hash, + compare); + break; + case AF_INET6: + c->h = hashtable_create(CONFIG(hashsize), + CONFIG(limit), + size, + hash6, + compare6); + break; + } + + if (!c->h) { + free(c->features); + free(c->feature_offset); + free(c); + return NULL; + } + + return c; +} + +void cache_destroy(struct cache *c) +{ + lock(); + hashtable_destroy(c->h); + unlock(); + free(c->features); + free(c->feature_offset); + free(c); +} + +static struct us_conntrack *__add(struct cache *c, struct nf_conntrack *ct) +{ + int i; + size_t size = c->h->datasize; + char buf[size]; + struct us_conntrack *u = (struct us_conntrack *) buf; + struct nf_conntrack *newct; + + memset(u, 0, size); + + u->cache = c; + if ((u->ct = newct = nfct_new()) == NULL) { + errno = ENOMEM; + return 0; + } + memcpy(u->ct, ct, nfct_sizeof(ct)); + + u = hashtable_add(c->h, u); + if (u) { + void *data = u->data; + + for (i = 0; i < c->num_features; i++) { + c->features[i]->add(u, data); + data += c->features[i]->size; + } + + if (c->extra) + c->extra->add(u, ((void *) u) + c->extra_offset); + + return u; + } + free(newct); + + return NULL; +} + +struct us_conntrack *__cache_add(struct cache *c, struct nf_conntrack *ct) +{ + struct us_conntrack *u; + + u = __add(c, ct); + if (u) { + c->add_ok++; + return u; + } + c->add_fail++; + + return NULL; +} + +struct us_conntrack *cache_add(struct cache *c, struct nf_conntrack *ct) +{ + struct us_conntrack *u; + + lock(); + u = __cache_add(c, ct); + unlock(); + + return u; +} + +static struct us_conntrack *__update(struct cache *c, struct nf_conntrack *ct) +{ + size_t size = c->h->datasize; + char buf[size]; + struct us_conntrack *u = (struct us_conntrack *) buf; + + u->ct = ct; + + u = (struct us_conntrack *) hashtable_test(c->h, u); + if (u) { + int i; + void *data = u->data; + + for (i = 0; i < c->num_features; i++) { + c->features[i]->update(u, data); + data += c->features[i]->size; + } + + if (c->extra) + c->extra->update(u, ((void *) u) + c->extra_offset); + + if (nfct_attr_is_set(ct, ATTR_STATUS)) + nfct_set_attr_u32(u->ct, ATTR_STATUS, + nfct_get_attr_u32(ct, ATTR_STATUS)); + if (nfct_attr_is_set(ct, ATTR_TCP_STATE)) + nfct_set_attr_u8(u->ct, ATTR_TCP_STATE, + nfct_get_attr_u8(ct, ATTR_TCP_STATE)); + if (nfct_attr_is_set(ct, ATTR_TIMEOUT)) + nfct_set_attr_u32(u->ct, ATTR_TIMEOUT, + nfct_get_attr_u32(ct, ATTR_TIMEOUT)); + + return u; + } + return NULL; +} + +struct us_conntrack *__cache_update(struct cache *c, struct nf_conntrack *ct) +{ + struct us_conntrack *u; + + u = __update(c, ct); + if (u) { + c->upd_ok++; + return u; + } + c->upd_fail++; + + return NULL; +} + +struct us_conntrack *cache_update(struct cache *c, struct nf_conntrack *ct) +{ + struct us_conntrack *u; + + lock(); + u = __cache_update(c, ct); + unlock(); + + return u; +} + +struct us_conntrack *cache_update_force(struct cache *c, + struct nf_conntrack *ct) +{ + struct us_conntrack *u; + + lock(); + if ((u = __update(c, ct)) != NULL) { + c->upd_ok++; + unlock(); + return u; + } + if ((u = __add(c, ct)) != NULL) { + c->add_ok++; + unlock(); + return u; + } + c->add_fail++; + unlock(); + return NULL; +} + +int cache_test(struct cache *c, struct nf_conntrack *ct) +{ + size_t size = c->h->datasize; + char buf[size]; + struct us_conntrack *u = (struct us_conntrack *) buf; + void *ret; + + u->ct = ct; + + lock(); + ret = hashtable_test(c->h, u); + unlock(); + + return ret != NULL; +} + +static int __del(struct cache *c, struct nf_conntrack *ct) +{ + size_t size = c->h->datasize; + char buf[size]; + struct us_conntrack *u = (struct us_conntrack *) buf; + + u->ct = ct; + + u = (struct us_conntrack *) hashtable_test(c->h, u); + if (u) { + int i; + void *data = u->data; + struct nf_conntrack *p = u->ct; + + for (i = 0; i < c->num_features; i++) { + c->features[i]->destroy(u, data); + data += c->features[i]->size; + } + + if (c->extra) + c->extra->destroy(u, ((void *) u) + c->extra_offset); + + hashtable_del(c->h, u); + free(p); + return 1; + } + return 0; +} + +int __cache_del(struct cache *c, struct nf_conntrack *ct) +{ + if (__del(c, ct)) { + c->del_ok++; + return 1; + } + c->del_fail++; + + return 0; +} + +int cache_del(struct cache *c, struct nf_conntrack *ct) +{ + int ret; + + lock(); + ret = __cache_del(c, ct); + unlock(); + + return ret; +} + +struct us_conntrack *cache_get_conntrack(struct cache *c, void *data) +{ + return data - c->extra_offset; +} + +void *cache_get_extra(struct cache *c, void *data) +{ + return data + c->extra_offset; +} + +void cache_stats(struct cache *c, int fd) +{ + char buf[512]; + int size; + + lock(); + size = sprintf(buf, "cache %s:\n" + "current active connections:\t%12u\n" + "connections created:\t\t%12u\tfailed:\t%12u\n" + "connections updated:\t\t%12u\tfailed:\t%12u\n" + "connections destroyed:\t\t%12u\tfailed:\t%12u\n\n", + c->name, + hashtable_counter(c->h), + c->add_ok, + c->add_fail, + c->upd_ok, + c->upd_fail, + c->del_ok, + c->del_fail); + unlock(); + send(fd, buf, size, 0); +} diff --git a/src/cache_iterators.c b/src/cache_iterators.c new file mode 100644 index 0000000..5d5d22b --- /dev/null +++ b/src/cache_iterators.c @@ -0,0 +1,229 @@ +/* + * (C) 2006-2007 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "cache.h" +#include "jhash.h" +#include "hash.h" +#include "conntrackd.h" +#include +#include +#include "us-conntrack.h" +#include "debug.h" + +struct __dump_container { + int fd; + int type; +}; + +static int do_dump(void *data1, void *data2) +{ + char buf[1024]; + int size; + struct __dump_container *container = data1; + struct us_conntrack *u = data2; + void *data = u->data; + int i; + + memset(buf, 0, sizeof(buf)); + size = nfct_snprintf(buf, + sizeof(buf), + u->ct, + NFCT_T_UNKNOWN, + container->type, + 0); + + for (i = 0; i < u->cache->num_features; i++) { + if (u->cache->features[i]->dump) { + size += u->cache->features[i]->dump(u, + data, + buf+size, + container->type); + data += u->cache->features[i]->size; + } + } + size += sprintf(buf+size, "\n"); + if (send(container->fd, buf, size, 0) == -1) { + if (errno != EPIPE) + return -1; + } + + return 0; +} + +void cache_dump(struct cache *c, int fd, int type) +{ + struct __dump_container tmp = { + .fd = fd, + .type = type + }; + + lock(); + hashtable_iterate(c->h, (void *) &tmp, do_dump); + unlock(); +} + +static int do_commit(void *data1, void *data2) +{ + int ret; + struct cache *c = data1; + struct us_conntrack *u = data2; + struct nf_conntrack *ct; + char buf[4096]; + struct nlmsghdr *nlh = (struct nlmsghdr *)buf; + + ct = nfct_clone(u->ct); + if (ct == NULL) + return 0; + + if (nfct_attr_is_set(ct, ATTR_STATUS)) { + u_int32_t status = nfct_get_attr_u32(ct, ATTR_STATUS); + status &= ~IPS_EXPECTED; + nfct_set_attr_u32(ct, ATTR_STATUS, status); + } + + if (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) + nfct_setobjopt(ct, NFCT_SOPT_UNDO_SNAT); + if (nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) + nfct_setobjopt(ct, NFCT_SOPT_UNDO_DNAT); + if (nfct_getobjopt(ct, NFCT_GOPT_IS_SPAT)) + nfct_setobjopt(ct, NFCT_SOPT_UNDO_SPAT); + if (nfct_getobjopt(ct, NFCT_GOPT_IS_DPAT)) + nfct_setobjopt(ct, NFCT_SOPT_UNDO_DPAT); + + /* + * Set a reduced timeout for candidate-to-be-committed + * conntracks that live in the external cache + */ + nfct_set_attr_u32(ct, ATTR_TIMEOUT, CONFIG(commit_timeout)); + + ret = nfct_build_query(STATE(subsys_sync), + NFCT_Q_CREATE, + ct, + nlh, + sizeof(buf)); + + free(ct); + + if (ret == -1) { + /* XXX: Please cleanup this debug crap, default in logfile */ + debug("--- failed to build: %s --- \n", strerror(errno)); + return 0; + } + + ret = nfnl_query(STATE(sync), nlh); + if (ret == -1) { + switch(errno) { + case EEXIST: + c->commit_exist++; + break; + default: + c->commit_fail++; + break; + } + debug("--- failed to commit: %s --- \n", strerror(errno)); + } else { + c->commit_ok++; + debug("----- commit -----\n"); + } + + /* keep iterating even if we have found errors */ + return 0; +} + +void cache_commit(struct cache *c) +{ + unsigned int commit_ok = c->commit_ok; + unsigned int commit_exist = c->commit_exist; + unsigned int commit_fail = c->commit_fail; + + lock(); + hashtable_iterate(c->h, c, do_commit); + unlock(); + + /* calculate new entries committed */ + commit_ok = c->commit_ok - commit_ok; + commit_fail = c->commit_fail - commit_fail; + commit_exist = c->commit_exist - commit_exist; + + /* log results */ + dlog(STATE(log), "Committed %u new entries", commit_ok); + + if (commit_exist) + dlog(STATE(log), "%u entries ignored, " + "already exist", commit_exist); + if (commit_fail) + dlog(STATE(log), "%u entries can't be " + "committed", commit_fail); +} + +static int do_flush(void *data1, void *data2) +{ + struct cache *c = data1; + struct us_conntrack *u = data2; + void *data = u->data; + int i; + + for (i = 0; i < c->num_features; i++) { + c->features[i]->destroy(u, data); + data += c->features[i]->size; + } + free(u->ct); + + return 0; +} + +void cache_flush(struct cache *c) +{ + lock(); + hashtable_iterate(c->h, c, do_flush); + hashtable_flush(c->h); + c->flush++; + unlock(); +} + +#include "sync.h" +#include "network.h" + +static int do_bulk(void *data1, void *data2) +{ + int ret; + struct us_conntrack *u = data2; + char buf[4096]; + struct nlnetwork *net = (struct nlnetwork *) buf; + + ret = build_network_msg(NFCT_Q_UPDATE, + STATE(subsys_sync), + u->ct, + buf, + sizeof(buf)); + if (ret == -1) + debug_ct(u->ct, "failed to build"); + + mcast_send_netmsg(STATE_SYNC(mcast_client), net); + STATE_SYNC(mcast_sync)->post_send(net, u); + + /* keep iterating even if we have found errors */ + return 0; +} + +void cache_bulk(struct cache *c) +{ + lock(); + hashtable_iterate(c->h, NULL, do_bulk); + unlock(); +} diff --git a/src/cache_lifetime.c b/src/cache_lifetime.c new file mode 100644 index 0000000..ae54df2 --- /dev/null +++ b/src/cache_lifetime.c @@ -0,0 +1,65 @@ +/* + * (C) 2006 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include "conntrackd.h" +#include "us-conntrack.h" +#include "cache.h" +#include "alarm.h" + +static void lifetime_add(struct us_conntrack *u, void *data) +{ + long *lifetime = data; + struct timeval tv; + + gettimeofday(&tv, NULL); + + *lifetime = tv.tv_sec; +} + +static void lifetime_update(struct us_conntrack *u, void *data) +{ +} + +static void lifetime_destroy(struct us_conntrack *u, void *data) +{ +} + +static int lifetime_dump(struct us_conntrack *u, + void *data, + char *buf, + int type) +{ + long *lifetime = data; + struct timeval tv; + + if (type == NFCT_O_XML) + return 0; + + gettimeofday(&tv, NULL); + + return sprintf(buf, " [active since %lds]", tv.tv_sec - *lifetime); +} + +struct cache_feature lifetime_feature = { + .size = sizeof(long), + .add = lifetime_add, + .update = lifetime_update, + .destroy = lifetime_destroy, + .dump = lifetime_dump +}; diff --git a/src/cache_timer.c b/src/cache_timer.c new file mode 100644 index 0000000..213b59a --- /dev/null +++ b/src/cache_timer.c @@ -0,0 +1,72 @@ +/* + * (C) 2006 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include "conntrackd.h" +#include "us-conntrack.h" +#include "cache.h" +#include "alarm.h" + +static void timeout(struct alarm_list *a, void *data) +{ + struct us_conntrack *u = data; + + debug_ct(u->ct, "expired timeout"); + __cache_del(u->cache, u->ct); +} + +static void timer_add(struct us_conntrack *u, void *data) +{ + struct alarm_list *alarm = data; + + init_alarm(alarm); + set_alarm_expiration(alarm, CONFIG(cache_timeout)); + set_alarm_data(alarm, u); + set_alarm_function(alarm, timeout); + add_alarm(alarm); +} + +static void timer_update(struct us_conntrack *u, void *data) +{ + struct alarm_list *alarm = data; + mod_alarm(alarm, CONFIG(cache_timeout)); +} + +static void timer_destroy(struct us_conntrack *u, void *data) +{ + struct alarm_list *alarm = data; + del_alarm(alarm); +} + +static int timer_dump(struct us_conntrack *u, void *data, char *buf, int type) +{ + struct alarm_list *alarm = data; + + if (type == NFCT_O_XML) + return 0; + + return sprintf(buf, " [expires in %ds]", alarm->expires); +} + +struct cache_feature timer_feature = { + .size = sizeof(struct alarm_list), + .add = timer_add, + .update = timer_update, + .destroy = timer_destroy, + .dump = timer_dump +}; diff --git a/src/checksum.c b/src/checksum.c new file mode 100644 index 0000000..41866ff --- /dev/null +++ b/src/checksum.c @@ -0,0 +1,32 @@ +/* + * Extracted from RFC 1071 with some minor changes to fix compilation on GCC, + * this can probably be improved + * --pablo 11/feb/07 + */ + +#include + +unsigned short do_csum(const void *addr, unsigned int count) +{ + unsigned int sum = 0; + + /* checksumming disabled, just skip */ + if (CONFIG(flags) & DONT_CHECKSUM) + return 0; + + while(count > 1) { + /* This is the inner loop */ + sum += *((unsigned short *) addr++); + count -= 2; + } + + /* Add left-over byte, if any */ + if(count > 0) + sum += *((unsigned char *) addr); + + /* Fold 32-bit sum to 16 bits */ + while (sum>>16) + sum = (sum & 0xffff) + (sum >> 16); + + return ~sum; +} diff --git a/src/conntrack.c b/src/conntrack.c new file mode 100644 index 0000000..30fbf69 --- /dev/null +++ b/src/conntrack.c @@ -0,0 +1,1131 @@ +/* + * (C) 2005 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Note: + * Yes, portions of this code has been stolen from iptables ;) + * Special thanks to the the Netfilter Core Team. + * Thanks to Javier de Miguel Rodriguez + * for introducing me to advanced firewalling stuff. + * + * --pablo 13/04/2005 + * + * 2005-04-16 Harald Welte : + * Add support for conntrack accounting and conntrack mark + * 2005-06-23 Harald Welte : + * Add support for expect creation + * 2005-09-24 Harald Welte : + * Remove remaints of "-A" + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_ARPA_INET_H +#include +#endif +#include +#include +#include +#include +#include "linux_list.h" +#include "conntrack.h" +#include +#include +#include + +static const char cmdflags[NUMBER_OF_CMD] += {'L','I','U','D','G','F','E','V','h','L','I','D','G','F','E'}; + +static const char cmd_need_param[NUMBER_OF_CMD] += { 2, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, 0, 2, 2 }; + +static const char optflags[NUMBER_OF_OPT] += {'s','d','r','q','p','t','u','z','e','[',']','{','}','a','m','i','f'}; + +static struct option original_opts[] = { + {"dump", 2, 0, 'L'}, + {"create", 1, 0, 'I'}, + {"delete", 1, 0, 'D'}, + {"update", 1, 0, 'U'}, + {"get", 1, 0, 'G'}, + {"flush", 1, 0, 'F'}, + {"event", 1, 0, 'E'}, + {"version", 0, 0, 'V'}, + {"help", 0, 0, 'h'}, + {"orig-src", 1, 0, 's'}, + {"orig-dst", 1, 0, 'd'}, + {"reply-src", 1, 0, 'r'}, + {"reply-dst", 1, 0, 'q'}, + {"protonum", 1, 0, 'p'}, + {"timeout", 1, 0, 't'}, + {"status", 1, 0, 'u'}, + {"zero", 0, 0, 'z'}, + {"event-mask", 1, 0, 'e'}, + {"tuple-src", 1, 0, '['}, + {"tuple-dst", 1, 0, ']'}, + {"mask-src", 1, 0, '{'}, + {"mask-dst", 1, 0, '}'}, + {"nat-range", 1, 0, 'a'}, + {"mark", 1, 0, 'm'}, + {"id", 2, 0, 'i'}, + {"family", 1, 0, 'f'}, + {0, 0, 0, 0} +}; + +#define OPTION_OFFSET 256 + +static struct nfct_handle *cth; +static struct option *opts = original_opts; +static unsigned int global_option_offset = 0; + +/* Table of legal combinations of commands and options. If any of the + * given commands make an option legal, that option is legal (applies to + * CMD_LIST and CMD_ZERO only). + * Key: + * 0 illegal + * 1 compulsory + * 2 optional + */ + +static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = +/* Well, it's better than "Re: Linux vs FreeBSD" */ +{ + /* s d r q p t u z e x y k l a m i f*/ +/*CT_LIST*/ {2,2,2,2,2,0,0,2,0,0,0,0,0,0,2,2,2}, +/*CT_CREATE*/ {2,2,2,2,1,1,1,0,0,0,0,0,0,2,2,0,0}, +/*CT_UPDATE*/ {2,2,2,2,1,2,2,0,0,0,0,0,0,0,2,2,0}, +/*CT_DELETE*/ {2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,2,0}, +/*CT_GET*/ {2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,2,0}, +/*CT_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*CT_EVENT*/ {2,2,2,2,2,0,0,0,2,0,0,0,0,0,2,0,0}, +/*VERSION*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*HELP*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*EXP_LIST*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2}, +/*EXP_CREATE*/{1,1,2,2,1,1,2,0,0,1,1,1,1,0,0,0,0}, +/*EXP_DELETE*/{1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0}, +/*EXP_GET*/ {1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0}, +/*EXP_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*EXP_EVENT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +}; + +static char *lib_dir = CONNTRACK_LIB_DIR; + +static LIST_HEAD(proto_list); + +void register_proto(struct ctproto_handler *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); +} + +static struct ctproto_handler *findproto(char *name) +{ + struct list_head *i; + struct ctproto_handler *cur = NULL, *handler = NULL; + + if (!name) + return handler; + + lib_dir = getenv("CONNTRACK_LIB_DIR"); + if (!lib_dir) + lib_dir = CONNTRACK_LIB_DIR; + + list_for_each(i, &proto_list) { + cur = (struct ctproto_handler *) i; + if (strcmp(cur->name, name) == 0) { + handler = cur; + break; + } + } + + if (!handler) { + char path[sizeof("ct_proto_.so") + + strlen(name) + strlen(lib_dir)]; + sprintf(path, "%s/ct_proto_%s.so", lib_dir, name); + if (dlopen(path, RTLD_NOW)) + handler = findproto(name); + else + fprintf(stderr, "%s\n", dlerror()); + } + + return handler; +} + +enum exittype { + OTHER_PROBLEM = 1, + PARAMETER_PROBLEM, + VERSION_PROBLEM +}; + +void extension_help(struct ctproto_handler *h) +{ + fprintf(stdout, "\n"); + fprintf(stdout, "Proto `%s' help:\n", h->name); + h->help(); +} + +void +exit_tryhelp(int status) +{ + fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n", + PROGNAME, PROGNAME); + exit(status); +} + +static void +exit_error(enum exittype status, char *msg, ...) +{ + va_list args; + + /* On error paths, make sure that we don't leak the memory + * reserved during options merging */ + if (opts != original_opts) { + free(opts); + opts = original_opts; + global_option_offset = 0; + } + va_start(args, msg); + fprintf(stderr,"%s v%s: ", PROGNAME, VERSION); + vfprintf(stderr, msg, args); + va_end(args); + fprintf(stderr, "\n"); + if (status == PARAMETER_PROBLEM) + exit_tryhelp(status); + exit(status); +} + +static void +generic_cmd_check(int command, int options) +{ + int i; + + for (i = 0; i < NUMBER_OF_CMD; i++) { + if (!(command & (1< illegal, 1 => legal, 0 => undecided. */ + + for (j = 0; j < NUMBER_OF_CMD; j++) { + if (!(command & (1<size; i++) + if (strncasecmp(str, p->parameter[i], strlen) == 0) { + *value |= p->value[i]; + ret = 1; + break; + } + + return ret; +} + +static void +parse_parameter(const char *arg, unsigned int *status, int parse_type) +{ + const char *comma; + + while ((comma = strchr(arg, ',')) != NULL) { + if (comma == arg + || !do_parse_parameter(arg, comma-arg, status, parse_type)) + exit_error(PARAMETER_PROBLEM,"Bad parameter `%s'", arg); + arg = comma+1; + } + + if (strlen(arg) == 0 + || !do_parse_parameter(arg, strlen(arg), status, parse_type)) + exit_error(PARAMETER_PROBLEM, "Bad parameter `%s'", arg); +} + +static void +add_command(unsigned int *cmd, const int newcmd, const int othercmds) +{ + if (*cmd & (~othercmds)) + exit_error(PARAMETER_PROBLEM, "Invalid commands combination\n"); + *cmd |= newcmd; +} + +unsigned int check_type(int argc, char *argv[]) +{ + char *table = NULL; + + /* Nasty bug or feature in getopt_long ? + * It seems that it behaves badly with optional arguments. + * Fortunately, I just stole the fix from iptables ;) */ + if (optarg) + return 0; + else if (optind < argc && argv[optind][0] != '-' + && argv[optind][0] != '!') + table = argv[optind++]; + + if (!table) + return 0; + + if (strncmp("expect", table, 6) == 0) + return 1; + else if (strncmp("conntrack", table, 9) == 0) + return 0; + else + exit_error(PARAMETER_PROBLEM, "unknown type `%s'\n", table); + + return 0; +} + +static void set_family(int *family, int new) +{ + if (*family == AF_UNSPEC) + *family = new; + else if (*family != new) + exit_error(PARAMETER_PROBLEM, "mismatched address family\n"); +} + +struct addr_parse { + struct in_addr addr; + struct in6_addr addr6; + unsigned int family; +}; + +int __parse_inetaddr(const char *cp, struct addr_parse *parse) +{ + if (inet_aton(cp, &parse->addr)) + return AF_INET; +#ifdef HAVE_INET_PTON_IPV6 + else if (inet_pton(AF_INET6, cp, &parse->addr6) > 0) + return AF_INET6; +#endif + + exit_error(PARAMETER_PROBLEM, "Invalid IP address `%s'.", cp); +} + +int parse_inetaddr(const char *cp, union nfct_address *address) +{ + struct addr_parse parse; + int ret; + + if ((ret = __parse_inetaddr(cp, &parse)) == AF_INET) + address->v4 = parse.addr.s_addr; + else if (ret == AF_INET6) + memcpy(address->v6, &parse.addr6, sizeof(parse.addr6)); + + return ret; +} + +/* Shamelessly stolen from libipt_DNAT ;). Ranges expected in network order. */ +static void +nat_parse(char *arg, int portok, struct nfct_nat *range) +{ + char *colon, *dash, *error; + struct addr_parse parse; + + memset(range, 0, sizeof(range)); + colon = strchr(arg, ':'); + + if (colon) { + int port; + + if (!portok) + exit_error(PARAMETER_PROBLEM, + "Need TCP or UDP with port specification"); + + port = atoi(colon+1); + if (port == 0 || port > 65535) + exit_error(PARAMETER_PROBLEM, + "Port `%s' not valid\n", colon+1); + + error = strchr(colon+1, ':'); + if (error) + exit_error(PARAMETER_PROBLEM, + "Invalid port:port syntax - use dash\n"); + + dash = strchr(colon, '-'); + if (!dash) { + range->l4min.tcp.port + = range->l4max.tcp.port + = htons(port); + } else { + int maxport; + + maxport = atoi(dash + 1); + if (maxport == 0 || maxport > 65535) + exit_error(PARAMETER_PROBLEM, + "Port `%s' not valid\n", dash+1); + if (maxport < port) + /* People are stupid. */ + exit_error(PARAMETER_PROBLEM, + "Port range `%s' funky\n", colon+1); + range->l4min.tcp.port = htons(port); + range->l4max.tcp.port = htons(maxport); + } + /* Starts with a colon? No IP info... */ + if (colon == arg) + return; + *colon = '\0'; + } + + dash = strchr(arg, '-'); + if (colon && dash && dash > colon) + dash = NULL; + + if (dash) + *dash = '\0'; + + if (__parse_inetaddr(arg, &parse) != AF_INET) + return; + + range->min_ip = parse.addr.s_addr; + if (dash) { + if (__parse_inetaddr(dash+1, &parse) != AF_INET) + return; + range->max_ip = parse.addr.s_addr; + } else + range->max_ip = parse.addr.s_addr; +} + +static void event_sighandler(int s) +{ + fprintf(stdout, "Now closing conntrack event dumping...\n"); + nfct_close(cth); + exit(0); +} + +static const char usage_commands[] = + "Commands:\n" + " -L [table] [options]\t\tList conntrack or expectation table\n" + " -G [table] parameters\t\tGet conntrack or expectation\n" + " -D [table] parameters\t\tDelete conntrack or expectation\n" + " -I [table] parameters\t\tCreate a conntrack or expectation\n" + " -U [table] parameters\t\tUpdate a conntrack\n" + " -E [table] [options]\t\tShow events\n" + " -F [table]\t\t\tFlush table\n"; + +static const char usage_tables[] = + "Tables: conntrack, expect\n"; + +static const char usage_conntrack_parameters[] = + "Conntrack parameters and options:\n" + " -a, --nat-range min_ip[-max_ip]\tNAT ip range\n" + " -m, --mark mark\t\t\tSet mark\n" + " -e, --event-mask eventmask\t\tEvent mask, eg. NEW,DESTROY\n" + " -z, --zero \t\t\t\tZero counters while listing\n" + ; + +static const char usage_expectation_parameters[] = + "Expectation parameters and options:\n" + " --tuple-src ip\tSource address in expect tuple\n" + " --tuple-dst ip\tDestination address in expect tuple\n" + " --mask-src ip\t\tSource mask address\n" + " --mask-dst ip\t\tDestination mask address\n"; + +static const char usage_parameters[] = + "Common parameters and options:\n" + " -s, --orig-src ip\t\tSource address from original direction\n" + " -d, --orig-dst ip\t\tDestination address from original direction\n" + " -r, --reply-src ip\t\tSource addres from reply direction\n" + " -q, --reply-dst ip\t\tDestination address from reply direction\n" + " -p, --protonum proto\t\tLayer 4 Protocol, eg. 'tcp'\n" + " -f, --family proto\t\tLayer 3 Protocol, eg. 'ipv6'\n" + " -t, --timeout timeout\t\tSet timeout\n" + " -u, --status status\t\tSet status, eg. ASSURED\n" + " -i, --id [id]\t\t\tShow or set conntrack ID\n" + ; + + +void usage(char *prog) { + fprintf(stdout, "Tool to manipulate conntrack and expectations. Version %s\n", VERSION); + fprintf(stdout, "Usage: %s [commands] [options]\n", prog); + + fprintf(stdout, "\n%s", usage_commands); + fprintf(stdout, "\n%s", usage_tables); + fprintf(stdout, "\n%s", usage_conntrack_parameters); + fprintf(stdout, "\n%s", usage_expectation_parameters); + fprintf(stdout, "\n%s", usage_parameters); +} + +#define CT_COMPARISON (CT_OPT_PROTO | CT_OPT_ORIG | CT_OPT_REPL | CT_OPT_MARK) + +static struct nfct_tuple orig, reply, mask; +static struct nfct_tuple exptuple; +static struct ctproto_handler *h; +static union nfct_protoinfo proto; +static struct nfct_nat range; +static struct nfct_conntrack *ct; +static struct nfct_expect *exp; +static unsigned long timeout; +static unsigned int status; +static unsigned int mark; +static unsigned int id = NFCT_ANY_ID; +static struct nfct_conntrack_compare cmp; + +int main(int argc, char *argv[]) +{ + int c; + unsigned int command = 0, options = 0; + unsigned int type = 0, event_mask = 0; + unsigned int l3flags = 0, l4flags = 0, metaflags = 0; + int res = 0; + int family = AF_UNSPEC; + struct nfct_conntrack_compare *pcmp; + + while ((c = getopt_long(argc, argv, + "L::I::U::D::G::E::F::hVs:d:r:q:p:t:u:e:a:z[:]:{:}:m:i::f:", + opts, NULL)) != -1) { + switch(c) { + case 'L': + type = check_type(argc, argv); + if (type == 0) + add_command(&command, CT_LIST, CT_NONE); + else if (type == 1) + add_command(&command, EXP_LIST, CT_NONE); + break; + case 'I': + type = check_type(argc, argv); + if (type == 0) + add_command(&command, CT_CREATE, CT_NONE); + else if (type == 1) + add_command(&command, EXP_CREATE, CT_NONE); + break; + case 'U': + type = check_type(argc, argv); + if (type == 0) + add_command(&command, CT_UPDATE, CT_NONE); + else + exit_error(PARAMETER_PROBLEM, "Can't update " + "expectations"); + break; + case 'D': + type = check_type(argc, argv); + if (type == 0) + add_command(&command, CT_DELETE, CT_NONE); + else if (type == 1) + add_command(&command, EXP_DELETE, CT_NONE); + break; + case 'G': + type = check_type(argc, argv); + if (type == 0) + add_command(&command, CT_GET, CT_NONE); + else if (type == 1) + add_command(&command, EXP_GET, CT_NONE); + break; + case 'F': + type = check_type(argc, argv); + if (type == 0) + add_command(&command, CT_FLUSH, CT_NONE); + else if (type == 1) + add_command(&command, EXP_FLUSH, CT_NONE); + break; + case 'E': + type = check_type(argc, argv); + if (type == 0) + add_command(&command, CT_EVENT, CT_NONE); + else if (type == 1) + add_command(&command, EXP_EVENT, CT_NONE); + break; + case 'V': + add_command(&command, CT_VERSION, CT_NONE); + break; + case 'h': + add_command(&command, CT_HELP, CT_NONE); + break; + case 's': + options |= CT_OPT_ORIG_SRC; + if (optarg) { + orig.l3protonum = + parse_inetaddr(optarg, &orig.src); + set_family(&family, orig.l3protonum); + if (orig.l3protonum == AF_INET) + l3flags |= IPV4_ORIG_SRC; + else if (orig.l3protonum == AF_INET6) + l3flags |= IPV6_ORIG_SRC; + } + break; + case 'd': + options |= CT_OPT_ORIG_DST; + if (optarg) { + orig.l3protonum = + parse_inetaddr(optarg, &orig.dst); + set_family(&family, orig.l3protonum); + if (orig.l3protonum == AF_INET) + l3flags |= IPV4_ORIG_DST; + else if (orig.l3protonum == AF_INET6) + l3flags |= IPV6_ORIG_DST; + } + break; + case 'r': + options |= CT_OPT_REPL_SRC; + if (optarg) { + reply.l3protonum = + parse_inetaddr(optarg, &reply.src); + set_family(&family, reply.l3protonum); + if (orig.l3protonum == AF_INET) + l3flags |= IPV4_REPL_SRC; + else if (orig.l3protonum == AF_INET6) + l3flags |= IPV6_REPL_SRC; + } + break; + case 'q': + options |= CT_OPT_REPL_DST; + if (optarg) { + reply.l3protonum = + parse_inetaddr(optarg, &reply.dst); + set_family(&family, reply.l3protonum); + if (orig.l3protonum == AF_INET) + l3flags |= IPV4_REPL_DST; + else if (orig.l3protonum == AF_INET6) + l3flags |= IPV6_REPL_DST; + } + break; + case 'p': + options |= CT_OPT_PROTO; + h = findproto(optarg); + if (!h) + exit_error(PARAMETER_PROBLEM, "proto needed\n"); + orig.protonum = h->protonum; + reply.protonum = h->protonum; + exptuple.protonum = h->protonum; + mask.protonum = h->protonum; + opts = merge_options(opts, h->opts, + &h->option_offset); + break; + case 't': + options |= CT_OPT_TIMEOUT; + if (optarg) + timeout = atol(optarg); + break; + case 'u': { + if (!optarg) + continue; + + options |= CT_OPT_STATUS; + parse_parameter(optarg, &status, PARSE_STATUS); + break; + } + case 'e': + options |= CT_OPT_EVENT_MASK; + parse_parameter(optarg, &event_mask, PARSE_EVENT); + break; + case 'z': + options |= CT_OPT_ZERO; + break; + case '{': + options |= CT_OPT_MASK_SRC; + if (optarg) { + mask.l3protonum = + parse_inetaddr(optarg, &mask.src); + set_family(&family, mask.l3protonum); + } + break; + case '}': + options |= CT_OPT_MASK_DST; + if (optarg) { + mask.l3protonum = + parse_inetaddr(optarg, &mask.dst); + set_family(&family, mask.l3protonum); + } + break; + case '[': + options |= CT_OPT_EXP_SRC; + if (optarg) { + exptuple.l3protonum = + parse_inetaddr(optarg, &exptuple.src); + set_family(&family, exptuple.l3protonum); + } + break; + case ']': + options |= CT_OPT_EXP_DST; + if (optarg) { + exptuple.l3protonum = + parse_inetaddr(optarg, &exptuple.dst); + set_family(&family, exptuple.l3protonum); + } + break; + case 'a': + options |= CT_OPT_NATRANGE; + set_family(&family, AF_INET); + nat_parse(optarg, 1, &range); + break; + case 'm': + options |= CT_OPT_MARK; + mark = atol(optarg); + metaflags |= NFCT_MARK; + break; + case 'i': { + char *s = NULL; + options |= CT_OPT_ID; + if (optarg) + break; + else if (optind < argc && argv[optind][0] != '-' + && argv[optind][0] != '!') + s = argv[optind++]; + + if (s) + id = atol(s); + break; + } + case 'f': + options |= CT_OPT_FAMILY; + if (strncmp(optarg, "ipv4", strlen("ipv4")) == 0) + set_family(&family, AF_INET); + else if (strncmp(optarg, "ipv6", strlen("ipv6")) == 0) + set_family(&family, AF_INET6); + else + exit_error(PARAMETER_PROBLEM, "Unknown " + "protocol family\n"); + break; + default: + if (h && h->parse_opts + &&!h->parse_opts(c - h->option_offset, argv, &orig, + &reply, &exptuple, &mask, &proto, + &l4flags)) + exit_error(PARAMETER_PROBLEM, "parse error\n"); + + /* Unknown argument... */ + if (!h) { + usage(argv[0]); + exit_error(PARAMETER_PROBLEM, "Missing " + "arguments...\n"); + } + break; + } + } + + /* default family */ + if (family == AF_UNSPEC) + family = AF_INET; + + generic_cmd_check(command, options); + generic_opt_check(command, options); + + if (!(command & CT_HELP) + && h && h->final_check + && !h->final_check(l4flags, command, &orig, &reply)) { + usage(argv[0]); + extension_help(h); + exit_error(PARAMETER_PROBLEM, "Missing protocol arguments!\n"); + } + + switch(command) { + + case CT_LIST: + cth = nfct_open(CONNTRACK, 0); + if (!cth) + exit_error(OTHER_PROBLEM, "Can't open handler"); + + if (options & CT_COMPARISON) { + + if (options & CT_OPT_ZERO) + exit_error(PARAMETER_PROBLEM, "Can't use -z " + "with filtering parameters"); + + ct = nfct_conntrack_alloc(&orig, &reply, timeout, + &proto, status, mark, id, + NULL); + if (!ct) + exit_error(OTHER_PROBLEM, "Not enough memory"); + + cmp.ct = ct; + cmp.flags = metaflags; + cmp.l3flags = l3flags; + cmp.l4flags = l4flags; + pcmp = &cmp; + } + + if (options & CT_OPT_ID) + nfct_register_callback(cth, + nfct_default_conntrack_display_id, + (void *) pcmp); + else + nfct_register_callback(cth, + nfct_default_conntrack_display, + (void *) pcmp); + + if (options & CT_OPT_ZERO) + res = + nfct_dump_conntrack_table_reset_counters(cth, family); + else + res = nfct_dump_conntrack_table(cth, family); + nfct_close(cth); + break; + + case EXP_LIST: + cth = nfct_open(EXPECT, 0); + if (!cth) + exit_error(OTHER_PROBLEM, "Can't open handler"); + if (options & CT_OPT_ID) + nfct_register_callback(cth, + nfct_default_expect_display_id, + NULL); + else + nfct_register_callback(cth, + nfct_default_expect_display, + NULL); + res = nfct_dump_expect_list(cth, family); + nfct_close(cth); + break; + + case CT_CREATE: + if ((options & CT_OPT_ORIG) + && !(options & CT_OPT_REPL)) { + reply.l3protonum = orig.l3protonum; + memcpy(&reply.src, &orig.dst, sizeof(reply.src)); + memcpy(&reply.dst, &orig.src, sizeof(reply.dst)); + } else if (!(options & CT_OPT_ORIG) + && (options & CT_OPT_REPL)) { + orig.l3protonum = reply.l3protonum; + memcpy(&orig.src, &reply.dst, sizeof(orig.src)); + memcpy(&orig.dst, &reply.src, sizeof(orig.dst)); + } + if (options & CT_OPT_NATRANGE) + ct = nfct_conntrack_alloc(&orig, &reply, timeout, + &proto, status, mark, id, + &range); + else + ct = nfct_conntrack_alloc(&orig, &reply, timeout, + &proto, status, mark, id, + NULL); + if (!ct) + exit_error(OTHER_PROBLEM, "Not Enough memory"); + + cth = nfct_open(CONNTRACK, 0); + if (!cth) { + nfct_conntrack_free(ct); + exit_error(OTHER_PROBLEM, "Can't open handler"); + } + res = nfct_create_conntrack(cth, ct); + nfct_close(cth); + nfct_conntrack_free(ct); + break; + + case EXP_CREATE: + if (options & CT_OPT_ORIG) + exp = nfct_expect_alloc(&orig, &exptuple, + &mask, timeout, id); + else if (options & CT_OPT_REPL) + exp = nfct_expect_alloc(&reply, &exptuple, + &mask, timeout, id); + if (!exp) + exit_error(OTHER_PROBLEM, "Not enough memory"); + + cth = nfct_open(EXPECT, 0); + if (!cth) { + nfct_expect_free(exp); + exit_error(OTHER_PROBLEM, "Can't open handler"); + } + res = nfct_create_expectation(cth, exp); + nfct_expect_free(exp); + nfct_close(cth); + break; + + case CT_UPDATE: + if ((options & CT_OPT_ORIG) + && !(options & CT_OPT_REPL)) { + reply.l3protonum = orig.l3protonum; + memcpy(&reply.src, &orig.dst, sizeof(reply.src)); + memcpy(&reply.dst, &orig.src, sizeof(reply.dst)); + } else if (!(options & CT_OPT_ORIG) + && (options & CT_OPT_REPL)) { + orig.l3protonum = reply.l3protonum; + memcpy(&orig.src, &reply.dst, sizeof(orig.src)); + memcpy(&orig.dst, &reply.src, sizeof(orig.dst)); + } + ct = nfct_conntrack_alloc(&orig, &reply, timeout, + &proto, status, mark, id, + NULL); + if (!ct) + exit_error(OTHER_PROBLEM, "Not enough memory"); + + cth = nfct_open(CONNTRACK, 0); + if (!cth) { + nfct_conntrack_free(ct); + exit_error(OTHER_PROBLEM, "Can't open handler"); + } + res = nfct_update_conntrack(cth, ct); + nfct_conntrack_free(ct); + nfct_close(cth); + break; + + case CT_DELETE: + if (!(options & CT_OPT_ORIG) && !(options & CT_OPT_REPL)) + exit_error(PARAMETER_PROBLEM, "Can't kill conntracks " + "just by its ID"); + cth = nfct_open(CONNTRACK, 0); + if (!cth) + exit_error(OTHER_PROBLEM, "Can't open handler"); + if (options & CT_OPT_ORIG) + res = nfct_delete_conntrack(cth, &orig, + NFCT_DIR_ORIGINAL, + id); + else if (options & CT_OPT_REPL) + res = nfct_delete_conntrack(cth, &reply, + NFCT_DIR_REPLY, + id); + nfct_close(cth); + break; + + case EXP_DELETE: + cth = nfct_open(EXPECT, 0); + if (!cth) + exit_error(OTHER_PROBLEM, "Can't open handler"); + if (options & CT_OPT_ORIG) + res = nfct_delete_expectation(cth, &orig, id); + else if (options & CT_OPT_REPL) + res = nfct_delete_expectation(cth, &reply, id); + nfct_close(cth); + break; + + case CT_GET: + cth = nfct_open(CONNTRACK, 0); + if (!cth) + exit_error(OTHER_PROBLEM, "Can't open handler"); + nfct_register_callback(cth, nfct_default_conntrack_display, + NULL); + if (options & CT_OPT_ORIG) + res = nfct_get_conntrack(cth, &orig, + NFCT_DIR_ORIGINAL, id); + else if (options & CT_OPT_REPL) + res = nfct_get_conntrack(cth, &reply, + NFCT_DIR_REPLY, id); + nfct_close(cth); + break; + + case EXP_GET: + cth = nfct_open(EXPECT, 0); + if (!cth) + exit_error(OTHER_PROBLEM, "Can't open handler"); + nfct_register_callback(cth, nfct_default_expect_display, + NULL); + if (options & CT_OPT_ORIG) + res = nfct_get_expectation(cth, &orig, id); + else if (options & CT_OPT_REPL) + res = nfct_get_expectation(cth, &reply, id); + nfct_close(cth); + break; + + case CT_FLUSH: + cth = nfct_open(CONNTRACK, 0); + if (!cth) + exit_error(OTHER_PROBLEM, "Can't open handler"); + res = nfct_flush_conntrack_table(cth, AF_INET); + nfct_close(cth); + break; + + case EXP_FLUSH: + cth = nfct_open(EXPECT, 0); + if (!cth) + exit_error(OTHER_PROBLEM, "Can't open handler"); + res = nfct_flush_expectation_table(cth, AF_INET); + nfct_close(cth); + break; + + case CT_EVENT: + if (options & CT_OPT_EVENT_MASK) + cth = nfct_open(CONNTRACK, event_mask); + else + cth = nfct_open(CONNTRACK, NFCT_ALL_CT_GROUPS); + + if (!cth) + exit_error(OTHER_PROBLEM, "Can't open handler"); + signal(SIGINT, event_sighandler); + + if (options & CT_COMPARISON) { + ct = nfct_conntrack_alloc(&orig, &reply, timeout, + &proto, status, mark, id, + NULL); + if (!ct) + exit_error(OTHER_PROBLEM, "Not enough memory"); + + cmp.ct = ct; + cmp.flags = metaflags; + cmp.l3flags = l3flags; + cmp.l4flags = l4flags; + pcmp = &cmp; + } + + nfct_register_callback(cth, + nfct_default_conntrack_event_display, + (void *) pcmp); + res = nfct_event_conntrack(cth); + nfct_close(cth); + break; + + case EXP_EVENT: + cth = nfct_open(EXPECT, NF_NETLINK_CONNTRACK_EXP_NEW); + if (!cth) + exit_error(OTHER_PROBLEM, "Can't open handler"); + signal(SIGINT, event_sighandler); + nfct_register_callback(cth, nfct_default_expect_display, + NULL); + res = nfct_event_expectation(cth); + nfct_close(cth); + break; + + case CT_VERSION: + fprintf(stdout, "%s v%s\n", PROGNAME, VERSION); + break; + case CT_HELP: + usage(argv[0]); + if (options & CT_OPT_PROTO) + extension_help(h); + break; + default: + usage(argv[0]); + break; + } + + if (opts != original_opts) { + free(opts); + opts = original_opts; + global_option_offset = 0; + } + + if (res < 0) { + fprintf(stderr, "Operation failed: %s\n", err2str(res, command)); + exit(OTHER_PROBLEM); + } + + return 0; +} diff --git a/src/hash.c b/src/hash.c new file mode 100644 index 0000000..274a140 --- /dev/null +++ b/src/hash.c @@ -0,0 +1,199 @@ +/* + * (C) 2006-2007 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Description: generic hash table implementation + */ + +#include +#include +#include +#include +#include +#include "slist.h" +#include "hash.h" + + +struct hashtable_node *hashtable_alloc_node(int datasize, void *data) +{ + struct hashtable_node *n; + int size = sizeof(struct hashtable_node) + datasize; + + n = malloc(size); + if (!n) + return NULL; + memset(n, 0, size); + memcpy(n->data, data, datasize); + + return n; +} + +void hashtable_destroy_node(struct hashtable_node *h) +{ + free(h); +} + +struct hashtable * +hashtable_create(int hashsize, int limit, int datasize, + u_int32_t (*hash)(const void *data, struct hashtable *table), + int (*compare)(const void *data1, const void *data2)) +{ + int i; + struct hashtable *h; + struct hashtype *t; + int size = sizeof(struct hashtable) + + hashsize * sizeof(struct slist_head); + + h = (struct hashtable *) malloc(size); + if (!h) { + errno = ENOMEM; + return NULL; + } + + memset(h, 0, size); + for (i=0; imembers[i]); + + h->hashsize = hashsize; + h->limit = limit; + h->datasize = datasize; + h->hash = hash; + h->compare = compare; + + return h; +} + +void hashtable_destroy(struct hashtable *h) +{ + hashtable_flush(h); + free(h); +} + +void *hashtable_add(struct hashtable *table, void *data) +{ + struct slist_head *e; + struct hashtable_node *n; + u_int32_t id; + int i; + + /* hash table is full */ + if (table->count >= table->limit) { + errno = ENOSPC; + return NULL; + } + + id = table->hash(data, table); + + slist_for_each(e, &table->members[id]) { + n = slist_entry(e, struct hashtable_node, head); + if (table->compare(n->data, data)) { + errno = EEXIST; + return NULL; + } + } + + n = hashtable_alloc_node(table->datasize, data); + if (n == NULL) { + errno = ENOMEM; + return NULL; + } + + slist_add(&table->members[id], &n->head); + table->count++; + + return n->data; +} + +void *hashtable_test(struct hashtable *table, const void *data) +{ + struct slist_head *e; + u_int32_t id; + struct hashtable_node *n; + int i; + + id = table->hash(data, table); + + slist_for_each(e, &table->members[id]) { + n = slist_entry(e, struct hashtable_node, head); + if (table->compare(n->data, data)) + return n->data; + } + + errno = ENOENT; + return NULL; +} + +int hashtable_del(struct hashtable *table, void *data) +{ + struct slist_head *e, *next, *prev; + u_int32_t id; + struct hashtable_node *n; + int i; + + id = table->hash(data, table); + + slist_for_each_safe(e, prev, next, &table->members[id]) { + n = slist_entry(e, struct hashtable_node, head); + if (table->compare(n->data, data)) { + slist_del(e, prev); + hashtable_destroy_node(n); + table->count--; + return 0; + } + } + errno = ENOENT; + return -1; +} + +int hashtable_flush(struct hashtable *table) +{ + int i; + struct slist_head *e, *next, *prev; + struct hashtable_node *n; + + for (i=0; i < table->hashsize; i++) + slist_for_each_safe(e, prev, next, &table->members[i]) { + n = slist_entry(e, struct hashtable_node, head); + slist_del(e, prev); + hashtable_destroy_node(n); + } + + table->count = 0; + + return 0; +} + +int hashtable_iterate(struct hashtable *table, void *data, + int (*iterate)(void *data1, void *data2)) +{ + int i; + struct slist_head *e, *next, *prev; + struct hashtable_node *n; + + for (i=0; i < table->hashsize; i++) { + slist_for_each_safe(e, prev, next, &table->members[i]) { + n = slist_entry(e, struct hashtable_node, head); + if (iterate(data, n->data) == -1) + return -1; + } + } + return 0; +} + +unsigned int hashtable_counter(struct hashtable *table) +{ + return table->count; +} diff --git a/src/ignore_pool.c b/src/ignore_pool.c new file mode 100644 index 0000000..5946617 --- /dev/null +++ b/src/ignore_pool.c @@ -0,0 +1,136 @@ +/* + * (C) 2006-2007 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "jhash.h" +#include "hash.h" +#include "conntrackd.h" +#include "ignore.h" +#include "debug.h" +#include + +#define IGNORE_POOL_SIZE 32 +#define IGNORE_POOL_LIMIT 1024 + +static u_int32_t hash(const void *data, struct hashtable *table) +{ + const u_int32_t *ip = data; + + return jhash_1word(*ip, 0) % table->hashsize; +} + +static u_int32_t hash6(const void *data, struct hashtable *table) +{ + return jhash(data, sizeof(u_int32_t)*4, 0) % table->hashsize; +} + +static int compare(const void *data1, const void *data2) +{ + const u_int32_t *ip1 = data1; + const u_int32_t *ip2 = data2; + + return *ip1 == *ip2; +} + +static int compare6(const void *data1, const void *data2) +{ + return memcmp(data1, data2, sizeof(u_int32_t)*4) == 0; +} + +struct ignore_pool *ignore_pool_create(u_int8_t proto) +{ + int i, j = 0; + struct ignore_pool *ip; + + ip = malloc(sizeof(struct ignore_pool)); + if (!ip) + return NULL; + memset(ip, 0, sizeof(struct ignore_pool)); + + switch(proto) { + case AF_INET: + ip->h = hashtable_create(IGNORE_POOL_SIZE, + IGNORE_POOL_LIMIT, + sizeof(u_int32_t), + hash, + compare); + break; + case AF_INET6: + ip->h = hashtable_create(IGNORE_POOL_SIZE, + IGNORE_POOL_LIMIT, + sizeof(u_int32_t)*4, + hash6, + compare6); + break; + } + + if (!ip->h) { + free(ip); + return NULL; + } + + return ip; +} + +void ignore_pool_destroy(struct ignore_pool *ip) +{ + hashtable_destroy(ip->h); + free(ip); +} + +int ignore_pool_add(struct ignore_pool *ip, void *data) +{ + if (!hashtable_add(ip->h, data)) + return 0; + + return 1; +} + +int __ignore_pool_test_ipv4(struct ignore_pool *ip, struct nf_conntrack *ct) +{ + return (hashtable_test(ip->h, nfct_get_attr(ct, ATTR_ORIG_IPV4_SRC)) || + hashtable_test(ip->h, nfct_get_attr(ct, ATTR_ORIG_IPV4_DST)) || + hashtable_test(ip->h, nfct_get_attr(ct, ATTR_REPL_IPV4_SRC)) || + hashtable_test(ip->h, nfct_get_attr(ct, ATTR_REPL_IPV4_DST))); +} + +int __ignore_pool_test_ipv6(struct ignore_pool *ip, struct nf_conntrack *ct) +{ + return (hashtable_test(ip->h, nfct_get_attr(ct, ATTR_ORIG_IPV6_SRC)) || + hashtable_test(ip->h, nfct_get_attr(ct, ATTR_ORIG_IPV6_DST)) || + hashtable_test(ip->h, nfct_get_attr(ct, ATTR_REPL_IPV6_SRC)) || + hashtable_test(ip->h, nfct_get_attr(ct, ATTR_REPL_IPV6_DST))); +} + +int ignore_pool_test(struct ignore_pool *ip, struct nf_conntrack *ct) +{ + int ret; + + switch(nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO)) { + case AF_INET: + ret = __ignore_pool_test_ipv4(ip, ct); + break; + case AF_INET6: + ret = __ignore_pool_test_ipv6(ip, ct); + break; + default: + dlog(STATE(log), "unknown conntrack layer 3 protocol?"); + break; + } + + return ret; +} diff --git a/src/local.c b/src/local.c new file mode 100644 index 0000000..eef70ad --- /dev/null +++ b/src/local.c @@ -0,0 +1,159 @@ +/* + * (C) 2006 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Description: UNIX sockets library + */ + +#include +#include +#include +#include +#include "debug.h" + +#include "local.h" + +int local_server_create(struct local_conf *conf) +{ + int fd; + int len; + struct sockaddr_un local; + + if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + debug("local_server_create:socket"); + return -1; + } + + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &conf->reuseaddr, + sizeof(conf->reuseaddr)) == -1) { + debug("local_server_create:setsockopt"); + close(fd); + return -1; + } + + local.sun_family = AF_UNIX; + strcpy(local.sun_path, conf->path); + len = strlen(local.sun_path) + sizeof(local.sun_family); + unlink(conf->path); + + if (bind(fd, (struct sockaddr *) &local, len) == -1) { + debug("local_server_create:bind"); + close(fd); + return -1; + } + + if (listen(fd, conf->backlog) == -1) { + close(fd); + debug("local_server_create:listen"); + return -1; + } + + return fd; +} + +void local_server_destroy(int fd) +{ + close(fd); +} + +int do_local_server_step(int fd, void *data, + void (*process)(int fd, void *data)) +{ + int rfd; + struct sockaddr_un local; + size_t sin_size = sizeof(struct sockaddr_un); + + if ((rfd = accept(fd, (struct sockaddr *)&local, &sin_size)) == -1) { + debug("do_local_server_step:accept"); + return -1; + } + + process(rfd, data); + close(rfd); + + return 0; +} + +int local_client_create(struct local_conf *conf) +{ + int len; + struct sockaddr_un local; + int fd; + + if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) + return -1; + + local.sun_family = AF_UNIX; + strcpy(local.sun_path, conf->path); + len = strlen(local.sun_path) + sizeof(local.sun_family); + + if (connect(fd, (struct sockaddr *) &local, len) == -1) { + close(fd); + debug("local_client_create: connect: "); + return -1; + } + + return fd; +} + +void local_client_destroy(int fd) +{ + close(fd); +} + +int do_local_client_step(int fd, void (*process)(char *buf)) +{ + int numbytes; + char buf[1024]; + + memset(buf, 0, sizeof(buf)); + while ((numbytes = recv(fd, buf, sizeof(buf)-1, 0)) > 0) { + buf[sizeof(buf)-1] = '\0'; + if (process) + process(buf); + memset(buf, 0, sizeof(buf)); + } + + return 0; +} + +void local_step(char *buf) +{ + printf(buf); +} + +int do_local_request(int request, + struct local_conf *conf, + void (*step)(char *buf)) +{ + int fd, ret; + + fd = local_client_create(conf); + if (fd == -1) + return -1; + + ret = send(fd, &request, sizeof(int), 0); + if (ret == -1) { + debug("send:"); + return -1; + } + + do_local_client_step(fd, step); + + local_client_destroy(fd); + + return 0; +} diff --git a/src/lock.c b/src/lock.c new file mode 100644 index 0000000..cd68baf --- /dev/null +++ b/src/lock.c @@ -0,0 +1,32 @@ +/* + * (C) 2006 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include + +static pthread_mutex_t global_lock = PTHREAD_MUTEX_INITIALIZER; + +void lock() +{ + pthread_mutex_lock(&global_lock); +} + +void unlock() +{ + pthread_mutex_unlock(&global_lock); +} diff --git a/src/log.c b/src/log.c new file mode 100644 index 0000000..88cadea --- /dev/null +++ b/src/log.c @@ -0,0 +1,57 @@ +/* + * (C) 2006 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Description: Logging support for the conntrack daemon + */ + +#include +#include +#include +#include + +FILE *init_log(char *filename) +{ + FILE *fd; + + fd = fopen(filename, "a+"); + if (fd == NULL) { + fprintf(stderr, "can't open log file `%s'\n", filename); + return NULL; + } + + return fd; +} + +void dlog(FILE *fd, char *format, ...) +{ + time_t t = time(NULL); + char *buf = ctime(&t); + va_list args; + + buf[strlen(buf)-1]='\0'; + va_start(args, format); + fprintf(fd, "[%s] (pid=%d) ", buf, getpid()); + vfprintf(fd, format, args); + va_end(args); + fprintf(fd, "\n"); + fflush(fd); +} + +void close_log(FILE *fd) +{ + fclose(fd); +} diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..1c75970 --- /dev/null +++ b/src/main.c @@ -0,0 +1,302 @@ +/* + * (C) 2006-2007 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include "conntrackd.h" +#include "log.h" +#include +#include +#include +#include +#include +#include +#include "hash.h" +#include "jhash.h" + +struct ct_general_state st; +union ct_state state; + +static const char usage_daemon_commands[] = + "Daemon mode commands:\n" + " -d [options]\t\tRun in daemon mode\n" + " -S [options]\t\tRun in statistics mode\n"; + +static const char usage_client_commands[] = + "Client mode commands:\n" + " -c, commit external cache to conntrack table\n" + " -f, flush internal and external cache\n" + " -F, flush kernel conntrack table\n" + " -i, display content of the internal cache\n" + " -e, display the content of the external cache\n" + " -k, kill conntrack daemon\n" + " -s, dump statistics\n" + " -R, resync with kernel conntrack table\n" + " -n, request resync with other node (only NACK mode)\n" + " -x, dump cache in XML format (requires -i or -e)"; + +static const char usage_options[] = + "Options:\n" + " -C [configfile], configuration file path\n"; + +void show_usage(char *progname) +{ + fprintf(stdout, "Connection tracking userspace daemon v%s\n", VERSION); + fprintf(stdout, "Usage: %s [commands] [options]\n\n", progname); + fprintf(stdout, "%s\n", usage_daemon_commands); + fprintf(stdout, "%s\n", usage_client_commands); + fprintf(stdout, "%s\n", usage_options); +} + +/* These live in run.c */ +int init(int); +void run(void); + +void set_operation_mode(int *current, int want, char *argv[]) +{ + if (*current == NOT_SET) { + *current = want; + return; + } + if (*current != want) { + show_usage(argv[0]); + fprintf(stderr, "\nError: Invalid parameters\n"); + exit(EXIT_FAILURE); + } +} + +static int check_capabilities(void) +{ + int ret; + cap_user_header_t hcap; + cap_user_data_t dcap; + + hcap = malloc(sizeof(cap_user_header_t)); + if (!hcap) + return -1; + + hcap->version = _LINUX_CAPABILITY_VERSION; + hcap->pid = getpid(); + + dcap = malloc(sizeof(cap_user_data_t)); + if (!dcap) { + free(hcap); + return -1; + } + + if (capget(hcap, dcap) == -1) { + free(hcap); + free(dcap); + return -1; + } + + ret = dcap->permitted & (1 << CAP_NET_ADMIN); + + free(hcap); + free(dcap); + + return ret; +} + +int main(int argc, char *argv[]) +{ + int ret, i, config_set = 0, action; + char config_file[PATH_MAX]; + int type = 0, mode = 0; + struct utsname u; + int version, major, minor; + + /* Check kernel version: it must be >= 2.6.18 */ + if (uname(&u) == -1) { + fprintf(stderr, "Can't retrieve kernel version via uname()\n"); + exit(EXIT_FAILURE); + } + sscanf(u.release, "%d.%d.%d", &version, &major, &minor); + if (version < 2 && major < 6) { + fprintf(stderr, "Linux kernel version must be >= 2.6.18\n"); + exit(EXIT_FAILURE); + } + + if (major == 6 && minor < 18) { + fprintf(stderr, "Linux kernel version must be >= 2.6.18\n"); + exit(EXIT_FAILURE); + } + + ret = check_capabilities(); + switch (ret) { + case -1: + fprintf(stderr, "Can't get capabilities\n"); + exit(EXIT_FAILURE); + break; + case 0: + fprintf(stderr, "You require CAP_NET_ADMIN in order " + "to run conntrackd\n"); + exit(EXIT_FAILURE); + break; + default: + break; + } + + for (i=1; i= PATH_MAX){ + config_file[PATH_MAX-1]='\0'; + fprintf(stderr, "Path to config file " + "to long. Cutting it " + "down to %d characters", + PATH_MAX); + } + config_set = 1; + break; + } + show_usage(argv[0]); + fprintf(stderr, "Missing config filename\n"); + break; + case 'F': + set_operation_mode(&type, REQUEST, argv); + action = FLUSH_MASTER; + case 'f': + set_operation_mode(&type, REQUEST, argv); + action = FLUSH_CACHE; + break; + case 'R': + set_operation_mode(&type, REQUEST, argv); + action = RESYNC_MASTER; + break; + case 'B': + set_operation_mode(&type, REQUEST, argv); + action = SEND_BULK; + break; + case 'k': + set_operation_mode(&type, REQUEST, argv); + action = KILL; + break; + case 's': + set_operation_mode(&type, REQUEST, argv); + action = STATS; + break; + case 'S': + set_operation_mode(&mode, STATS_MODE, argv); + break; + case 'n': + set_operation_mode(&type, REQUEST, argv); + action = REQUEST_DUMP; + break; + case 'x': + if (action == DUMP_INTERNAL) + action = DUMP_INT_XML; + else if (action == DUMP_EXTERNAL) + action = DUMP_EXT_XML; + else { + show_usage(argv[0]); + fprintf(stderr, "Error: Invalid parameters\n"); + exit(EXIT_FAILURE); + + } + break; + default: + show_usage(argv[0]); + fprintf(stderr, "Unknown option: %s\n", argv[i]); + return 0; + break; + } + } + + if (config_set == 0) + strcpy(config_file, DEFAULT_CONFIGFILE); + + if ((ret = init_config(config_file)) == -1) { + fprintf(stderr, "can't open config file `%s'\n", config_file); + exit(EXIT_FAILURE); + } + + /* + * Setting up logfile + */ + STATE(log) = init_log(CONFIG(logfile)); + if (!STATE(log)) { + fprintf(stdout, "can't open logfile `%s\n'", CONFIG(logfile)); + exit(EXIT_FAILURE); + } + + if (type == REQUEST) { + if (do_local_request(action, &conf.local, local_step) == -1) + fprintf(stderr, "can't connect: is conntrackd " + "running? appropiate permissions?\n"); + exit(EXIT_SUCCESS); + } + + /* + * lock file + */ + if ((ret = open(CONFIG(lockfile), O_CREAT | O_EXCL | O_TRUNC)) == -1) { + fprintf(stderr, "lockfile `%s' exists, perhaps conntrackd " + "already running?\n", CONFIG(lockfile)); + exit(EXIT_FAILURE); + } + close(ret); + + /* Daemonize conntrackd */ + if (type == DAEMON) { + pid_t pid; + + if ((pid = fork()) == -1) { + dlog(STATE(log), "fork() failed: " + "%s", strerror(errno)); + exit(EXIT_FAILURE); + } else if (pid) + exit(EXIT_SUCCESS); + + dlog(STATE(log), "--- starting in daemon mode ---"); + } else + dlog(STATE(log), "--- starting in console mode ---"); + + /* + * initialization process + */ + + if (init(mode) == -1) { + close_log(STATE(log)); + fprintf(stderr, "ERROR: conntrackd cannot start, please " + "check the logfile for more info\n"); + unlink(CONFIG(lockfile)); + exit(EXIT_FAILURE); + } + + /* + * run main process + */ + run(); +} diff --git a/src/mcast.c b/src/mcast.c new file mode 100644 index 0000000..9904544 --- /dev/null +++ b/src/mcast.c @@ -0,0 +1,287 @@ +/* + * (C) 2006 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Description: multicast socket library + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mcast.h" +#include "debug.h" + +struct mcast_sock *mcast_server_create(struct mcast_conf *conf) +{ + int yes = 1; + union { + struct ip_mreq ipv4; + struct ipv6_mreq ipv6; + } mreq; + struct mcast_sock *m; + + m = (struct mcast_sock *) malloc(sizeof(struct mcast_sock)); + if (!m) + return NULL; + memset(m, 0, sizeof(struct mcast_sock)); + + switch(conf->ipproto) { + case AF_INET: + mreq.ipv4.imr_multiaddr.s_addr = conf->in.inet_addr.s_addr; + mreq.ipv4.imr_interface.s_addr =conf->ifa.interface_addr.s_addr; + + m->addr.ipv4.sin_family = AF_INET; + m->addr.ipv4.sin_port = htons(conf->port); + m->addr.ipv4.sin_addr.s_addr = htonl(INADDR_ANY); + break; + + case AF_INET6: + memcpy(&mreq.ipv6.ipv6mr_multiaddr, &conf->in.inet_addr6, + sizeof(u_int32_t) * 4); + memcpy(&mreq.ipv6.ipv6mr_interface, &conf->ifa.interface_addr6, + sizeof(u_int32_t) * 4); + + m->addr.ipv6.sin6_family = AF_INET6; + m->addr.ipv6.sin6_port = htons(conf->port); + m->addr.ipv6.sin6_addr = in6addr_any; + break; + } + + if ((m->fd = socket(conf->ipproto, SOCK_DGRAM, 0)) == -1) { + debug("mcast_sock_server_create:socket"); + free(m); + return NULL; + } + + if (setsockopt(m->fd, SOL_SOCKET, SO_REUSEADDR, &yes, + sizeof(int)) == -1) { + debug("mcast_sock_server_create:setsockopt1"); + close(m->fd); + free(m); + return NULL; + } + + if (bind(m->fd, (struct sockaddr *) &m->addr, + sizeof(struct sockaddr)) == -1) { + debug("mcast_sock_server_create:bind"); + close(m->fd); + free(m); + return NULL; + } + + + switch(conf->ipproto) { + case AF_INET: + if (setsockopt(m->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, + &mreq.ipv4, sizeof(mreq.ipv4)) < 0) { + debug("mcast_sock_server_create:setsockopt2"); + close(m->fd); + free(m); + return NULL; + } + break; + case AF_INET6: + if (setsockopt(m->fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, + &mreq.ipv6, sizeof(mreq.ipv6)) < 0) { + debug("mcast_sock_server_create:setsockopt2"); + close(m->fd); + free(m); + return NULL; + } + break; + } + + return m; +} + +void mcast_server_destroy(struct mcast_sock *m) +{ + close(m->fd); + free(m); +} + +static int +__mcast_client_create_ipv4(struct mcast_sock *m, struct mcast_conf *conf) +{ + int no = 0; + + m->addr.ipv4.sin_family = AF_INET; + m->addr.ipv4.sin_port = htons(conf->port); + m->addr.ipv4.sin_addr = conf->in.inet_addr; + + if (setsockopt(m->fd, IPPROTO_IP, IP_MULTICAST_LOOP, &no, + sizeof(int)) < 0) { + debug("mcast_sock_client_create:setsockopt2"); + close(m->fd); + return -1; + } + + if (setsockopt(m->fd, IPPROTO_IP, IP_MULTICAST_IF, + &conf->ifa.interface_addr, + sizeof(struct in_addr)) == -1) { + debug("mcast_sock_client_create:setsockopt3"); + close(m->fd); + free(m); + return -1; + } + + return 0; +} + +static int +__mcast_client_create_ipv6(struct mcast_sock *m, struct mcast_conf *conf) +{ + int no = 0; + + m->addr.ipv6.sin6_family = AF_INET6; + m->addr.ipv6.sin6_port = htons(conf->port); + memcpy(&m->addr.ipv6.sin6_addr, + &conf->in.inet_addr6, + sizeof(struct in6_addr)); + + if (setsockopt(m->fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &no, + sizeof(int)) < 0) { + debug("mcast_sock_client_create:setsockopt2"); + close(m->fd); + return -1; + } + + if (setsockopt(m->fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, + &conf->ifa.interface_addr, + sizeof(struct in_addr)) == -1) { + debug("mcast_sock_client_create:setsockopt3"); + close(m->fd); + free(m); + return -1; + } + + return 0; +} + +struct mcast_sock *mcast_client_create(struct mcast_conf *conf) +{ + int ret = 0; + struct sockaddr_in addr; + struct mcast_sock *m; + + m = (struct mcast_sock *) malloc(sizeof(struct mcast_sock)); + if (!m) + return NULL; + memset(m, 0, sizeof(struct mcast_sock)); + + if ((m->fd = socket(conf->ipproto, SOCK_DGRAM, 0)) == -1) { + debug("mcast_sock_client_create:socket"); + return NULL; + } + + switch(conf->ipproto) { + case AF_INET: + ret = __mcast_client_create_ipv4(m, conf); + break; + case AF_INET6: + ret = __mcast_client_create_ipv6(m, conf); + break; + default: + break; + } + + if (ret == -1) { + free(m); + m = NULL; + } + + return m; +} + +void mcast_client_destroy(struct mcast_sock *m) +{ + close(m->fd); + free(m); +} + +int mcast_send(struct mcast_sock *m, void *data, int size) +{ + int ret; + + ret = sendto(m->fd, + data, + size, + 0, + (struct sockaddr *) &m->addr, + sizeof(struct sockaddr)); + if (ret == -1) { + debug("mcast_sock_send"); + m->stats.error++; + return ret; + } + + m->stats.bytes += ret; + m->stats.messages++; + + return ret; +} + +int mcast_recv(struct mcast_sock *m, void *data, int size) +{ + int ret; + socklen_t sin_size = sizeof(struct sockaddr_in); + + ret = recvfrom(m->fd, + data, + size, + 0, + (struct sockaddr *)&m->addr, + &sin_size); + if (ret == -1) { + debug("mcast_sock_recv"); + m->stats.error++; + return ret; + } + + m->stats.bytes += ret; + m->stats.messages++; + + return ret; +} + +struct mcast_stats *mcast_get_stats(struct mcast_sock *m) +{ + return &m->stats; +} + +void mcast_dump_stats(int fd, struct mcast_sock *s, struct mcast_sock *r) +{ + char buf[512]; + int size; + + size = sprintf(buf, "multicast traffic:\n" + "%20llu Bytes sent " + "%20llu Bytes recv\n" + "%20llu Pckts sent " + "%20llu Pckts recv\n" + "%20llu Error send " + "%20llu Error recv\n\n", + s->stats.bytes, r->stats.bytes, + s->stats.messages, r->stats.messages, + s->stats.error, r->stats.error); + + send(fd, buf, size, 0); +} diff --git a/src/netlink.c b/src/netlink.c new file mode 100644 index 0000000..0bde632 --- /dev/null +++ b/src/netlink.c @@ -0,0 +1,326 @@ +/* + * (C) 2006 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "conntrackd.h" +#include +#include +#include +#include "us-conntrack.h" +#include +#include +#include "network.h" + +static int ignore_conntrack(struct nf_conntrack *ct) +{ + /* ignore a certain protocol */ + if (CONFIG(ignore_protocol)[nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO)]) + return 1; + + /* Accept DNAT'ed traffic: not really coming to the local machine */ + if ((CONFIG(flags) & STRIP_NAT) && + nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) { + debug_ct(ct, "DNAT"); + return 0; + } + + /* Accept SNAT'ed traffic: not really coming to the local machine */ + if ((CONFIG(flags) & STRIP_NAT) && + nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) { + debug_ct(ct, "SNAT"); + return 0; + } + + /* Ignore traffic */ + if (ignore_pool_test(STATE(ignore_pool), ct)) { + debug_ct(ct, "ignore traffic"); + return 1; + } + + return 0; +} + +static int nl_event_handler(struct nlmsghdr *nlh, + struct nfattr *nfa[], + void *data) +{ + char tmp[1024]; + struct nf_conntrack *ct = (struct nf_conntrack *) tmp; + int type; + + memset(tmp, 0, sizeof(tmp)); + + if ((type = nfct_parse_conntrack(NFCT_T_ALL, nlh, ct)) == NFCT_T_ERROR) + return NFCT_CB_STOP; + + /* + * Ignore this conntrack: it talks about a + * connection that is not interesting for us. + */ + if (ignore_conntrack(ct)) + return NFCT_CB_STOP; + + switch(type) { + case NFCT_T_NEW: + STATE(mode)->event_new(ct, nlh); + break; + case NFCT_T_UPDATE: + STATE(mode)->event_upd(ct, nlh); + break; + case NFCT_T_DESTROY: + if (STATE(mode)->event_dst(ct, nlh)) + update_traffic_stats(ct); + break; + default: + dlog(STATE(log), "received unknown msg from ctnetlink\n"); + break; + } + + return NFCT_CB_STOP; +} + +int nl_init_event_handler(void) +{ + struct nfnl_callback cb_events = { + .call = nl_event_handler, + .attr_count = CTA_MAX + }; + + /* open event netlink socket */ + STATE(event) = nfnl_open(); + if (!STATE(event)) + return -1; + + /* set up socket buffer size */ + if (CONFIG(netlink_buffer_size)) + nfnl_rcvbufsiz(STATE(event), CONFIG(netlink_buffer_size)); + else { + socklen_t socklen = sizeof(unsigned int); + unsigned int read_size; + + /* get current buffer size */ + getsockopt(nfnl_fd(STATE(event)), SOL_SOCKET, + SO_RCVBUF, &read_size, &socklen); + + CONFIG(netlink_buffer_size) = read_size; + } + + /* ensure that maximum grown size is >= than maximum size */ + if (CONFIG(netlink_buffer_size_max_grown) < CONFIG(netlink_buffer_size)) + CONFIG(netlink_buffer_size_max_grown) = + CONFIG(netlink_buffer_size); + + /* open event subsystem */ + STATE(subsys_event) = nfnl_subsys_open(STATE(event), + NFNL_SUBSYS_CTNETLINK, + IPCTNL_MSG_MAX, + NFCT_ALL_CT_GROUPS); + if (STATE(subsys_event) == NULL) + return -1; + + /* register callback for new and update events */ + nfnl_callback_register(STATE(subsys_event), + IPCTNL_MSG_CT_NEW, + &cb_events); + + /* register callback for delete events */ + nfnl_callback_register(STATE(subsys_event), + IPCTNL_MSG_CT_DELETE, + &cb_events); + + return 0; +} + +static int nl_dump_handler(struct nlmsghdr *nlh, + struct nfattr *nfa[], + void *data) +{ + char buf[1024]; + struct nf_conntrack *ct = (struct nf_conntrack *) buf; + int type; + + memset(buf, 0, sizeof(buf)); + + if ((type = nfct_parse_conntrack(NFCT_T_ALL, nlh, ct)) == NFCT_T_ERROR) + return NFCT_CB_CONTINUE; + + /* + * Ignore this conntrack: it talks about a + * connection that is not interesting for us. + */ + if (ignore_conntrack(ct)) + return NFCT_CB_CONTINUE; + + switch(type) { + case NFCT_T_UPDATE: + STATE(mode)->dump(ct, nlh); + break; + default: + dlog(STATE(log), "received unknown msg from ctnetlink"); + break; + } + return NFCT_CB_CONTINUE; +} + +int nl_init_dump_handler(void) +{ + struct nfnl_callback cb_dump = { + .call = nl_dump_handler, + .attr_count = CTA_MAX + }; + + /* open dump netlink socket */ + STATE(dump) = nfnl_open(); + if (!STATE(dump)) + return -1; + + /* open dump subsystem */ + STATE(subsys_dump) = nfnl_subsys_open(STATE(dump), + NFNL_SUBSYS_CTNETLINK, + IPCTNL_MSG_MAX, + 0); + if (STATE(subsys_dump) == NULL) + return -1; + + /* register callback for dumped entries */ + nfnl_callback_register(STATE(subsys_dump), + IPCTNL_MSG_CT_NEW, + &cb_dump); + + if (nl_dump_conntrack_table(STATE(dump), STATE(subsys_dump)) == -1) + return -1; + + return 0; +} + +static int nl_overrun_handler(struct nlmsghdr *nlh, + struct nfattr *nfa[], + void *data) +{ + char buf[1024]; + struct nf_conntrack *ct = (struct nf_conntrack *) buf; + int type; + + memset(buf, 0, sizeof(buf)); + + if ((type = nfct_parse_conntrack(NFCT_T_ALL, nlh, ct)) == NFCT_T_ERROR) + return NFCT_CB_CONTINUE; + + /* + * Ignore this conntrack: it talks about a + * connection that is not interesting for us. + */ + if (ignore_conntrack(ct)) + return NFCT_CB_CONTINUE; + + switch(type) { + case NFCT_T_UPDATE: + if (STATE(mode)->overrun) + STATE(mode)->overrun(ct, nlh); + break; + default: + dlog(STATE(log), "received unknown msg from ctnetlink"); + break; + } + return NFCT_CB_CONTINUE; +} + +int nl_init_overrun_handler(void) +{ + struct nfnl_callback cb_sync = { + .call = nl_overrun_handler, + .attr_count = CTA_MAX + }; + + /* open sync netlink socket */ + STATE(sync) = nfnl_open(); + if (!STATE(sync)) + return -1; + + /* open synchronizer subsystem */ + STATE(subsys_sync) = nfnl_subsys_open(STATE(sync), + NFNL_SUBSYS_CTNETLINK, + IPCTNL_MSG_MAX, + 0); + if (STATE(subsys_sync) == NULL) + return -1; + + /* register callback for dumped entries */ + nfnl_callback_register(STATE(subsys_sync), + IPCTNL_MSG_CT_NEW, + &cb_sync); + + return 0; +} + +static int warned = 0; + +void nl_resize_socket_buffer(struct nfnl_handle *h) +{ + unsigned int s = CONFIG(netlink_buffer_size) * 2; + + /* already warned that we have reached the maximum buffer size */ + if (warned) + return; + + if (s > CONFIG(netlink_buffer_size_max_grown)) { + dlog(STATE(log), "maximum netlink socket buffer size reached"); + s = CONFIG(netlink_buffer_size_max_grown); + warned = 1; + } + + CONFIG(netlink_buffer_size) = nfnl_rcvbufsiz(h, s); + + /* notify the sysadmin */ + dlog(STATE(log), "netlink socket buffer size has been set to %u bytes", + CONFIG(netlink_buffer_size)); +} + +int nl_dump_conntrack_table(struct nfnl_handle *h, + struct nfnl_subsys_handle *subsys) +{ + struct nfnlhdr req; + + memset(&req, 0, sizeof(req)); + nfct_build_query(subsys, + NFCT_Q_DUMP, + &CONFIG(family), + &req, + sizeof(req)); + + if (nfnl_query(h, &req.nlh) == -1) + return -1; + + return 0; +} + +int nl_flush_master_conntrack_table(void) +{ + struct nfnlhdr req; + + memset(&req, 0, sizeof(req)); + nfct_build_query(STATE(subsys_sync), + NFCT_Q_FLUSH, + &CONFIG(family), + &req, + sizeof(req)); + + if (nfnl_query(STATE(sync), &req.nlh) == -1) + return -1; + + return 0; +} diff --git a/src/network.c b/src/network.c new file mode 100644 index 0000000..b9be318 --- /dev/null +++ b/src/network.c @@ -0,0 +1,282 @@ +/* + * (C) 2006-2007 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "conntrackd.h" +#include "network.h" + +#if 0 +#define _TEST_DROP +#else +#undef _TEST_DROP +#endif + +static int drop = 0; /* debugging purposes */ +static unsigned int seq_set, cur_seq; + +static int send_netmsg(struct mcast_sock *m, void *data, unsigned int len) +{ + struct nlnetwork *net = data; + +#ifdef _TEST_DROP + if (++drop > 10) { + drop = 0; + printf("dropping resend (seq=%u)\n", ntohl(net->seq)); + return 0; + } +#endif + return mcast_send(m, net, len); +} + +int mcast_send_netmsg(struct mcast_sock *m, void *data) +{ + struct nlmsghdr *nlh = data + sizeof(struct nlnetwork); + unsigned int len = nlh->nlmsg_len + sizeof(struct nlnetwork); + struct nlnetwork *net = data; + + if (!seq_set) { + seq_set = 1; + cur_seq = time(NULL); + net->flags |= NET_HELLO; + } + + net->flags = htons(net->flags); + net->seq = htonl(cur_seq++); + + if (nlh_host2network(nlh) == -1) + return -1; + + net->checksum = 0; + net->checksum = ntohs(do_csum(data, len)); + + return send_netmsg(m, data, len); +} + +int mcast_resend_netmsg(struct mcast_sock *m, void *data) +{ + struct nlnetwork *net = data; + struct nlmsghdr *nlh = data + sizeof(struct nlnetwork); + unsigned int len = htonl(nlh->nlmsg_len) + sizeof(struct nlnetwork); + + net->flags = ntohs(net->flags); + + if (!seq_set) { + seq_set = 1; + cur_seq = time(NULL); + net->flags |= NET_HELLO; + } + + if (net->flags & NET_NACK || net->flags & NET_ACK) { + struct nlnetwork_ack *nack = (struct nlnetwork_ack *) net; + len = sizeof(struct nlnetwork_ack); + } + + net->flags = htons(net->flags); + net->seq = htonl(cur_seq++); + net->checksum = 0; + net->checksum = ntohs(do_csum(data, len)); + + return send_netmsg(m, data, len); +} + +int mcast_send_error(struct mcast_sock *m, void *data) +{ + struct nlnetwork *net = data; + unsigned int len = sizeof(struct nlnetwork); + + if (!seq_set) { + seq_set = 1; + cur_seq = time(NULL); + net->flags |= NET_HELLO; + } + + if (net->flags & NET_NACK || net->flags & NET_ACK) { + struct nlnetwork_ack *nack = (struct nlnetwork_ack *) net; + nack->from = htonl(nack->from); + nack->to = htonl(nack->to); + len = sizeof(struct nlnetwork_ack); + } + + net->flags = htons(net->flags); + net->seq = htonl(cur_seq++); + net->checksum = 0; + net->checksum = ntohs(do_csum(data, len)); + + return send_netmsg(m, data, len); +} + +static int valid_checksum(void *data, unsigned int len) +{ + struct nlnetwork *net = data; + unsigned short checksum, tmp; + + checksum = ntohs(net->checksum); + + /* no checksum, skip */ + if (!checksum) + return 1; + + net->checksum = 0; + tmp = do_csum(data, len); + + return tmp == checksum; +} + +int mcast_recv_netmsg(struct mcast_sock *m, void *data, int len) +{ + int ret; + struct nlnetwork *net = data; + struct nlmsghdr *nlh = data + sizeof(struct nlnetwork); + struct nfgenmsg *nfhdr; + + ret = mcast_recv(m, net, len); + if (ret <= 0) + return ret; + + if (ret < sizeof(struct nlnetwork)) + return -1; + + if (!valid_checksum(data, ret)) + return -1; + + net->flags = ntohs(net->flags); + net->seq = ntohl(net->seq); + + if (net->flags & NET_HELLO) + STATE_SYNC(last_seq_recv) = net->seq-1; + + if (net->flags & NET_NACK || net->flags & NET_ACK) { + struct nlnetwork_ack *nack = (struct nlnetwork_ack *) net; + + if (ret < sizeof(struct nlnetwork_ack)) + return -1; + + nack->from = ntohl(nack->from); + nack->to = ntohl(nack->to); + + return ret; + } + + if (net->flags & NET_RESYNC) + return ret; + + /* information received is too small */ + if (ret < NLMSG_SPACE(sizeof(struct nfgenmsg))) + return -1; + + /* information received and message length does not match */ + if (ret != ntohl(nlh->nlmsg_len) + sizeof(struct nlnetwork)) + return -1; + + /* this message does not come from ctnetlink */ + if (NFNL_SUBSYS_ID(ntohs(nlh->nlmsg_type)) != NFNL_SUBSYS_CTNETLINK) + return -1; + + nfhdr = NLMSG_DATA(nlh); + + /* only AF_INET and AF_INET6 are supported */ + if (nfhdr->nfgen_family != AF_INET && + nfhdr->nfgen_family != AF_INET6) + return -1; + + /* only process message coming from nfnetlink v0 */ + if (nfhdr->version != NFNETLINK_V0) + return -1; + + if (nlh_network2host(nlh) == -1) + return -1; + + return ret; +} + +int mcast_track_seq(u_int32_t seq, u_int32_t *exp_seq) +{ + static int seq_set = 0; + int ret = 1; + + /* netlink sequence tracking initialization */ + if (!seq_set) { + seq_set = 1; + goto out; + } + + /* fast path: we received the correct sequence */ + if (seq == STATE_SYNC(last_seq_recv)+1) + goto out; + + /* out of sequence: some messages got lost */ + if (seq > STATE_SYNC(last_seq_recv)+1) { + STATE_SYNC(packets_lost) += seq-STATE_SYNC(last_seq_recv)+1; + ret = 0; + goto out; + } + + /* out of sequence: replayed or sequence wrapped around issues */ + if (seq < STATE_SYNC(last_seq_recv)+1) { + /* + * Check if the sequence has wrapped around. + * Perhaps it can be a replayed packet. + */ + if (STATE_SYNC(last_seq_recv)+1-seq > ~0U/2) { + /* + * Indeed, it is a wrapped around + */ + STATE_SYNC(packets_lost) += + ~0U-STATE_SYNC(last_seq_recv)+1+seq; + } else { + /* + * It is a delayed packet + */ + dlog(STATE(log), "delayed packet? exp=%u rcv=%u", + STATE_SYNC(last_seq_recv)+1, seq); + } + ret = 0; + } + +out: + *exp_seq = STATE_SYNC(last_seq_recv)+1; + /* update expected sequence */ + STATE_SYNC(last_seq_recv) = seq; + + return ret; +} + +int build_network_msg(const int msg_type, + struct nfnl_subsys_handle *ssh, + struct nf_conntrack *ct, + void *buffer, + unsigned int size) +{ + memset(buffer, 0, size); + buffer += sizeof(struct nlnetwork); + return nfct_build_query(ssh, msg_type, ct, buffer, size); +} + +unsigned int parse_network_msg(struct nf_conntrack *ct, + const struct nlmsghdr *nlh) +{ + /* + * The parsing of netlink messages going through network is + * similar to the one that is done for messages coming from + * kernel, therefore do not replicate more code and use the + * function provided in the libraries. + * + * Yup, this is a hack 8) + */ + return nfct_parse_conntrack(NFCT_T_ALL, nlh, ct); +} + diff --git a/src/proxy.c b/src/proxy.c new file mode 100644 index 0000000..b9bb04e --- /dev/null +++ b/src/proxy.c @@ -0,0 +1,124 @@ +/* + * (C) 2006 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include + +#if 0 +#define dprintf printf +#else +#define dprintf +#endif + +int nlh_payload_host2network(struct nfattr *nfa, int len) +{ + struct nfattr *__nfa; + + while (NFA_OK(nfa, len)) { + + dprintf("type=%d nfalen=%d len=%d [%s]\n", + nfa->nfa_type & 0x7fff, + nfa->nfa_len, len, + nfa->nfa_type & NFNL_NFA_NEST ? "NEST":""); + + if (nfa->nfa_type & NFNL_NFA_NEST) { + if (NFA_PAYLOAD(nfa) > len) + return -1; + + if (nlh_payload_host2network(NFA_DATA(nfa), + NFA_PAYLOAD(nfa)) == -1) + return -1; + } + + __nfa = NFA_NEXT(nfa, len); + + nfa->nfa_type = htons(nfa->nfa_type); + nfa->nfa_len = htons(nfa->nfa_len); + + nfa = __nfa; + } + return 0; +} + +int nlh_host2network(struct nlmsghdr *nlh) +{ + struct nfgenmsg *nfhdr = NLMSG_DATA(nlh); + struct nfattr *cda[CTA_MAX]; + unsigned int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg)); + unsigned int len = nlh->nlmsg_len - NLMSG_ALIGN(min_len); + + nlh->nlmsg_len = htonl(nlh->nlmsg_len); + nlh->nlmsg_type = htons(nlh->nlmsg_type); + nlh->nlmsg_flags = htons(nlh->nlmsg_flags); + nlh->nlmsg_seq = htonl(nlh->nlmsg_seq); + nlh->nlmsg_pid = htonl(nlh->nlmsg_pid); + + nfhdr->res_id = htons(nfhdr->res_id); + + return nlh_payload_host2network(NFM_NFA(NLMSG_DATA(nlh)), len); +} + +int nlh_payload_network2host(struct nfattr *nfa, int len) +{ + nfa->nfa_type = ntohs(nfa->nfa_type); + nfa->nfa_len = ntohs(nfa->nfa_len); + + while(NFA_OK(nfa, len)) { + + dprintf("type=%d nfalen=%d len=%d [%s]\n", + nfa->nfa_type & 0x7fff, + nfa->nfa_len, len, + nfa->nfa_type & NFNL_NFA_NEST ? "NEST":""); + + if (nfa->nfa_type & NFNL_NFA_NEST) { + if (NFA_PAYLOAD(nfa) > len) + return -1; + + if (nlh_payload_network2host(NFA_DATA(nfa), + NFA_PAYLOAD(nfa)) == -1) + return -1; + } + + nfa = NFA_NEXT(nfa,len); + + if (len < NFA_LENGTH(0)) + break; + + nfa->nfa_type = ntohs(nfa->nfa_type); + nfa->nfa_len = ntohs(nfa->nfa_len); + } + return 0; +} + +int nlh_network2host(struct nlmsghdr *nlh) +{ + struct nfgenmsg *nfhdr = NLMSG_DATA(nlh); + struct nfattr *cda[CTA_MAX]; + unsigned int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg)); + unsigned int len = ntohl(nlh->nlmsg_len) - NLMSG_ALIGN(min_len); + + nlh->nlmsg_len = ntohl(nlh->nlmsg_len); + nlh->nlmsg_type = ntohs(nlh->nlmsg_type); + nlh->nlmsg_flags = ntohs(nlh->nlmsg_flags); + nlh->nlmsg_seq = ntohl(nlh->nlmsg_seq); + nlh->nlmsg_pid = ntohl(nlh->nlmsg_pid); + + nfhdr->res_id = ntohs(nfhdr->res_id); + + return nlh_payload_network2host(NFM_NFA(NLMSG_DATA(nlh)), len); +} diff --git a/src/read_config_lex.l b/src/read_config_lex.l new file mode 100644 index 0000000..dee90c9 --- /dev/null +++ b/src/read_config_lex.l @@ -0,0 +1,125 @@ +%{ +/* + * (C) 2006 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Description: configuration file syntax + */ + +#include "read_config_yy.h" +#include "conntrackd.h" +%} + +%option yylineno +%option nounput + +ws [ \t]+ +comment #.*$ +nl [\n\r] + +is_on [o|O][n|N] +is_off [o|O][f|F][f|F] +integer [0-9]+ +path \/[^\"\n ]* +ip4_end [0-9]*[0-9]+ +ip4_part [0-2]*{ip4_end} +ip4 {ip4_part}\.{ip4_part}\.{ip4_part}\.{ip4_part} +hex_255 [0-9a-fA-F]{1,4} +ip6_part {hex_255}":"? +ip6_form1 {ip6_part}{0,16}"::"{ip6_part}{0,16} +ip6_form2 ({hex_255}":"){16}{hex_255} +ip6 {ip6_form1}|{ip6_form2} +string [a-zA-Z]* +persistent [P|p][E|e][R|r][S|s][I|i][S|s][T|t][E|e][N|n][T|T] +nack [N|n][A|a][C|c][K|k] + +%% +"UNIX" { return T_UNIX; } +"IPv4_address" { return T_IPV4_ADDR; } +"IPv6_address" { return T_IPV6_ADDR; } +"IPv4_interface" { return T_IPV4_IFACE; } +"IPv6_interface" { return T_IPV6_IFACE; } +"Port" { return T_PORT; } +"Multicast" { return T_MULTICAST; } +"HashSize" { return T_HASHSIZE; } +"RefreshTime" { return T_REFRESH; } +"CacheTimeout" { return T_EXPIRE; } +"CommitTimeout" { return T_TIMEOUT; } +"DelayDestroyMessages" { return T_DELAY; } +"HashLimit" { return T_HASHLIMIT; } +"Path" { return T_PATH; } +"IgnoreProtocol" { return T_IGNORE_PROTOCOL; } +"UDP" { return T_UDP; } +"ICMP" { return T_ICMP; } +"VRRP" { return T_VRRP; } +"IGMP" { return T_IGMP; } +"TCP" { return T_TCP; } +"IgnoreTrafficFor" { return T_IGNORE_TRAFFIC; } +"StripNAT" { return T_STRIP_NAT; } +"Backlog" { return T_BACKLOG; } +"Group" { return T_GROUP; } +"LogFile" { return T_LOG; } +"LockFile" { return T_LOCK; } +"General" { return T_GENERAL; } +"Sync" { return T_SYNC; } +"Stats" { return T_STATS; } +"RelaxTransitions" { return T_RELAX_TRANSITIONS; } +"SocketBufferSize" { return T_BUFFER_SIZE; } +"SocketBufferSizeMaxGrown" { return T_BUFFER_SIZE_MAX_GROWN; } +"SocketBufferSizeMaxGrowth" { return T_BUFFER_SIZE_MAX_GROWN; } +"Mode" { return T_SYNC_MODE; } +"ListenTo" { return T_LISTEN_TO; } +"Family" { return T_FAMILY; } +"ResendBufferSize" { return T_RESEND_BUFFER_SIZE; } +"Checksum" { return T_CHECKSUM; } +"ACKWindowSize" { return T_WINDOWSIZE; } +"Replicate" { return T_REPLICATE; } +"for" { return T_FOR; } +"SYN_SENT" { return T_SYN_SENT; } +"SYN_RECV" { return T_SYN_RECV; } +"ESTABLISHED" { return T_ESTABLISHED; } +"FIN_WAIT" { return T_FIN_WAIT; } +"CLOSE_WAIT" { return T_CLOSE_WAIT; } +"LAST_ACK" { return T_LAST_ACK; } +"TIME_WAIT" { return T_TIME_WAIT; } +"CLOSE" { return T_CLOSE; } +"LISTEN" { return T_LISTEN; } + +{is_on} { return T_ON; } +{is_off} { return T_OFF; } +{integer} { yylval.val = atoi(yytext); return T_NUMBER; } +{ip4} { yylval.string = strdup(yytext); return T_IP; } +{ip6} { yylval.string = strdup(yytext); return T_IP; } +{path} { yylval.string = strdup(yytext); return T_PATH_VAL; } +{persistent} { return T_PERSISTENT; } +{nack} { return T_NACK; } +{string} { yylval.string = strdup(yytext); return T_STRING; } + +{comment} ; +{ws} ; +{nl} ; + +<> { yyterminate(); } + +. { return yytext[0]; } + +%% + +int +yywrap() +{ + return 1; +} diff --git a/src/read_config_yy.y b/src/read_config_yy.y new file mode 100644 index 0000000..1668919 --- /dev/null +++ b/src/read_config_yy.y @@ -0,0 +1,550 @@ +%{ +/* + * (C) 2006 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Description: configuration file abstract grammar + */ + +#include +#include +#include +#include +#include "conntrackd.h" +#include "ignore.h" + +extern char *yytext; +extern int yylineno; + +struct ct_conf conf; +%} + +%union { + int val; + char *string; +} + +%token T_IPV4_ADDR T_IPV4_IFACE T_PORT T_HASHSIZE T_HASHLIMIT T_MULTICAST +%token T_PATH T_UNIX T_REFRESH T_IPV6_ADDR T_IPV6_IFACE +%token T_IGNORE_UDP T_IGNORE_ICMP T_IGNORE_TRAFFIC T_BACKLOG T_GROUP +%token T_LOG T_UDP T_ICMP T_IGMP T_VRRP T_TCP T_IGNORE_PROTOCOL +%token T_LOCK T_STRIP_NAT T_BUFFER_SIZE_MAX_GROWN T_EXPIRE T_TIMEOUT +%token T_GENERAL T_SYNC T_STATS T_RELAX_TRANSITIONS T_BUFFER_SIZE T_DELAY +%token T_SYNC_MODE T_LISTEN_TO T_FAMILY T_RESEND_BUFFER_SIZE +%token T_PERSISTENT T_NACK T_CHECKSUM T_WINDOWSIZE T_ON T_OFF +%token T_REPLICATE T_FOR +%token T_ESTABLISHED T_SYN_SENT T_SYN_RECV T_FIN_WAIT +%token T_CLOSE_WAIT T_LAST_ACK T_TIME_WAIT T_CLOSE T_LISTEN + + +%token T_IP T_PATH_VAL +%token T_NUMBER +%token T_STRING + +%% + +configfile : + | lines + ; + +lines : line + | lines line + ; + +line : ignore_protocol + | ignore_traffic + | strip_nat + | general + | sync + | stats + ; + +log : T_LOG T_PATH_VAL +{ + strncpy(conf.logfile, $2, FILENAME_MAXLEN); +}; + +lock : T_LOCK T_PATH_VAL +{ + strncpy(conf.lockfile, $2, FILENAME_MAXLEN); +}; + +strip_nat: T_STRIP_NAT +{ + conf.flags |= STRIP_NAT; +}; + +refreshtime : T_REFRESH T_NUMBER +{ + conf.refresh = $2; +}; + +expiretime: T_EXPIRE T_NUMBER +{ + conf.cache_timeout = $2; +}; + +timeout: T_TIMEOUT T_NUMBER +{ + conf.commit_timeout = $2; +}; + +checksum: T_CHECKSUM T_ON +{ +}; + +checksum: T_CHECKSUM T_OFF +{ + conf.flags |= DONT_CHECKSUM; +}; + +ignore_traffic : T_IGNORE_TRAFFIC '{' ignore_traffic_options '}'; + +ignore_traffic_options : + | ignore_traffic_options ignore_traffic_option; + +ignore_traffic_option : T_IPV4_ADDR T_IP +{ + union inet_address ip; + int family = 0; + + memset(&ip, 0, sizeof(union inet_address)); + + if (inet_aton($2, &ip.ipv4)) + family = AF_INET; +#ifdef HAVE_INET_PTON_IPV6 + else if (inet_pton(AF_INET6, $2, &ip.ipv6) > 0) + family = AF_INET6; +#endif + + if (!family) { + fprintf(stdout, "%s is not a valid IP, ignoring", $2); + return; + } + + if (!STATE(ignore_pool)) { + STATE(ignore_pool) = ignore_pool_create(family); + if (!STATE(ignore_pool)) { + fprintf(stdout, "Can't create ignore pool!\n"); + exit(EXIT_FAILURE); + } + } + + if (!ignore_pool_add(STATE(ignore_pool), &ip)) { + if (errno == EEXIST) + fprintf(stdout, "IP %s is repeated " + "in the ignore pool\n", $2); + if (errno == ENOSPC) + fprintf(stdout, "Too many IP in the ignore pool!\n"); + } +}; + +multicast_line : T_MULTICAST '{' multicast_options '}'; + +multicast_options : + | multicast_options multicast_option; + +multicast_option : T_IPV4_ADDR T_IP +{ + if (!inet_aton($2, &conf.mcast.in)) { + fprintf(stderr, "%s is not a valid IPv4 address\n"); + return; + } + + if (conf.mcast.ipproto == AF_INET6) { + fprintf(stderr, "Your multicast address is IPv4 but " + "is binded to an IPv6 interface? Surely " + "this is not what you want\n"); + return; + } + + conf.mcast.ipproto = AF_INET; +}; + +multicast_option : T_IPV6_ADDR T_IP +{ +#ifdef HAVE_INET_PTON_IPV6 + if (inet_pton(AF_INET6, $2, &conf.mcast.in) <= 0) + fprintf(stderr, "%s is not a valid IPv6 address\n", $2); +#endif + + if (conf.mcast.ipproto == AF_INET) { + fprintf(stderr, "Your multicast address is IPv6 but " + "is binded to an IPv4 interface? Surely " + "this is not what you want\n"); + return; + } + + conf.mcast.ipproto = AF_INET6; +}; + +multicast_option : T_IPV4_IFACE T_IP +{ + if (!inet_aton($2, &conf.mcast.ifa)) { + fprintf(stderr, "%s is not a valid IPv4 address\n"); + return; + } + + if (conf.mcast.ipproto == AF_INET6) { + fprintf(stderr, "Your multicast interface is IPv4 but " + "is binded to an IPv6 interface? Surely " + "this is not what you want\n"); + return; + } + + conf.mcast.ipproto = AF_INET; +}; + +multicast_option : T_IPV6_IFACE T_IP +{ +#ifdef HAVE_INET_PTON_IPV6 + if (inet_pton(AF_INET6, $2, &conf.mcast.ifa) <= 0) + fprintf(stderr, "%s is not a valid IPv6 address\n", $2); +#endif + + if (conf.mcast.ipproto == AF_INET) { + fprintf(stderr, "Your multicast interface is IPv6 but " + "is binded to an IPv4 interface? Surely " + "this is not what you want\n"); + return; + } + + conf.mcast.ipproto = AF_INET6; +}; + +multicast_option : T_BACKLOG T_NUMBER +{ + conf.mcast.backlog = $2; +}; + +multicast_option : T_GROUP T_NUMBER +{ + conf.mcast.port = $2; +}; + +hashsize : T_HASHSIZE T_NUMBER +{ + conf.hashsize = $2; +}; + +hashlimit: T_HASHLIMIT T_NUMBER +{ + conf.limit = $2; +}; + +unix_line: T_UNIX '{' unix_options '}'; + +unix_options: + | unix_options unix_option + ; + +unix_option : T_PATH T_PATH_VAL +{ + strcpy(conf.local.path, $2); +}; + +unix_option : T_BACKLOG T_NUMBER +{ + conf.local.backlog = $2; +}; + +ignore_protocol: T_IGNORE_PROTOCOL '{' ignore_proto_list '}'; + +ignore_proto_list: + | ignore_proto_list ignore_proto + ; + +ignore_proto: T_NUMBER +{ + if ($1 < IPPROTO_MAX) + conf.ignore_protocol[$1] = 1; + else + fprintf(stdout, "Protocol number `%d' is freak\n", $1); +}; + +ignore_proto: T_UDP +{ + conf.ignore_protocol[IPPROTO_UDP] = 1; +}; + +ignore_proto: T_ICMP +{ + conf.ignore_protocol[IPPROTO_ICMP] = 1; +}; + +ignore_proto: T_VRRP +{ + conf.ignore_protocol[IPPROTO_VRRP] = 1; +}; + +ignore_proto: T_IGMP +{ + conf.ignore_protocol[IPPROTO_IGMP] = 1; +}; + +sync: T_SYNC '{' sync_list '}'; + +sync_list: + | sync_list sync_line; + +sync_line: refreshtime + | expiretime + | timeout + | checksum + | multicast_line + | relax_transitions + | delay_destroy_msgs + | sync_mode_persistent + | sync_mode_nack + | listen_to + | state_replication + ; + +sync_mode_persistent: T_SYNC_MODE T_PERSISTENT '{' sync_mode_persistent_list '}' +{ + conf.flags |= SYNC_MODE_PERSISTENT; +}; + +sync_mode_nack: T_SYNC_MODE T_NACK '{' sync_mode_nack_list '}' +{ + conf.flags |= SYNC_MODE_NACK; +}; + +sync_mode_persistent_list: + | sync_mode_persistent_list sync_mode_persistent_line; + +sync_mode_persistent_line: refreshtime + | expiretime + | timeout + | relax_transitions + | delay_destroy_msgs + ; + +sync_mode_nack_list: + | sync_mode_nack_list sync_mode_nack_line; + +sync_mode_nack_line: resend_buffer_size + | timeout + | window_size + ; + +resend_buffer_size: T_RESEND_BUFFER_SIZE T_NUMBER +{ + conf.resend_buffer_size = $2; +}; + +window_size: T_WINDOWSIZE T_NUMBER +{ + conf.window_size = $2; +}; + +relax_transitions: T_RELAX_TRANSITIONS +{ + conf.flags |= RELAX_TRANSITIONS; +}; + +delay_destroy_msgs: T_DELAY +{ + conf.flags |= DELAY_DESTROY_MSG; +}; + +listen_to: T_LISTEN_TO T_IP +{ + union inet_address addr; + +#ifdef HAVE_INET_PTON_IPV6 + if (inet_pton(AF_INET6, $2, &addr.ipv6) <= 0) +#endif + if (inet_aton($2, &addr.ipv4) <= 0) { + fprintf(stderr, "%s is not a valid IP address\n", $2); + exit(EXIT_FAILURE); + } + + if (CONFIG(listen_to_len) == 0 || CONFIG(listen_to_len) % 16) { + CONFIG(listen_to) = realloc(CONFIG(listen_to), + sizeof(union inet_address) * + (CONFIG(listen_to_len) + 16)); + if (CONFIG(listen_to) == NULL) { + fprintf(stderr, "cannot init listen_to array\n"); + exit(EXIT_FAILURE); + } + + memset(CONFIG(listen_to) + + (CONFIG(listen_to_len) * sizeof(union inet_address)), + 0, sizeof(union inet_address) * 16); + + } +}; + +state_replication: T_REPLICATE states T_FOR state_proto; + +states: + | states state; + +state_proto: T_TCP; +state: tcp_state; + +tcp_state: T_SYN_SENT +{ + extern struct state_replication_helper tcp_state_helper; + state_helper_register(&tcp_state_helper, TCP_CONNTRACK_SYN_SENT); +}; +tcp_state: T_SYN_RECV +{ + extern struct state_replication_helper tcp_state_helper; + state_helper_register(&tcp_state_helper, TCP_CONNTRACK_SYN_RECV); +}; +tcp_state: T_ESTABLISHED +{ + extern struct state_replication_helper tcp_state_helper; + state_helper_register(&tcp_state_helper, TCP_CONNTRACK_ESTABLISHED); +}; +tcp_state: T_FIN_WAIT +{ + extern struct state_replication_helper tcp_state_helper; + state_helper_register(&tcp_state_helper, TCP_CONNTRACK_FIN_WAIT); +}; +tcp_state: T_CLOSE_WAIT +{ + extern struct state_replication_helper tcp_state_helper; + state_helper_register(&tcp_state_helper, TCP_CONNTRACK_CLOSE_WAIT); +}; +tcp_state: T_LAST_ACK +{ + extern struct state_replication_helper tcp_state_helper; + state_helper_register(&tcp_state_helper, TCP_CONNTRACK_LAST_ACK); +}; +tcp_state: T_TIME_WAIT +{ + extern struct state_replication_helper tcp_state_helper; + state_helper_register(&tcp_state_helper, TCP_CONNTRACK_TIME_WAIT); +}; +tcp_state: T_CLOSE +{ + extern struct state_replication_helper tcp_state_helper; + state_helper_register(&tcp_state_helper, TCP_CONNTRACK_CLOSE); +}; +tcp_state: T_LISTEN +{ + extern struct state_replication_helper tcp_state_helper; + state_helper_register(&tcp_state_helper, TCP_CONNTRACK_LISTEN); +}; + +general: T_GENERAL '{' general_list '}'; + +general_list: + | general_list general_line + ; + +general_line: hashsize + | hashlimit + | log + | lock + | unix_line + | netlink_buffer_size + | netlink_buffer_size_max_grown + | family + ; + +netlink_buffer_size: T_BUFFER_SIZE T_NUMBER +{ + conf.netlink_buffer_size = $2; +}; + +netlink_buffer_size_max_grown : T_BUFFER_SIZE_MAX_GROWN T_NUMBER +{ + conf.netlink_buffer_size_max_grown = $2; +}; + +family : T_FAMILY T_STRING +{ + if (strncmp($2, "IPv6", strlen("IPv6")) == 0) + conf.family = AF_INET6; + else + conf.family = AF_INET; +}; + +stats: T_SYNC '{' stats_list '}'; + +stats_list: + | stats_list stat_line + ; + +stat_line: + | + ; + +%% + +int +yyerror(char *msg) +{ + printf("Error parsing config file: "); + printf("line (%d), symbol '%s': %s\n", yylineno, yytext, msg); + exit(EXIT_FAILURE); +} + +int +init_config(char *filename) +{ + FILE *fp; + + fp = fopen(filename, "r"); + if (!fp) + return -1; + + yyrestart(fp); + yyparse(); + fclose(fp); + + /* default to IPv4 */ + if (CONFIG(family) == 0) + CONFIG(family) = AF_INET; + + /* set to default is not specified */ + if (strcmp(CONFIG(lockfile), "") == 0) + strncpy(CONFIG(lockfile), DEFAULT_LOCKFILE, FILENAME_MAXLEN); + + /* default to 180 seconds of expiration time: cache entries */ + if (CONFIG(cache_timeout) == 0) + CONFIG(cache_timeout) = 180; + + /* default to 180 seconds: committed entries */ + if (CONFIG(commit_timeout) == 0) + CONFIG(commit_timeout) = 180; + + /* default to 60 seconds of refresh time */ + if (CONFIG(refresh) == 0) + CONFIG(refresh) = 60; + + if (CONFIG(resend_buffer_size) == 0) + CONFIG(resend_buffer_size) = 262144; + + /* create empty pool */ + if (!STATE(ignore_pool)) { + STATE(ignore_pool) = ignore_pool_create(CONFIG(family)); + if (!STATE(ignore_pool)) { + fprintf(stdout, "Can't create ignore pool!\n"); + exit(EXIT_FAILURE); + } + } + + /* default to a window size of 20 packets */ + if (CONFIG(window_size) == 0) + CONFIG(window_size) = 20; + + return 0; +} diff --git a/src/run.c b/src/run.c new file mode 100644 index 0000000..67437d8 --- /dev/null +++ b/src/run.c @@ -0,0 +1,227 @@ +/* + * (C) 2006-2007 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Description: run and init functions + */ + +#include "conntrackd.h" +#include +#include +#include "us-conntrack.h" +#include +#include + +void killer(int foo) +{ + /* no signals while handling signals */ + sigprocmask(SIG_BLOCK, &STATE(block), NULL); + + nfnl_subsys_close(STATE(subsys_event)); + nfnl_subsys_close(STATE(subsys_dump)); + nfnl_subsys_close(STATE(subsys_sync)); + nfnl_close(STATE(event)); + nfnl_close(STATE(dump)); + nfnl_close(STATE(sync)); + + ignore_pool_destroy(STATE(ignore_pool)); + local_server_destroy(STATE(local)); + STATE(mode)->kill(); + unlink(CONFIG(lockfile)); + dlog(STATE(log), "------- shutdown received ----"); + close_log(STATE(log)); + + sigprocmask(SIG_UNBLOCK, &STATE(block), NULL); + + exit(0); +} + +void local_handler(int fd, void *data) +{ + int ret; + int type; + + ret = read(fd, &type, sizeof(type)); + if (ret == -1) { + dlog(STATE(log), "can't read from unix socket\n"); + return; + } + if (ret == 0) { + debug("nothing to process\n"); + return; + } + + switch(type) { + case FLUSH_MASTER: + dlog(STATE(log), "[REQ] flushing master table"); + nl_flush_master_conntrack_table(); + return; + case RESYNC_MASTER: + dlog(STATE(log), "[REQ] resync with master table"); + nl_dump_conntrack_table(STATE(dump), STATE(subsys_dump)); + return; + } + + if (!STATE(mode)->local(fd, type, data)) + dlog(STATE(log), "[FAIL] unknown local request %d", type); +} + +int init(int mode) +{ + switch(mode) { + case STATS_MODE: + STATE(mode) = &stats_mode; + break; + case SYNC_MODE: + STATE(mode) = &sync_mode; + break; + default: + fprintf(stderr, "Unknown running mode! default " + "to synchronization mode\n"); + STATE(mode) = &sync_mode; + break; + } + + /* Initialization */ + if (STATE(mode)->init() == -1) { + dlog(STATE(log), "[FAIL] initialization failed"); + return -1; + } + + /* local UNIX socket */ + STATE(local) = local_server_create(&CONFIG(local)); + if (!STATE(local)) { + dlog(STATE(log), "[FAIL] can't open unix socket!"); + return -1; + } + + if (nl_init_event_handler() == -1) { + dlog(STATE(log), "[FAIL] can't open netlink handler! " + "no ctnetlink kernel support?"); + return -1; + } + + if (nl_init_dump_handler() == -1) { + dlog(STATE(log), "[FAIL] can't open netlink handler! " + "no ctnetlink kernel support?"); + return -1; + } + + if (nl_init_overrun_handler() == -1) { + dlog(STATE(log), "[FAIL] can't open netlink handler! " + "no ctnetlink kernel support?"); + return -1; + } + + /* Signals handling */ + sigemptyset(&STATE(block)); + sigaddset(&STATE(block), SIGTERM); + sigaddset(&STATE(block), SIGINT); + + if (signal(SIGINT, killer) == SIG_ERR) + return -1; + + if (signal(SIGTERM, killer) == SIG_ERR) + return -1; + + /* ignore connection reset by peer */ + if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) + return -1; + + dlog(STATE(log), "[OK] initialization completed"); + + return 0; +} + +#define POLL_NSECS 1 + +static void __run(void) +{ + int max, ret; + fd_set readfds; + struct timeval tv = { + .tv_sec = POLL_NSECS, + .tv_usec = 0 + }; + + FD_ZERO(&readfds); + FD_SET(STATE(local), &readfds); + FD_SET(nfnl_fd(STATE(event)), &readfds); + + max = MAX(STATE(local), nfnl_fd(STATE(event))); + + if (STATE(mode)->add_fds_to_set) + max = MAX(max, STATE(mode)->add_fds_to_set(&readfds)); + + ret = select(max+1, &readfds, NULL, NULL, &tv); + if (ret == -1) { + /* interrupted syscall, retry */ + if (errno == EINTR) + return; + + dlog(STATE(log), "select() failed: %s", strerror(errno)); + return; + } + + /* signals are racy */ + sigprocmask(SIG_BLOCK, &STATE(block), NULL); + + /* order received via UNIX socket */ + if (FD_ISSET(STATE(local), &readfds)) + do_local_server_step(STATE(local), NULL, local_handler); + + /* conntrack event has happened */ + if (FD_ISSET(nfnl_fd(STATE(event)), &readfds)) { + ret = nfnl_catch(STATE(event)); + if (ret == -1) { + switch(errno) { + case ENOBUFS: + /* + * It seems that ctnetlink can't back off, + * it's likely that we're losing events. + * Solution: duplicate the socket buffer + * size and resync with master conntrack table. + */ + nl_resize_socket_buffer(STATE(event)); + nl_dump_conntrack_table(STATE(sync), + STATE(subsys_sync)); + break; + case ENOENT: + /* + * We received a message from another + * netfilter subsystem that we are not + * interested in. Just ignore it. + */ + break; + default: + dlog(STATE(log), "event catch says: %s", + strerror(errno)); + break; + } + } + } + + if (STATE(mode)->step) + STATE(mode)->step(&readfds); + + sigprocmask(SIG_UNBLOCK, &STATE(block), NULL); +} + +void run(void) +{ + while(1) + __run(); +} diff --git a/src/state_helper.c b/src/state_helper.c new file mode 100644 index 0000000..81b0d09 --- /dev/null +++ b/src/state_helper.c @@ -0,0 +1,44 @@ +/* + * (C) 2006-2007 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "conntrackd.h" +#include "state_helper.h" + +static struct state_replication_helper *helper[IPPROTO_MAX]; + +int state_helper_verdict(int type, struct nf_conntrack *ct) +{ + u_int8_t l4proto; + + if (type == NFCT_T_DESTROY) + return ST_H_REPLICATE; + + l4proto = nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO); + if (helper[l4proto]) + return helper[l4proto]->verdict(helper[l4proto], ct); + + return ST_H_REPLICATE; +} + +void state_helper_register(struct state_replication_helper *h, int state) +{ + if (helper[h->proto] == NULL) + helper[h->proto] = h; + + helper[h->proto]->state |= (1 << state); +} diff --git a/src/state_helper_tcp.c b/src/state_helper_tcp.c new file mode 100644 index 0000000..af714dc --- /dev/null +++ b/src/state_helper_tcp.c @@ -0,0 +1,35 @@ +/* + * (C) 2006-2007 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "conntrackd.h" +#include "state_helper.h" + +static int tcp_verdict(const struct state_replication_helper *h, + const struct nf_conntrack *ct) +{ + u_int8_t state = nfct_get_attr_u8(ct, ATTR_TCP_STATE); + if (h->state & (1 << state)) + return ST_H_REPLICATE; + + return ST_H_SKIP; +} + +struct state_replication_helper tcp_state_helper = { + .proto = IPPROTO_TCP, + .verdict = tcp_verdict, +}; diff --git a/src/stats-mode.c b/src/stats-mode.c new file mode 100644 index 0000000..9647bbf --- /dev/null +++ b/src/stats-mode.c @@ -0,0 +1,151 @@ +/* + * (C) 2006 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include "cache.h" +#include "conntrackd.h" +#include +#include +#include +#include "us-conntrack.h" +#include +#include + +static int init_stats(void) +{ + int ret; + + state.stats = malloc(sizeof(struct ct_stats_state)); + if (!state.stats) { + dlog(STATE(log), "[FAIL] can't allocate memory for stats sync"); + return -1; + } + memset(state.stats, 0, sizeof(struct ct_stats_state)); + + STATE_STATS(cache) = cache_create("stats", + LIFETIME, + CONFIG(family), + NULL); + if (!STATE_STATS(cache)) { + dlog(STATE(log), "[FAIL] can't allocate memory for the " + "external cache"); + return -1; + } + + return 0; +} + +static void kill_stats() +{ + cache_destroy(STATE_STATS(cache)); +} + +/* handler for requests coming via UNIX socket */ +static int local_handler_stats(int fd, int type, void *data) +{ + int ret = 1; + + switch(type) { + case DUMP_INTERNAL: + cache_dump(STATE_STATS(cache), fd, NFCT_O_PLAIN); + break; + case DUMP_INT_XML: + cache_dump(STATE_SYNC(internal), fd, NFCT_O_XML); + break; + case FLUSH_CACHE: + dlog(STATE(log), "[REQ] flushing caches"); + cache_flush(STATE_STATS(cache)); + break; + case KILL: + killer(); + break; + case STATS: + cache_stats(STATE_STATS(cache), fd); + dump_traffic_stats(fd); + break; + default: + ret = 0; + break; + } + + return ret; +} + +static void dump_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh) +{ + if (cache_update_force(STATE_STATS(cache), ct)) + debug_ct(ct, "resync entry"); +} + +static void event_new_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh) +{ + debug_ct(ct, "debug event"); + if (cache_add(STATE_STATS(cache), ct)) { + debug_ct(ct, "cache new"); + } else { + dlog(STATE(log), "can't add to cache cache: " + "%s\n", strerror(errno)); + debug_ct(ct, "can't add"); + } +} + +static void event_update_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh) +{ + debug_ct(ct, "update"); + + if (!cache_update(STATE_STATS(cache), ct)) { + /* + * Perhaps we are losing events. If we are working + * in relax mode then add a new entry to the cache. + * + * FIXME: relax transitions not implemented yet + */ + if ((CONFIG(flags) & RELAX_TRANSITIONS) + && cache_add(STATE_STATS(cache), ct)) { + debug_ct(ct, "forcing cache update"); + } else { + debug_ct(ct, "can't update"); + return; + } + } + debug_ct(ct, "update"); +} + +static int event_destroy_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh) +{ + if (cache_del(STATE_STATS(cache), ct)) { + debug_ct(ct, "cache destroy"); + return 1; + } else { + debug_ct(ct, "can't destroy!"); + return 0; + } +} + +struct ct_mode stats_mode = { + .init = init_stats, + .add_fds_to_set = NULL, + .step = NULL, + .local = local_handler_stats, + .kill = kill_stats, + .dump = dump_stats, + .overrun = dump_stats, + .event_new = event_new_stats, + .event_upd = event_update_stats, + .event_dst = event_destroy_stats +}; diff --git a/src/sync-mode.c b/src/sync-mode.c new file mode 100644 index 0000000..b32bef7 --- /dev/null +++ b/src/sync-mode.c @@ -0,0 +1,416 @@ +/* + * (C) 2006 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include "cache.h" +#include "conntrackd.h" +#include +#include +#include +#include "us-conntrack.h" +#include +#include +#include "sync.h" +#include "network.h" + +/* handler for multicast messages received */ +static void mcast_handler() +{ + int ret; + char buf[4096], tmp[256]; + struct mcast_sock *m = STATE_SYNC(mcast_server); + unsigned int type; + struct nlnetwork *net = (struct nlnetwork *) buf; + unsigned int size = sizeof(struct nlnetwork); + struct nlmsghdr *nlh = (struct nlmsghdr *) (buf + size); + struct nf_conntrack *ct = (struct nf_conntrack *) tmp; + struct us_conntrack *u = NULL; + + memset(tmp, 0, sizeof(tmp)); + + ret = mcast_recv_netmsg(m, buf, sizeof(buf)); + if (ret <= 0) { + STATE(malformed)++; + return; + } + + if (STATE_SYNC(mcast_sync)->pre_recv(net)) + return; + + if ((type = parse_network_msg(ct, nlh)) == NFCT_T_ERROR) { + STATE(malformed)++; + return; + } + + nfct_attr_unset(ct, ATTR_TIMEOUT); + nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES); + nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS); + nfct_attr_unset(ct, ATTR_REPL_COUNTER_BYTES); + nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); + + switch(type) { + case NFCT_T_NEW: +retry: + if ((u = cache_add(STATE_SYNC(external), ct))) { + debug_ct(u->ct, "external new"); + } else { + /* + * One certain connection A arrives to the cache but + * another existing connection B in the cache has + * the same configuration, therefore B clashes with A. + */ + if (errno == EEXIST) { + cache_del(STATE_SYNC(external), ct); + goto retry; + } + debug_ct(ct, "can't add"); + } + break; + case NFCT_T_UPDATE: + if ((u = cache_update_force(STATE_SYNC(external), ct))) { + debug_ct(u->ct, "external update"); + } else + debug_ct(ct, "can't update"); + break; + case NFCT_T_DESTROY: + if (cache_del(STATE_SYNC(external), ct)) + debug_ct(ct, "external destroy"); + else + debug_ct(ct, "can't destroy"); + break; + default: + debug("unknown type %d\n", type); + break; + } +} + +static int init_sync(void) +{ + int ret; + + state.sync = malloc(sizeof(struct ct_sync_state)); + if (!state.sync) { + dlog(STATE(log), "[FAIL] can't allocate memory for state sync"); + return -1; + } + memset(state.sync, 0, sizeof(struct ct_sync_state)); + + if (CONFIG(flags) & SYNC_MODE_NACK) + STATE_SYNC(mcast_sync) = &nack; + else + /* default to persistent mode */ + STATE_SYNC(mcast_sync) = ¬rack; + + if (STATE_SYNC(mcast_sync)->init) + STATE_SYNC(mcast_sync)->init(); + + STATE_SYNC(internal) = + cache_create("internal", + STATE_SYNC(mcast_sync)->internal_cache_flags, + CONFIG(family), + STATE_SYNC(mcast_sync)->internal_cache_extra); + + if (!STATE_SYNC(internal)) { + dlog(STATE(log), "[FAIL] can't allocate memory for " + "the internal cache"); + return -1; + } + + STATE_SYNC(external) = + cache_create("external", + STATE_SYNC(mcast_sync)->external_cache_flags, + CONFIG(family), + NULL); + + if (!STATE_SYNC(external)) { + dlog(STATE(log), "[FAIL] can't allocate memory for the " + "external cache"); + return -1; + } + + /* multicast server to receive events from the wire */ + STATE_SYNC(mcast_server) = mcast_server_create(&CONFIG(mcast)); + if (STATE_SYNC(mcast_server) == NULL) { + dlog(STATE(log), "[FAIL] can't open multicast server!"); + return -1; + } + + /* multicast client to send events on the wire */ + STATE_SYNC(mcast_client) = mcast_client_create(&CONFIG(mcast)); + if (STATE_SYNC(mcast_client) == NULL) { + dlog(STATE(log), "[FAIL] can't open client multicast socket!"); + return -1; + } + + /* initialization of multicast sequence generation */ + STATE_SYNC(last_seq_sent) = time(NULL); + + if (create_alarm_thread() == -1) { + dlog(STATE(log), "[FAIL] can't initialize alarm thread"); + return -1; + } + + return 0; +} + +static int add_fds_to_set_sync(fd_set *readfds) +{ + FD_SET(STATE_SYNC(mcast_server->fd), readfds); + + return STATE_SYNC(mcast_server->fd); +} + +static void step_sync(fd_set *readfds) +{ + /* multicast packet has been received */ + if (FD_ISSET(STATE_SYNC(mcast_server->fd), readfds)) + mcast_handler(); +} + +static void kill_sync() +{ + cache_destroy(STATE_SYNC(internal)); + cache_destroy(STATE_SYNC(external)); + + mcast_server_destroy(STATE_SYNC(mcast_server)); + mcast_client_destroy(STATE_SYNC(mcast_client)); + + destroy_alarm_thread(); + + if (STATE_SYNC(mcast_sync)->kill) + STATE_SYNC(mcast_sync)->kill(); +} + +static dump_stats_sync(int fd) +{ + char buf[512]; + int size; + + size = sprintf(buf, "multicast sequence tracking:\n" + "%20llu Pckts mfrm " + "%20llu Pckts lost\n\n", + STATE(malformed), + STATE_SYNC(packets_lost)); + + send(fd, buf, size, 0); +} + +/* handler for requests coming via UNIX socket */ +static int local_handler_sync(int fd, int type, void *data) +{ + int ret = 1; + + switch(type) { + case DUMP_INTERNAL: + cache_dump(STATE_SYNC(internal), fd, NFCT_O_PLAIN); + break; + case DUMP_EXTERNAL: + cache_dump(STATE_SYNC(external), fd, NFCT_O_PLAIN); + break; + case DUMP_INT_XML: + cache_dump(STATE_SYNC(internal), fd, NFCT_O_XML); + break; + case DUMP_EXT_XML: + cache_dump(STATE_SYNC(external), fd, NFCT_O_XML); + break; + case COMMIT: + dlog(STATE(log), "[REQ] commit external cache to master table"); + cache_commit(STATE_SYNC(external)); + break; + case FLUSH_CACHE: + dlog(STATE(log), "[REQ] flushing caches"); + cache_flush(STATE_SYNC(internal)); + cache_flush(STATE_SYNC(external)); + break; + case KILL: + killer(); + break; + case STATS: + cache_stats(STATE_SYNC(internal), fd); + cache_stats(STATE_SYNC(external), fd); + dump_traffic_stats(fd); + mcast_dump_stats(fd, STATE_SYNC(mcast_client), + STATE_SYNC(mcast_server)); + dump_stats_sync(fd); + break; + case SEND_BULK: + dlog(STATE(log), "[REQ] sending bulk update"); + cache_bulk(STATE_SYNC(internal)); + break; + default: + if (STATE_SYNC(mcast_sync)->local) + ret = STATE_SYNC(mcast_sync)->local(fd, type, data); + break; + } + + return ret; +} + +static void dump_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) +{ + /* This is required by kernels < 2.6.20 */ + nfct_attr_unset(ct, ATTR_TIMEOUT); + nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES); + nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS); + nfct_attr_unset(ct, ATTR_REPL_COUNTER_BYTES); + nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); + nfct_attr_unset(ct, ATTR_USE); + + if (cache_update_force(STATE_SYNC(internal), ct)) + debug_ct(ct, "resync"); +} + +static void mcast_send_sync(struct nlmsghdr *nlh, + struct us_conntrack *u, + struct nf_conntrack *ct, + int type) +{ + char buf[4096]; + struct nlnetwork *net = (struct nlnetwork *) buf; + int mangled = 0; + + memset(buf, 0, sizeof(buf)); + + if (!state_helper_verdict(type, ct)) + return; + + if (!mangled) + memcpy(buf + sizeof(struct nlnetwork), nlh, nlh->nlmsg_len); + + mcast_send_netmsg(STATE_SYNC(mcast_client), net); + STATE_SYNC(mcast_sync)->post_send(net, u); +} + +static void overrun_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) +{ + struct us_conntrack *u; + + /* This is required by kernels < 2.6.20 */ + nfct_attr_unset(ct, ATTR_TIMEOUT); + nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES); + nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS); + nfct_attr_unset(ct, ATTR_REPL_COUNTER_BYTES); + nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); + nfct_attr_unset(ct, ATTR_USE); + + if (!cache_test(STATE_SYNC(internal), ct)) { + if ((u = cache_update_force(STATE_SYNC(internal), ct))) { + debug_ct(ct, "overrun resync"); + mcast_send_sync(nlh, u, ct, NFCT_T_UPDATE); + } + } +} + +static void event_new_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) +{ + struct us_conntrack *u; + + /* required by linux kernel <= 2.6.20 */ + nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES); + nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS); + nfct_attr_unset(ct, ATTR_REPL_COUNTER_BYTES); + nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); + nfct_attr_unset(ct, ATTR_TIMEOUT); +retry: + if ((u = cache_add(STATE_SYNC(internal), ct))) { + mcast_send_sync(nlh, u, ct, NFCT_T_NEW); + debug_ct(u->ct, "internal new"); + } else { + if (errno == EEXIST) { + char buf[4096]; + struct nlmsghdr *nlh = (struct nlmsghdr *) buf; + + int ret = build_network_msg(NFCT_Q_DESTROY, + STATE(subsys_event), + ct, + buf, + sizeof(buf)); + if (ret == -1) + return; + + cache_del(STATE_SYNC(internal), ct); + mcast_send_sync(nlh, NULL, ct, NFCT_T_NEW); + goto retry; + } + dlog(STATE(log), "can't add to internal cache: " + "%s\n", strerror(errno)); + debug_ct(ct, "can't add"); + } +} + +static void event_update_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) +{ + struct us_conntrack *u; + + nfct_attr_unset(ct, ATTR_TIMEOUT); + + if ((u = cache_update(STATE_SYNC(internal), ct)) == NULL) { + /* + * Perhaps we are losing events. If we are working + * in relax mode then add a new entry to the cache. + * + * FIXME: relax transitions not implemented yet + */ + if ((CONFIG(flags) & RELAX_TRANSITIONS) + && (u = cache_add(STATE_SYNC(internal), ct))) { + debug_ct(u->ct, "forcing internal update"); + } else { + debug_ct(ct, "can't update"); + return; + } + } + debug_ct(u->ct, "internal update"); + mcast_send_sync(nlh, u, ct, NFCT_T_UPDATE); +} + +static int event_destroy_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) +{ + nfct_attr_unset(ct, ATTR_TIMEOUT); + + if (CONFIG(flags) & DELAY_DESTROY_MSG) { + + nfct_set_attr_u32(ct, ATTR_STATUS, IPS_DYING); + + if (cache_update(STATE_SYNC(internal), ct)) { + debug_ct(ct, "delay internal destroy"); + return 1; + } else { + debug_ct(ct, "can't delay destroy!"); + return 0; + } + } else { + if (cache_del(STATE_SYNC(internal), ct)) { + mcast_send_sync(nlh, NULL, ct, NFCT_T_DESTROY); + debug_ct(ct, "internal destroy"); + } else + debug_ct(ct, "can't destroy"); + } +} + +struct ct_mode sync_mode = { + .init = init_sync, + .add_fds_to_set = add_fds_to_set_sync, + .step = step_sync, + .local = local_handler_sync, + .kill = kill_sync, + .dump = dump_sync, + .overrun = overrun_sync, + .event_new = event_new_sync, + .event_upd = event_update_sync, + .event_dst = event_destroy_sync +}; diff --git a/src/sync-nack.c b/src/sync-nack.c new file mode 100644 index 0000000..288dba4 --- /dev/null +++ b/src/sync-nack.c @@ -0,0 +1,309 @@ +/* + * (C) 2006-2007 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include "conntrackd.h" +#include "sync.h" +#include "linux_list.h" +#include "us-conntrack.h" +#include "buffer.h" +#include "debug.h" +#include "network.h" +#include +#include + +#if 0 +#define dp printf +#else +#define dp +#endif + +static LIST_HEAD(queue); + +struct cache_nack { + struct list_head head; + u_int32_t seq; +}; + +static void cache_nack_add(struct us_conntrack *u, void *data) +{ + struct cache_nack *cn = data; + + INIT_LIST_HEAD(&cn->head); + list_add(&cn->head, &queue); +} + +static void cache_nack_update(struct us_conntrack *u, void *data) +{ + struct cache_nack *cn = data; + + if (cn->head.next != LIST_POISON1 && + cn->head.prev != LIST_POISON2) + list_del(&cn->head); + + INIT_LIST_HEAD(&cn->head); + list_add(&cn->head, &queue); +} + +static void cache_nack_destroy(struct us_conntrack *u, void *data) +{ + struct cache_nack *cn = data; + + if (cn->head.next != LIST_POISON1 && + cn->head.prev != LIST_POISON2) + list_del(&cn->head); +} + +static struct cache_extra cache_nack_extra = { + .size = sizeof(struct cache_nack), + .add = cache_nack_add, + .update = cache_nack_update, + .destroy = cache_nack_destroy +}; + +static int nack_init() +{ + STATE_SYNC(buffer) = buffer_create(CONFIG(resend_buffer_size)); + if (STATE_SYNC(buffer) == NULL) + return -1; + + return 0; +} + +static void nack_kill() +{ + buffer_destroy(STATE_SYNC(buffer)); +} + +static void mcast_send_nack(u_int32_t expt_seq, u_int32_t recv_seq) +{ + struct nlnetwork_ack nack = { + .flags = NET_NACK, + .from = expt_seq, + .to = recv_seq, + }; + + mcast_send_error(STATE_SYNC(mcast_client), &nack); + buffer_add(STATE_SYNC(buffer), &nack, sizeof(struct nlnetwork_ack)); +} + +static void mcast_send_ack(u_int32_t from, u_int32_t to) +{ + struct nlnetwork_ack ack = { + .flags = NET_ACK, + .from = from, + .to = to, + }; + + mcast_send_error(STATE_SYNC(mcast_client), &ack); + buffer_add(STATE_SYNC(buffer), &ack, sizeof(struct nlnetwork_ack)); +} + +static void mcast_send_resync() +{ + struct nlnetwork net = { + .flags = NET_RESYNC, + }; + + mcast_send_error(STATE_SYNC(mcast_client), &net); + buffer_add(STATE_SYNC(buffer), &net, sizeof(struct nlnetwork)); +} + +int nack_local(int fd, int type, void *data) +{ + int ret = 1; + + switch(type) { + case REQUEST_DUMP: + mcast_send_resync(); + dlog(STATE(log), "[REQ] request resync"); + break; + default: + ret = 0; + break; + } + + return ret; +} + +static int buffer_compare(void *data1, void *data2) +{ + struct nlnetwork *net = data1; + struct nlnetwork_ack *nack = data2; + struct nlmsghdr *nlh = data1 + sizeof(struct nlnetwork); + + unsigned old_seq = ntohl(net->seq); + + if (ntohl(net->seq) >= nack->from && ntohl(net->seq) <= nack->to) { + if (mcast_resend_netmsg(STATE_SYNC(mcast_client), net)) + dp("resend destroy (old seq=%u) (seq=%u)\n", + old_seq, ntohl(net->seq)); + } + return 0; +} + +static int buffer_remove(void *data1, void *data2) +{ + struct nlnetwork *net = data1; + struct nlnetwork_ack *h = data2; + + if (ntohl(net->seq) >= h->from && ntohl(net->seq) <= h->to) { + dp("remove from buffer (seq=%u)\n", ntohl(net->seq)); + __buffer_del(STATE_SYNC(buffer), data1); + } + return 0; +} + +static void queue_resend(struct cache *c, unsigned int from, unsigned int to) +{ + struct list_head *n; + struct us_conntrack *u; + unsigned int *seq; + + lock(); + list_for_each(n, &queue) { + struct cache_nack *cn = (struct cache_nack *) n; + struct us_conntrack *u; + + u = cache_get_conntrack(STATE_SYNC(internal), cn); + + if (cn->seq >= from && cn->seq <= to) { + debug_ct(u->ct, "resend nack"); + dp("resending nack'ed (oldseq=%u) ", cn->seq); + + char buf[4096]; + struct nlnetwork *net = (struct nlnetwork *) buf; + + int ret = build_network_msg(NFCT_Q_UPDATE, + STATE(subsys_event), + u->ct, + buf, + sizeof(buf)); + if (ret == -1) { + unlock(); + break; + } + + mcast_send_netmsg(STATE_SYNC(mcast_client), buf); + STATE_SYNC(mcast_sync)->post_send(net, u); + dp("(newseq=%u)\n", *seq); + } + } + unlock(); +} + +static void queue_empty(struct cache *c, unsigned int from, unsigned int to) +{ + struct list_head *n, *tmp; + struct us_conntrack *u; + unsigned int *seq; + + lock(); + dp("ACK from %u to %u\n", from, to); + list_for_each_safe(n, tmp, &queue) { + struct cache_nack *cn = (struct cache_nack *) n; + + u = cache_get_conntrack(STATE_SYNC(internal), cn); + if (cn->seq >= from && cn->seq <= to) { + dp("remove %u\n", cn->seq); + debug_ct(u->ct, "ack received: empty queue"); + dp("queue: deleting from queue (seq=%u)\n", cn->seq); + list_del(&cn->head); + } + } + unlock(); +} + +static int nack_pre_recv(const struct nlnetwork *net) +{ + static unsigned int window = 0; + unsigned int exp_seq; + + if (window == 0) + window = CONFIG(window_size); + + if (!mcast_track_seq(net->seq, &exp_seq)) { + dp("OOS: sending nack (seq=%u)\n", exp_seq); + mcast_send_nack(exp_seq, net->seq - 1); + window = CONFIG(window_size); + } else { + /* received a window, send an acknowledgement */ + if (--window == 0) { + dp("sending ack (seq=%u)\n", net->seq); + mcast_send_ack(net->seq-CONFIG(window_size), net->seq); + } + } + + if (net->flags & NET_NACK) { + struct nlnetwork_ack *nack = (struct nlnetwork_ack *) net; + + dp("NACK: from seq=%u to seq=%u\n", nack->from, nack->to); + queue_resend(STATE_SYNC(internal), nack->from, nack->to); + buffer_iterate(STATE_SYNC(buffer), nack, buffer_compare); + return 1; + } else if (net->flags & NET_RESYNC) { + dp("RESYNC ALL\n"); + cache_bulk(STATE_SYNC(internal)); + return 1; + } else if (net->flags & NET_ACK) { + struct nlnetwork_ack *h = (struct nlnetwork_ack *) net; + + dp("ACK: from seq=%u to seq=%u\n", h->from, h->to); + queue_empty(STATE_SYNC(internal), h->from, h->to); + buffer_iterate(STATE_SYNC(buffer), h, buffer_remove); + return 1; + } + + return 0; +} + +static void nack_post_send(const struct nlnetwork *net, struct us_conntrack *u) +{ + unsigned int size = sizeof(struct nlnetwork); + struct nlmsghdr *nlh = (struct nlmsghdr *) ((void *) net + size); + + if (NFNL_MSG_TYPE(ntohs(nlh->nlmsg_type)) == IPCTNL_MSG_CT_DELETE) { + buffer_add(STATE_SYNC(buffer), net, + ntohl(nlh->nlmsg_len) + size); + } else if (u != NULL) { + unsigned int *seq; + struct list_head *n; + struct cache_nack *cn; + + cn = (struct cache_nack *) + cache_get_extra(STATE_SYNC(internal), u); + cn->seq = ntohl(net->seq); + if (cn->head.next != LIST_POISON1 && + cn->head.prev != LIST_POISON2) + list_del(&cn->head); + + INIT_LIST_HEAD(&cn->head); + list_add(&cn->head, &queue); + } +} + +struct sync_mode nack = { + .internal_cache_flags = LIFETIME, + .external_cache_flags = LIFETIME, + .internal_cache_extra = &cache_nack_extra, + .init = nack_init, + .kill = nack_kill, + .local = nack_local, + .pre_recv = nack_pre_recv, + .post_send = nack_post_send, +}; diff --git a/src/sync-notrack.c b/src/sync-notrack.c new file mode 100644 index 0000000..2b5ae38 --- /dev/null +++ b/src/sync-notrack.c @@ -0,0 +1,127 @@ +/* + * (C) 2006-2007 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "conntrackd.h" +#include "sync.h" +#include "network.h" +#include "us-conntrack.h" +#include "alarm.h" + +static void refresher(struct alarm_list *a, void *data) +{ + struct us_conntrack *u = data; + char buf[8192]; + int size; + + if (nfct_get_attr_u32(u->ct, ATTR_STATUS) & IPS_DYING) { + + debug_ct(u->ct, "persistence destroy"); + + size = build_network_msg(NFCT_Q_DESTROY, + STATE(subsys_event), + u->ct, + buf, + sizeof(buf)); + + __cache_del(u->cache, u->ct); + mcast_send_netmsg(STATE_SYNC(mcast_client), buf); + } else { + + debug_ct(u->ct, "persistence update"); + + a->expires = random() % CONFIG(refresh) + 1; + size = build_network_msg(NFCT_Q_UPDATE, + STATE(subsys_event), + u->ct, + buf, + sizeof(buf)); + mcast_send_netmsg(STATE_SYNC(mcast_client), buf); + } +} + +static void cache_notrack_add(struct us_conntrack *u, void *data) +{ + struct alarm_list *alarm = data; + + init_alarm(alarm); + set_alarm_expiration(alarm, (random() % conf.refresh) + 1); + set_alarm_data(alarm, u); + set_alarm_function(alarm, refresher); + add_alarm(alarm); +} + +static void cache_notrack_update(struct us_conntrack *u, void *data) +{ + struct alarm_list *alarm = data; + mod_alarm(alarm, (random() % conf.refresh) + 1); +} + +static void cache_notrack_destroy(struct us_conntrack *u, void *data) +{ + struct alarm_list *alarm = data; + del_alarm(alarm); +} + +static struct cache_extra cache_notrack_extra = { + .size = sizeof(struct alarm_list), + .add = cache_notrack_add, + .update = cache_notrack_update, + .destroy = cache_notrack_destroy +}; + +static int notrack_pre_recv(const struct nlnetwork *net) +{ + unsigned int exp_seq; + + /* + * Ignore error messages: Although this message type is not ever + * generated in notrack mode, we don't want to crash the daemon + * if someone nuts mixes nack and notrack. + */ + if (net->flags & (NET_RESYNC | NET_NACK)) + return 1; + + /* + * Multicast sequence tracking: we keep track of multicast messages + * although we don't do any explicit message recovery. So, why do + * we do sequence tracking? Just to let know the sysadmin. + * + * Let t be 1 < t < RefreshTime. To ensure consistency, conntrackd + * retransmit every t seconds a message with the state of a certain + * entry even if such entry did not change. This mechanism also + * provides passive resynchronization, in other words, there is + * no facility to request a full synchronization from new nodes that + * just joined the cluster, instead they just get resynchronized in + * RefreshTime seconds at worst case. + */ + mcast_track_seq(net->seq, &exp_seq); + + return 0; +} + +static void notrack_post_send(const struct nlnetwork *n, struct us_conntrack *u) +{ +} + +struct sync_mode notrack = { + .internal_cache_flags = LIFETIME, + .external_cache_flags = TIMER | LIFETIME, + .internal_cache_extra = &cache_notrack_extra, + .pre_recv = notrack_pre_recv, + .post_send = notrack_post_send, +}; diff --git a/src/traffic_stats.c b/src/traffic_stats.c new file mode 100644 index 0000000..b510b77 --- /dev/null +++ b/src/traffic_stats.c @@ -0,0 +1,54 @@ +/* + * (C) 2006 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "cache.h" +#include "hash.h" +#include "conntrackd.h" +#include +#include +#include +#include "us-conntrack.h" +#include + +void update_traffic_stats(struct nf_conntrack *ct) +{ + STATE(bytes)[NFCT_DIR_ORIGINAL] += + nfct_get_attr_u32(ct, ATTR_ORIG_COUNTER_BYTES); + STATE(bytes)[NFCT_DIR_REPLY] += + nfct_get_attr_u32(ct, ATTR_REPL_COUNTER_BYTES); + STATE(packets)[NFCT_DIR_ORIGINAL] += + nfct_get_attr_u32(ct, ATTR_ORIG_COUNTER_PACKETS); + STATE(packets)[NFCT_DIR_REPLY] += + nfct_get_attr_u32(ct, ATTR_REPL_COUNTER_PACKETS); +} + +void dump_traffic_stats(int fd) +{ + char buf[512]; + int size; + u_int64_t bytes = STATE(bytes)[NFCT_DIR_ORIGINAL] + + STATE(bytes)[NFCT_DIR_REPLY]; + u_int64_t packets = STATE(packets)[NFCT_DIR_ORIGINAL] + + STATE(packets)[NFCT_DIR_REPLY]; + + size = sprintf(buf, "traffic processed:\n"); + size += sprintf(buf+size, "%20llu Bytes ", bytes); + size += sprintf(buf+size, "%20llu Pckts\n\n", packets); + + send(fd, buf, size, 0); +} diff --git a/test.sh b/test.sh new file mode 100644 index 0000000..4694236 --- /dev/null +++ b/test.sh @@ -0,0 +1,110 @@ +CONNTRACK=conntrack + +SRC=1.1.1.1 +DST=2.2.2.2 +SPORT=2005 +DPORT=21 + +case $1 in + dump) + echo "Dumping conntrack table" + $CONNTRACK -L + ;; + flush) + echo "Flushing conntrack table" + $CONNTRACK -F + ;; + new) + echo "creating a new conntrack" + $CONNTRACK -I --orig-src $SRC --orig-dst $DST \ + --reply-src $DST --reply-dst $SRC -p tcp \ + --orig-port-src $SPORT --orig-port-dst $DPORT \ + --reply-port-src $DPORT --reply-port-dst $SPORT \ + --state LISTEN -u SEEN_REPLY -t 50 + ;; + new-simple) + echo "creating a new conntrack (simplified)" + $CONNTRACK -I --orig-src $SRC --orig-dst $DST \ + -p tcp --orig-port-src $SPORT --orig-port-dst $DPORT \ + --state LISTEN -u SEEN_REPLY -t 50 + ;; + new-nat) + echo "creating a new conntrack (NAT)" + $CONNTRACK -I --orig-src $SRC --orig-dst $DST \ + -p tcp --orig-port-src $SPORT --orig-port-dst $DPORT \ + --state LISTEN -u SEEN_REPLY,SRC_NAT -t 50 -a 8.8.8.8 + ;; + get) + echo "getting a conntrack" + $CONNTRACK -G --orig-src $SRC --orig-dst $DST \ + -p tcp --orig-port-src $SPORT --orig-port-dst $DPORT \ + --reply-port-src $DPORT --reply-port-dst $SPORT + ;; + change) + echo "change a conntrack" + $CONNTRACK -U --orig-src $SRC --orig-dst $DST \ + --reply-src $DST --reply-dst $SRC -p tcp \ + --orig-port-src $SPORT --orig-port-dst $DPORT \ + --reply-port-src $DPORT --reply-port-dst $SPORT \ + --state TIME_WAIT -u ASSURED,SEEN_REPLY -t 500 + ;; + delete) + $CONNTRACK -D --orig-src $SRC --orig-dst $DST \ + -p tcp --orig-port-src $SPORT --orig-port-dst $DPORT + ;; + output) + proc=$(cat /proc/net/ip_conntrack | wc -l) + netl=$($CONNTRACK -L | wc -l) + count=$(cat /proc/sys/net/ipv4/netfilter/ip_conntrack_count) + if [ $proc -ne $netl ]; then + echo "proc is $proc and netl is $netl and count is $count" + else + if [ $proc -ne $count ]; then + echo "proc is $proc and netl is $netl and count is $count" + else + echo "now $proc" + fi + fi + ;; + dump-expect) + $CONNTRACK -L expect + ;; + flush-expect) + $CONNTRACK -F expect + ;; + create-expect) + # requires modprobe ip_conntrack_ftp + $CONNTRACK -I expect --orig-src $SRC --orig-dst $DST \ + --tuple-src 4.4.4.4 --tuple-dst 5.5.5.5 \ + --mask-src 255.255.255.0 --mask-dst 255.255.255.255 \ + -p tcp --orig-port-src $SPORT --orig-port-dst $DPORT \ + -t 200 --tuple-port-src 10 --tuple-port-dst 300 \ + --mask-port-src 10 --mask-port-dst 300 + ;; + get-expect) + $CONNTRACK -G expect --orig-src 4.4.4.4 --orig-dst 5.5.5.5 \ + --p tcp --orig-port-src 0 --orig-port-dst 0 \ + --mask-port-src 10 --mask-port-dst 11 + ;; + delete-expect) + $CONNTRACK -D expect --orig-src 4.4.4.4 \ + --orig-dst 5.5.5.5 -p tcp --orig-port-src 0 \ + --orig-port-dst 0 --mask-port-src 10 --mask-port-dst 11 + ;; + *) + echo "Usage: $0 [dump" + echo " |new" + echo " |new-simple" + echo " |new-nat" + echo " |get" + echo " |change" + echo " |delete" + echo " |output" + echo " |flush" + echo " |dump-expect" + echo " |flush-expect" + echo " |create-expect" + echo " |get-expect" + echo " |delete-expect]" + ;; +esac -- cgit v1.2.3 From 9212740cfbefc500c93f55b2b5289b1740e9c9e0 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Tue, 17 Apr 2007 00:28:16 +0000 Subject: - bump version to 0.9.3 - show 'conntrack-tools' string when 'conntrack -V' is issued - include missing headers to include/Makefile.am --- Makefile.am | 2 +- configure.in | 2 +- include/Makefile.am | 3 ++- src/conntrack.c | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/Makefile.am b/Makefile.am index 07a5ea0..d60c935 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5,7 +5,7 @@ include Make_global.am AUTOMAKE_OPTIONS = foreign dist-bzip2 1.6 man_MANS = conntrack.8 -EXTRA_DIST = Make_global.am ChangeLog TODO +EXTRA_DIST = $(man_MANS) Make_global.am ChangeLog TODO SUBDIRS = src extensions DIST_SUBDIRS = include src extensions examples diff --git a/configure.in b/configure.in index 5bd9815..e58bfc4 100644 --- a/configure.in +++ b/configure.in @@ -1,4 +1,4 @@ -AC_INIT(conntrackd, 0.9.2, pablo@netfilter.org) +AC_INIT(conntrackd, 0.9.3, pablo@netfilter.org) AC_CANONICAL_SYSTEM diff --git a/include/Makefile.am b/include/Makefile.am index e669d73..a7716d9 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -1,5 +1,6 @@ noinst_HEADERS = alarm.h jhash.h slist.h cache.h linux_list.h \ sync.h conntrackd.h local.h us-conntrack.h \ - debug.h log.h hash.h mcast.h buffer.h + debug.h log.h hash.h mcast.h buffer.h conntrack.h \ + state_helper.h network.h ignore.h diff --git a/src/conntrack.c b/src/conntrack.c index 30fbf69..b550c39 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -1104,7 +1104,7 @@ int main(int argc, char *argv[]) break; case CT_VERSION: - fprintf(stdout, "%s v%s\n", PROGNAME, VERSION); + printf("%s v%s (conntrack-tools)\n", PROGNAME, VERSION); break; case CT_HELP: usage(argv[0]); -- cgit v1.2.3 From 37ef0a638d19ca5145f6d4868e42b7aa2c735d46 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Sun, 6 May 2007 17:36:13 +0000 Subject: - add warning note to ctnl_test.c: old API is deprecated - split expect_api_test.c into small example files expect_*.c - introduce alias tags for original tuple attributes - introduce nfexp_sizeof and nfexp_maxsize - build expectation attributes iif they are set - fix l3num setting in expect/build.c --- conntrack.8 | 9 +- examples/cli/test.sh | 11 +- extensions/Makefile.am | 4 +- extensions/libct_proto_icmp.c | 56 ++-- extensions/libct_proto_sctp.c | 164 ---------- extensions/libct_proto_tcp.c | 157 +++++---- extensions/libct_proto_udp.c | 93 ++++-- include/conntrack.h | 28 +- src/conntrack.c | 735 ++++++++++++++++++++++++------------------ 9 files changed, 643 insertions(+), 614 deletions(-) delete mode 100644 extensions/libct_proto_sctp.c (limited to 'src') diff --git a/conntrack.8 b/conntrack.8 index 307180b..6c5d9d6 100644 --- a/conntrack.8 +++ b/conntrack.8 @@ -1,6 +1,7 @@ -.TH CONNTRACK 8 "Jun 23, 2005" "" "" +.TH CONNTRACK 8 "May 6, 2007" "" "" .\" Man page written by Harald Welte . +Man page written by Harald Welte and Pablo Neira Ayuso . diff --git a/examples/cli/test.sh b/examples/cli/test.sh index 4694236..36c4826 100644 --- a/examples/cli/test.sh +++ b/examples/cli/test.sh @@ -32,7 +32,7 @@ case $1 in echo "creating a new conntrack (NAT)" $CONNTRACK -I --orig-src $SRC --orig-dst $DST \ -p tcp --orig-port-src $SPORT --orig-port-dst $DPORT \ - --state LISTEN -u SEEN_REPLY,SRC_NAT -t 50 -a 8.8.8.8 + --state LISTEN -u SEEN_REPLY -t 50 --dst-nat 8.8.8.8 ;; get) echo "getting a conntrack" @@ -78,18 +78,17 @@ case $1 in --tuple-src 4.4.4.4 --tuple-dst 5.5.5.5 \ --mask-src 255.255.255.0 --mask-dst 255.255.255.255 \ -p tcp --orig-port-src $SPORT --orig-port-dst $DPORT \ - -t 200 --tuple-port-src 10 --tuple-port-dst 300 \ + -t 200 --tuple-port-src 10240 --tuple-port-dst 10241\ --mask-port-src 10 --mask-port-dst 300 ;; get-expect) $CONNTRACK -G expect --orig-src 4.4.4.4 --orig-dst 5.5.5.5 \ - --p tcp --orig-port-src 0 --orig-port-dst 0 \ - --mask-port-src 10 --mask-port-dst 11 + --p tcp --orig-port-src 10240 --orig-port-dst 10241 ;; delete-expect) $CONNTRACK -D expect --orig-src 4.4.4.4 \ - --orig-dst 5.5.5.5 -p tcp --orig-port-src 0 \ - --orig-port-dst 0 --mask-port-src 10 --mask-port-dst 11 + --orig-dst 5.5.5.5 -p tcp --orig-port-src 10240 \ + --orig-port-dst 10241 ;; *) echo "Usage: $0 [dump" diff --git a/extensions/Makefile.am b/extensions/Makefile.am index 5366ee3..db97c4d 100644 --- a/extensions/Makefile.am +++ b/extensions/Makefile.am @@ -4,7 +4,7 @@ AM_CFLAGS=-fPIC -Wall LIBS= pkglib_LTLIBRARIES = ct_proto_tcp.la ct_proto_udp.la \ - ct_proto_icmp.la ct_proto_sctp.la + ct_proto_icmp.la ct_proto_tcp_la_SOURCES = libct_proto_tcp.c ct_proto_tcp_la_LDFLAGS = -module -avoid-version @@ -12,5 +12,3 @@ ct_proto_udp_la_SOURCES = libct_proto_udp.c ct_proto_udp_la_LDFLAGS = -module -avoid-version ct_proto_icmp_la_SOURCES = libct_proto_icmp.c ct_proto_icmp_la_LDFLAGS = -module -avoid-version -ct_proto_sctp_la_SOURCES = libct_proto_sctp.c -ct_proto_sctp_la_LDFLAGS = -module -avoid-version diff --git a/extensions/libct_proto_icmp.c b/extensions/libct_proto_icmp.c index e7cb04d..7b02dec 100644 --- a/extensions/libct_proto_icmp.c +++ b/extensions/libct_proto_icmp.c @@ -1,6 +1,6 @@ /* - * (C) 2005 by Pablo Neira Ayuso - * Harald Welte + * (C) 2005-2007 by Pablo Neira Ayuso + * 2005 by 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 @@ -43,35 +43,42 @@ static u_int8_t invmap[] [ICMP_ADDRESSREPLY] = ICMP_ADDRESS + 1}; static int parse(char c, char *argv[], - struct nfct_tuple *orig, - struct nfct_tuple *reply, - struct nfct_tuple *exptuple, - struct nfct_tuple *mask, - union nfct_protoinfo *proto, + struct nf_conntrack *ct, + struct nf_conntrack *exptuple, + struct nf_conntrack *mask, unsigned int *flags) { switch(c) { case '1': - if (optarg) { - orig->l4dst.icmp.type = atoi(optarg); - reply->l4dst.icmp.type = - invmap[orig->l4dst.icmp.type] - 1; - *flags |= ICMP_TYPE; - } + if (!optarg) + break; + + nfct_set_attr_u8(ct, + ATTR_ICMP_TYPE, + atoi(optarg)); + /* FIXME: + reply->l4dst.icmp.type = + invmap[orig->l4dst.icmp.type] - 1; + */ + *flags |= ICMP_TYPE; break; case '2': - if (optarg) { - orig->l4dst.icmp.code = atoi(optarg); - reply->l4dst.icmp.code = 0; - *flags |= ICMP_CODE; - } + if (!optarg) + break; + + nfct_set_attr_u8(ct, + ATTR_ICMP_CODE, + atoi(optarg)); + *flags |= ICMP_CODE; break; case '3': - if (optarg) { - orig->l4src.icmp.id = htons(atoi(optarg)); - reply->l4dst.icmp.id = 0; - *flags |= ICMP_ID; - } + if (!optarg) + break; + + nfct_set_attr_u16(ct, + ATTR_ICMP_ID, + htons(atoi(optarg))); + *flags |= ICMP_ID; break; } return 1; @@ -79,8 +86,7 @@ static int parse(char c, char *argv[], static int final_check(unsigned int flags, unsigned int command, - struct nfct_tuple *orig, - struct nfct_tuple *reply) + struct nf_conntrack *ct) { if (!(flags & ICMP_TYPE)) return 0; diff --git a/extensions/libct_proto_sctp.c b/extensions/libct_proto_sctp.c deleted file mode 100644 index 1c8f0d1..0000000 --- a/extensions/libct_proto_sctp.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - * (C) 2005 by Harald Welte - * 2006 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 -#include -#include -#include -#include /* For htons */ -#include "conntrack.h" -#include -#include - -static struct option opts[] = { - {"orig-port-src", 1, 0, '1'}, - {"orig-port-dst", 1, 0, '2'}, - {"reply-port-src", 1, 0, '3'}, - {"reply-port-dst", 1, 0, '4'}, - {"state", 1, 0, '5'}, - {"tuple-port-src", 1, 0, '6'}, - {"tuple-port-dst", 1, 0, '7'}, - {0, 0, 0, 0} -}; - -static const char *states[] = { - "NONE", - "CLOSED", - "COOKIE_WAIT", - "COOKIE_ECHOED", - "ESTABLISHED", - "SHUTDOWN_SENT", - "SHUTDOWN_RECV", - "SHUTDOWN_ACK_SENT", -}; - -static void help() -{ - fprintf(stdout, "--orig-port-src original source port\n"); - fprintf(stdout, "--orig-port-dst original destination port\n"); - fprintf(stdout, "--reply-port-src reply source port\n"); - fprintf(stdout, "--reply-port-dst reply destination port\n"); - fprintf(stdout, "--state SCTP state, fe. ESTABLISHED\n"); - fprintf(stdout, "--tuple-port-src expectation tuple src port\n"); - fprintf(stdout, "--tuple-port-src expectation tuple dst port\n"); -} - -static int parse_options(char c, char *argv[], - struct nfct_tuple *orig, - struct nfct_tuple *reply, - struct nfct_tuple *exptuple, - struct nfct_tuple *mask, - union nfct_protoinfo *proto, - unsigned int *flags) -{ - switch(c) { - case '1': - if (optarg) { - orig->l4src.sctp.port = htons(atoi(optarg)); - *flags |= SCTP_ORIG_SPORT; - } - break; - case '2': - if (optarg) { - orig->l4dst.sctp.port = htons(atoi(optarg)); - *flags |= SCTP_ORIG_DPORT; - } - break; - case '3': - if (optarg) { - reply->l4src.sctp.port = htons(atoi(optarg)); - *flags |= SCTP_REPL_SPORT; - } - break; - case '4': - if (optarg) { - reply->l4dst.sctp.port = htons(atoi(optarg)); - *flags |= SCTP_REPL_DPORT; - } - break; - case '5': - if (optarg) { - int i; - for (i=0; i<10; i++) { - if (strcmp(optarg, states[i]) == 0) { - /* FIXME: Add state to - * nfct_protoinfo - proto->sctp.state = i; */ - break; - } - } - if (i == 10) { - printf("doh?\n"); - return 0; - } - *flags |= SCTP_STATE; - } - break; - case '6': - if (optarg) { - exptuple->l4src.sctp.port = htons(atoi(optarg)); - *flags |= SCTP_EXPTUPLE_SPORT; - } - break; - case '7': - if (optarg) { - exptuple->l4dst.sctp.port = htons(atoi(optarg)); - *flags |= SCTP_EXPTUPLE_DPORT; - } - - } - return 1; -} - -static int final_check(unsigned int flags, - unsigned int command, - struct nfct_tuple *orig, - struct nfct_tuple *reply) -{ - int ret = 0; - - if ((flags & (SCTP_ORIG_SPORT|SCTP_ORIG_DPORT)) - && !(flags & (SCTP_REPL_SPORT|SCTP_REPL_DPORT))) { - reply->l4src.sctp.port = orig->l4dst.sctp.port; - reply->l4dst.sctp.port = orig->l4src.sctp.port; - ret = 1; - } else if (!(flags & (SCTP_ORIG_SPORT|SCTP_ORIG_DPORT)) - && (flags & (SCTP_REPL_SPORT|SCTP_REPL_DPORT))) { - orig->l4src.sctp.port = reply->l4dst.sctp.port; - orig->l4dst.sctp.port = reply->l4src.sctp.port; - ret = 1; - } - if ((flags & (SCTP_ORIG_SPORT|SCTP_ORIG_DPORT)) - && ((flags & (SCTP_REPL_SPORT|SCTP_REPL_DPORT)))) - ret = 1; - - /* --state is missing and we are trying to create a conntrack */ - if (ret && (command & CT_CREATE) && (!(flags & SCTP_STATE))) - ret = 0; - - return ret; -} - -static struct ctproto_handler sctp = { - .name = "sctp", - .protonum = IPPROTO_SCTP, - .parse_opts = parse_options, - .final_check = final_check, - .help = help, - .opts = opts, - .version = VERSION, -}; - -static void __attribute__ ((constructor)) init(void); - -static void init(void) -{ - register_proto(&sctp); -} diff --git a/extensions/libct_proto_tcp.c b/extensions/libct_proto_tcp.c index ee24206..736bcff 100644 --- a/extensions/libct_proto_tcp.c +++ b/extensions/libct_proto_tcp.c @@ -1,5 +1,5 @@ /* - * (C) 2005 by Pablo Neira Ayuso + * (C) 2005-2007 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 @@ -56,78 +56,112 @@ static void help() fprintf(stdout, "--state TCP state, fe. ESTABLISHED\n"); } -static int parse_options(char c, char *argv[], - struct nfct_tuple *orig, - struct nfct_tuple *reply, - struct nfct_tuple *exptuple, - struct nfct_tuple *mask, - union nfct_protoinfo *proto, +static int parse_options(char c, char *argv[], + struct nf_conntrack *ct, + struct nf_conntrack *exptuple, + struct nf_conntrack *mask, unsigned int *flags) { + int i; + switch(c) { case '1': - if (optarg) { - orig->l4src.tcp.port = htons(atoi(optarg)); - *flags |= TCP_ORIG_SPORT; - } + if (!optarg) + break; + + nfct_set_attr_u16(ct, + ATTR_ORIG_PORT_SRC, + htons(atoi(optarg))); + + *flags |= TCP_ORIG_SPORT; break; case '2': - if (optarg) { - orig->l4dst.tcp.port = htons(atoi(optarg)); - *flags |= TCP_ORIG_DPORT; - } + if (!optarg) + break; + + nfct_set_attr_u16(ct, + ATTR_ORIG_PORT_DST, + htons(atoi(optarg))); + + *flags |= TCP_ORIG_DPORT; break; case '3': - if (optarg) { - reply->l4src.tcp.port = htons(atoi(optarg)); - *flags |= TCP_REPL_SPORT; - } + if (!optarg) + break; + + nfct_set_attr_u16(ct, + ATTR_REPL_PORT_SRC, + htons(atoi(optarg))); + + *flags |= TCP_REPL_SPORT; break; case '4': - if (optarg) { - reply->l4dst.tcp.port = htons(atoi(optarg)); - *flags |= TCP_REPL_DPORT; - } + if (!optarg) + break; + + nfct_set_attr_u16(ct, + ATTR_REPL_PORT_DST, + htons(atoi(optarg))); + + *flags |= TCP_REPL_DPORT; break; case '5': - if (optarg) { - mask->l4src.tcp.port = htons(atoi(optarg)); - *flags |= TCP_MASK_SPORT; - } + if (!optarg) + break; + + nfct_set_attr_u16(mask, + ATTR_ORIG_PORT_SRC, + htons(atoi(optarg))); + + *flags |= TCP_MASK_SPORT; break; case '6': - if (optarg) { - mask->l4dst.tcp.port = htons(atoi(optarg)); - *flags |= TCP_MASK_DPORT; - } + if (!optarg) + break; + + nfct_set_attr_u16(mask, + ATTR_ORIG_PORT_DST, + htons(atoi(optarg))); + + *flags |= TCP_MASK_DPORT; break; case '7': - if (optarg) { - int i; - for (i=0; i<10; i++) { - if (strcmp(optarg, states[i]) == 0) { - proto->tcp.state = i; - break; - } - } - if (i == 10) { - printf("doh?\n"); - return 0; + if (!optarg) + break; + + for (i=0; i<10; i++) { + if (strcmp(optarg, states[i]) == 0) { + nfct_set_attr_u8(ct, + ATTR_TCP_STATE, + i); + break; } - *flags |= TCP_STATE; } + if (i == 10) { + printf("doh?\n"); + return 0; + } + *flags |= TCP_STATE; break; case '8': - if (optarg) { - exptuple->l4src.tcp.port = htons(atoi(optarg)); - *flags |= TCP_EXPTUPLE_SPORT; - } + if (!optarg) + break; + + nfct_set_attr_u16(exptuple, + ATTR_ORIG_PORT_SRC, + htons(atoi(optarg))); + + *flags |= TCP_EXPTUPLE_SPORT; break; case '9': - if (optarg) { - exptuple->l4dst.tcp.port = htons(atoi(optarg)); - *flags |= TCP_EXPTUPLE_DPORT; - } + if (!optarg) + break; + + nfct_set_attr_u16(exptuple, + ATTR_ORIG_PORT_DST, + htons(atoi(optarg))); + + *flags |= TCP_EXPTUPLE_DPORT; break; } return 1; @@ -135,20 +169,27 @@ static int parse_options(char c, char *argv[], static int final_check(unsigned int flags, unsigned int command, - struct nfct_tuple *orig, - struct nfct_tuple *reply) + struct nf_conntrack *ct) { int ret = 0; - + if ((flags & (TCP_ORIG_SPORT|TCP_ORIG_DPORT)) && !(flags & (TCP_REPL_SPORT|TCP_REPL_DPORT))) { - reply->l4src.tcp.port = orig->l4dst.tcp.port; - reply->l4dst.tcp.port = orig->l4src.tcp.port; + nfct_set_attr_u16(ct, + ATTR_REPL_PORT_SRC, + nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST)); + nfct_set_attr_u16(ct, + ATTR_REPL_PORT_DST, + nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC)); ret = 1; } else if (!(flags & (TCP_ORIG_SPORT|TCP_ORIG_DPORT)) && (flags & (TCP_REPL_SPORT|TCP_REPL_DPORT))) { - orig->l4src.tcp.port = reply->l4dst.tcp.port; - orig->l4dst.tcp.port = reply->l4src.tcp.port; + nfct_set_attr_u16(ct, + ATTR_ORIG_PORT_SRC, + nfct_get_attr_u16(ct, ATTR_REPL_PORT_DST)); + nfct_set_attr_u16(ct, + ATTR_ORIG_PORT_DST, + nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC)); ret = 1; } if ((flags & (TCP_ORIG_SPORT|TCP_ORIG_DPORT)) diff --git a/extensions/libct_proto_udp.c b/extensions/libct_proto_udp.c index 48079e0..1bc70d4 100644 --- a/extensions/libct_proto_udp.c +++ b/extensions/libct_proto_udp.c @@ -1,5 +1,5 @@ /* - * (C) 2005 by Pablo Neira Ayuso + * (C) 2005-2007 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 @@ -10,11 +10,13 @@ #include #include #include +#include #include /* For htons */ -#include "conntrack.h" #include #include +#include "conntrack.h" + static struct option opts[] = { {"orig-port-src", 1, 0, '1'}, {"orig-port-dst", 1, 0, '2'}, @@ -39,38 +41,54 @@ static void help() fprintf(stdout, "--tuple-port-src expectation tuple dst port\n"); } -static int parse_options(char c, char *argv[], - struct nfct_tuple *orig, - struct nfct_tuple *reply, +static int parse_options(char c, char *argv[], + struct nf_conntrack *ct, struct nfct_tuple *exptuple, struct nfct_tuple *mask, - union nfct_protoinfo *proto, unsigned int *flags) { + int i; + switch(c) { case '1': - if (optarg) { - orig->l4src.udp.port = htons(atoi(optarg)); - *flags |= UDP_ORIG_SPORT; - } + if (!optarg) + break; + + nfct_set_attr_u16(ct, + ATTR_ORIG_PORT_SRC, + htons(atoi(optarg))); + + *flags |= UDP_ORIG_SPORT; break; case '2': - if (optarg) { - orig->l4dst.udp.port = htons(atoi(optarg)); - *flags |= UDP_ORIG_DPORT; - } + if (!optarg) + break; + + nfct_set_attr_u16(ct, + ATTR_ORIG_PORT_DST, + htons(atoi(optarg))); + + *flags |= UDP_ORIG_DPORT; break; case '3': - if (optarg) { - reply->l4src.udp.port = htons(atoi(optarg)); - *flags |= UDP_REPL_SPORT; - } + if (!optarg) + break; + + nfct_set_attr_u16(ct, + ATTR_REPL_PORT_SRC, + htons(atoi(optarg))); + + *flags |= UDP_REPL_SPORT; break; case '4': - if (optarg) { - reply->l4dst.udp.port = htons(atoi(optarg)); - *flags |= UDP_REPL_DPORT; - } + if (!optarg) + break; + + nfct_set_attr_u16(ct, + ATTR_REPL_PORT_DST, + htons(atoi(optarg))); + + *flags |= UDP_REPL_DPORT; break; case '5': if (optarg) { @@ -95,32 +113,41 @@ static int parse_options(char c, char *argv[], exptuple->l4dst.udp.port = htons(atoi(optarg)); *flags |= UDP_EXPTUPLE_DPORT; } - + break; } return 1; } static int final_check(unsigned int flags, unsigned int command, - struct nfct_tuple *orig, - struct nfct_tuple *reply) + struct nf_conntrack *ct) { + int ret = 0; + if ((flags & (UDP_ORIG_SPORT|UDP_ORIG_DPORT)) && !(flags & (UDP_REPL_SPORT|UDP_REPL_DPORT))) { - reply->l4src.udp.port = orig->l4dst.udp.port; - reply->l4dst.udp.port = orig->l4src.udp.port; - return 1; + nfct_set_attr_u16(ct, + ATTR_REPL_PORT_SRC, + nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST)); + nfct_set_attr_u16(ct, + ATTR_REPL_PORT_DST, + nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC)); + ret = 1; } else if (!(flags & (UDP_ORIG_SPORT|UDP_ORIG_DPORT)) && (flags & (UDP_REPL_SPORT|UDP_REPL_DPORT))) { - orig->l4src.udp.port = reply->l4dst.udp.port; - orig->l4dst.udp.port = reply->l4src.udp.port; - return 1; + nfct_set_attr_u16(ct, + ATTR_ORIG_PORT_SRC, + nfct_get_attr_u16(ct, ATTR_REPL_PORT_DST)); + nfct_set_attr_u16(ct, + ATTR_ORIG_PORT_DST, + nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC)); + ret = 1; } if ((flags & (UDP_ORIG_SPORT|UDP_ORIG_DPORT)) && ((flags & (UDP_REPL_SPORT|UDP_REPL_DPORT)))) - return 1; + ret = 1; - return 0; + return ret; } static struct ctproto_handler udp = { diff --git a/include/conntrack.h b/include/conntrack.h index fb3b9b6..50aec19 100644 --- a/include/conntrack.h +++ b/include/conntrack.h @@ -1,10 +1,6 @@ #ifndef _CONNTRACK_H #define _CONNTRACK_H -#ifdef HAVE_CONFIG_H -#include "../config.h" -#endif - #include "linux_list.h" #include #include @@ -122,9 +118,18 @@ enum options { CT_OPT_FAMILY_BIT = 16, CT_OPT_FAMILY = (1 << CT_OPT_FAMILY_BIT), - CT_OPT_MAX_BIT = CT_OPT_FAMILY_BIT + CT_OPT_SRC_NAT_BIT = 17, + CT_OPT_SRC_NAT = (1 << CT_OPT_SRC_NAT_BIT), + + CT_OPT_DST_NAT_BIT = 18, + CT_OPT_DST_NAT = (1 << CT_OPT_DST_NAT_BIT), + + CT_OPT_XML_BIT = 19, + CT_OPT_XML = (1 << CT_OPT_XML_BIT), + + CT_OPT_MAX = CT_OPT_XML_BIT }; -#define NUMBER_OF_OPT CT_OPT_MAX_BIT+1 +#define NUMBER_OF_OPT CT_OPT_MAX+1 struct ctproto_handler { struct list_head head; @@ -136,17 +141,14 @@ struct ctproto_handler { enum ctattr_protoinfo protoinfo_attr; int (*parse_opts)(char c, char *argv[], - struct nfct_tuple *orig, - struct nfct_tuple *reply, - struct nfct_tuple *exptuple, - struct nfct_tuple *mask, - union nfct_protoinfo *proto, + struct nf_conntrack *ct, + struct nf_conntrack *exptuple, + struct nf_conntrack *mask, unsigned int *flags); int (*final_check)(unsigned int flags, unsigned int command, - struct nfct_tuple *orig, - struct nfct_tuple *reply); + struct nf_conntrack *ct); void (*help)(); diff --git a/src/conntrack.c b/src/conntrack.c index b550c39..f3aa06f 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -1,5 +1,5 @@ /* - * (C) 2005 by Pablo Neira Ayuso + * (C) 2005-2007 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 @@ -29,6 +29,8 @@ * Add support for expect creation * 2005-09-24 Harald Welte : * Remove remaints of "-A" + * 2007-04-22 Pablo Neira Ayuso : + * Ported to the new libnetfilter_conntrack API * */ #include @@ -63,7 +65,7 @@ static const char cmd_need_param[NUMBER_OF_CMD] = { 2, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, 0, 2, 2 }; static const char optflags[NUMBER_OF_OPT] -= {'s','d','r','q','p','t','u','z','e','[',']','{','}','a','m','i','f'}; += {'s','d','r','q','p','t','u','z','e','[',']','{','}','a','m','i','f','n','g','x'}; static struct option original_opts[] = { {"dump", 2, 0, 'L'}, @@ -88,10 +90,13 @@ static struct option original_opts[] = { {"tuple-dst", 1, 0, ']'}, {"mask-src", 1, 0, '{'}, {"mask-dst", 1, 0, '}'}, - {"nat-range", 1, 0, 'a'}, + {"nat-range", 1, 0, 'a'}, /* deprecated */ {"mark", 1, 0, 'm'}, - {"id", 2, 0, 'i'}, + {"id", 2, 0, 'i'}, /* deprecated */ {"family", 1, 0, 'f'}, + {"src-nat", 1, 0, 'n'}, + {"dst-nat", 1, 0, 'g'}, + {"xml", 0, 0, 'x'}, {0, 0, 0, 0} }; @@ -113,28 +118,33 @@ static unsigned int global_option_offset = 0; static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = /* Well, it's better than "Re: Linux vs FreeBSD" */ { - /* s d r q p t u z e x y k l a m i f*/ -/*CT_LIST*/ {2,2,2,2,2,0,0,2,0,0,0,0,0,0,2,2,2}, -/*CT_CREATE*/ {2,2,2,2,1,1,1,0,0,0,0,0,0,2,2,0,0}, -/*CT_UPDATE*/ {2,2,2,2,1,2,2,0,0,0,0,0,0,0,2,2,0}, -/*CT_DELETE*/ {2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,2,0}, -/*CT_GET*/ {2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,2,0}, -/*CT_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*CT_EVENT*/ {2,2,2,2,2,0,0,0,2,0,0,0,0,0,2,0,0}, -/*VERSION*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*HELP*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*EXP_LIST*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2}, -/*EXP_CREATE*/{1,1,2,2,1,1,2,0,0,1,1,1,1,0,0,0,0}, -/*EXP_DELETE*/{1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0}, -/*EXP_GET*/ {1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0}, -/*EXP_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*EXP_EVENT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + /* s d r q p t u z e x y k l a m i f n g x */ +/*CT_LIST*/ {2,2,2,2,2,0,0,2,0,0,0,0,0,0,2,2,2,0,0,2}, +/*CT_CREATE*/ {2,2,2,2,1,1,1,0,0,0,0,0,0,2,2,0,0,2,2,0}, +/*CT_UPDATE*/ {2,2,2,2,1,2,2,0,0,0,0,0,0,0,2,2,0,0,0,0}, +/*CT_DELETE*/ {2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0}, +/*CT_GET*/ {2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,2,0,0,0,2}, +/*CT_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*CT_EVENT*/ {2,2,2,2,2,0,0,0,2,0,0,0,0,0,2,0,0,0,0,2}, +/*VERSION*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*HELP*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*EXP_LIST*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,0,0,0}, +/*EXP_CREATE*/{1,1,2,2,1,1,2,0,0,1,1,1,1,0,0,0,0,0,0,0}, +/*EXP_DELETE*/{1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*EXP_GET*/ {1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*EXP_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*EXP_EVENT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, }; static char *lib_dir = CONNTRACK_LIB_DIR; static LIST_HEAD(proto_list); +static unsigned int options; +static unsigned int command; + +#define CT_COMPARISON (CT_OPT_PROTO | CT_OPT_ORIG | CT_OPT_REPL | CT_OPT_MARK) + void register_proto(struct ctproto_handler *h) { if (strcmp(h->version, VERSION) != 0) { @@ -328,7 +338,7 @@ err2str(int err, enum action command) return table[i].message; } - return strerror(err); + return strerror(-err); } #define PARSE_STATUS 0 @@ -340,9 +350,8 @@ static struct parse_parameter { size_t size; unsigned int value[6]; } parse_array[PARSE_MAX] = { - { {"ASSURED", "SEEN_REPLY", "UNSET", "SRC_NAT", "DST_NAT","FIXED_TIMEOUT"}, 6, - { IPS_ASSURED, IPS_SEEN_REPLY, 0, - IPS_SRC_NAT_DONE, IPS_DST_NAT_DONE, IPS_FIXED_TIMEOUT} }, + { {"ASSURED", "SEEN_REPLY", "UNSET", "FIXED_TIMEOUT"}, 4, + { IPS_ASSURED, IPS_SEEN_REPLY, 0, IPS_FIXED_TIMEOUT} }, { {"ALL", "NEW", "UPDATES", "DESTROY"}, 4, {~0U, NF_NETLINK_CONNTRACK_NEW, NF_NETLINK_CONNTRACK_UPDATE, NF_NETLINK_CONNTRACK_DESTROY} }, @@ -354,7 +363,17 @@ do_parse_parameter(const char *str, size_t strlen, unsigned int *value, { int i, ret = 0; struct parse_parameter *p = &parse_array[parse_type]; - + + if (strncasecmp(str, "SRC_NAT", strlen) == 0) { + printf("skipping SRC_NAT, use --src-nat instead\n"); + return 1; + } + + if (strncasecmp(str, "DST_NAT", strlen) == 0) { + printf("skipping DST_NAT, use --dst-nat instead\n"); + return 1; + } + for (i = 0; i < p->size; i++) if (strncasecmp(str, p->parameter[i], strlen) == 0) { *value |= p->value[i]; @@ -430,7 +449,7 @@ struct addr_parse { unsigned int family; }; -int __parse_inetaddr(const char *cp, struct addr_parse *parse) +int parse_inetaddr(const char *cp, struct addr_parse *parse) { if (inet_aton(cp, &parse->addr)) return AF_INET; @@ -442,12 +461,17 @@ int __parse_inetaddr(const char *cp, struct addr_parse *parse) exit_error(PARAMETER_PROBLEM, "Invalid IP address `%s'.", cp); } -int parse_inetaddr(const char *cp, union nfct_address *address) +union ct_address { + u_int32_t v4; + u_int32_t v6[4]; +}; + +int parse_addr(const char *cp, union ct_address *address) { struct addr_parse parse; int ret; - - if ((ret = __parse_inetaddr(cp, &parse)) == AF_INET) + + if ((ret = parse_inetaddr(cp, &parse)) == AF_INET) address->v4 = parse.addr.s_addr; else if (ret == AF_INET6) memcpy(address->v6, &parse.addr6, sizeof(parse.addr6)); @@ -457,73 +481,43 @@ int parse_inetaddr(const char *cp, union nfct_address *address) /* Shamelessly stolen from libipt_DNAT ;). Ranges expected in network order. */ static void -nat_parse(char *arg, int portok, struct nfct_nat *range) +nat_parse(char *arg, int portok, struct nf_conntrack *obj, int type) { char *colon, *dash, *error; - struct addr_parse parse; + union ct_address parse; - memset(range, 0, sizeof(range)); colon = strchr(arg, ':'); if (colon) { - int port; + u_int16_t port; if (!portok) exit_error(PARAMETER_PROBLEM, "Need TCP or UDP with port specification"); port = atoi(colon+1); - if (port == 0 || port > 65535) + if (port == 0) exit_error(PARAMETER_PROBLEM, "Port `%s' not valid\n", colon+1); error = strchr(colon+1, ':'); if (error) exit_error(PARAMETER_PROBLEM, - "Invalid port:port syntax - use dash\n"); - - dash = strchr(colon, '-'); - if (!dash) { - range->l4min.tcp.port - = range->l4max.tcp.port - = htons(port); - } else { - int maxport; - - maxport = atoi(dash + 1); - if (maxport == 0 || maxport > 65535) - exit_error(PARAMETER_PROBLEM, - "Port `%s' not valid\n", dash+1); - if (maxport < port) - /* People are stupid. */ - exit_error(PARAMETER_PROBLEM, - "Port range `%s' funky\n", colon+1); - range->l4min.tcp.port = htons(port); - range->l4max.tcp.port = htons(maxport); - } - /* Starts with a colon? No IP info... */ - if (colon == arg) - return; - *colon = '\0'; - } + "Invalid port:port syntax\n"); - dash = strchr(arg, '-'); - if (colon && dash && dash > colon) - dash = NULL; - - if (dash) - *dash = '\0'; + if (type == CT_OPT_SRC_NAT) + nfct_set_attr_u16(obj, ATTR_SNAT_PORT, port); + else if (type == CT_OPT_DST_NAT) + nfct_set_attr_u16(obj, ATTR_DNAT_PORT, port); + } - if (__parse_inetaddr(arg, &parse) != AF_INET) + if (parse_addr(arg, &parse) != AF_INET) return; - range->min_ip = parse.addr.s_addr; - if (dash) { - if (__parse_inetaddr(dash+1, &parse) != AF_INET) - return; - range->max_ip = parse.addr.s_addr; - } else - range->max_ip = parse.addr.s_addr; + if (type == CT_OPT_SRC_NAT) + nfct_set_attr_u32(obj, ATTR_SNAT_IPV4, parse.v4); + else if (type == CT_OPT_DST_NAT) + nfct_set_attr_u32(obj, ATTR_DNAT_IPV4, parse.v4); } static void event_sighandler(int s) @@ -548,10 +542,12 @@ static const char usage_tables[] = static const char usage_conntrack_parameters[] = "Conntrack parameters and options:\n" - " -a, --nat-range min_ip[-max_ip]\tNAT ip range\n" + " -n, --src-nat ip\tsource NAT ip\n" + " -g, --dst-nat ip\tdestination NAT ip\n" " -m, --mark mark\t\t\tSet mark\n" " -e, --event-mask eventmask\t\tEvent mask, eg. NEW,DESTROY\n" " -z, --zero \t\t\t\tZero counters while listing\n" + " -x, --xml \t\t\t\tDisplay output in XML format\n"; ; static const char usage_expectation_parameters[] = @@ -571,7 +567,6 @@ static const char usage_parameters[] = " -f, --family proto\t\tLayer 3 Protocol, eg. 'ipv6'\n" " -t, --timeout timeout\t\tSet timeout\n" " -u, --status status\t\tSet status, eg. ASSURED\n" - " -i, --id [id]\t\t\tShow or set conntrack ID\n" ; @@ -586,33 +581,78 @@ void usage(char *prog) { fprintf(stdout, "\n%s", usage_parameters); } -#define CT_COMPARISON (CT_OPT_PROTO | CT_OPT_ORIG | CT_OPT_REPL | CT_OPT_MARK) +unsigned int output_flags = NFCT_O_DEFAULT; + +static int event_cb(enum nf_conntrack_msg_type type, + struct nf_conntrack *ct, + void *data) +{ + char buf[1024]; + struct nf_conntrack *obj = data; + + if (options & CT_COMPARISON && !nfct_compare(obj, ct)) + return NFCT_CB_CONTINUE; + + nfct_snprintf(buf, 1024, ct, type, output_flags, 0); + printf("%s\n", buf); + + return NFCT_CB_CONTINUE; +} + +static int dump_cb(enum nf_conntrack_msg_type type, + struct nf_conntrack *ct, + void *data) +{ + char buf[1024]; + struct nf_conntrack *obj = data; + + if (options & CT_COMPARISON && !nfct_compare(obj, ct)) + return NFCT_CB_CONTINUE; + + nfct_snprintf(buf, 1024, ct, NFCT_T_UNKNOWN, output_flags, 0); + printf("%s\n", buf); + + return NFCT_CB_CONTINUE; +} + +static int dump_exp_cb(enum nf_conntrack_msg_type type, + struct nf_expect *exp, + void *data) +{ + char buf[1024]; + + nfexp_snprintf(buf, 1024, exp, NFCT_T_UNKNOWN, NFCT_O_DEFAULT, 0); + printf("%s\n", buf); + + return NFCT_CB_CONTINUE; +} -static struct nfct_tuple orig, reply, mask; -static struct nfct_tuple exptuple; static struct ctproto_handler *h; -static union nfct_protoinfo proto; -static struct nfct_nat range; -static struct nfct_conntrack *ct; -static struct nfct_expect *exp; -static unsigned long timeout; -static unsigned int status; -static unsigned int mark; -static unsigned int id = NFCT_ANY_ID; -static struct nfct_conntrack_compare cmp; int main(int argc, char *argv[]) { int c; - unsigned int command = 0, options = 0; - unsigned int type = 0, event_mask = 0; - unsigned int l3flags = 0, l4flags = 0, metaflags = 0; + unsigned int type = 0, event_mask = 0, l4flags = 0, status = 0; int res = 0; int family = AF_UNSPEC; - struct nfct_conntrack_compare *pcmp; + char __obj[nfct_maxsize()]; + char __exptuple[nfct_maxsize()]; + char __mask[nfct_maxsize()]; + struct nf_conntrack *obj = (struct nf_conntrack *) __obj; + struct nf_conntrack *exptuple = (struct nf_conntrack *) __exptuple; + struct nf_conntrack *mask = (struct nf_conntrack *) __mask; + char __exp[nfexp_maxsize()]; + struct nf_expect *exp = (struct nf_expect *) __exp; + int l3protonum; + union ct_address ad; + + memset(__obj, 0, sizeof(__obj)); + memset(__exptuple, 0, sizeof(__exptuple)); + memset(__mask, 0, sizeof(__mask)); + memset(__exp, 0, sizeof(__exp)); while ((c = getopt_long(argc, argv, - "L::I::U::D::G::E::F::hVs:d:r:q:p:t:u:e:a:z[:]:{:}:m:i::f:", + "L::I::U::D::G::E::F::hVs:d:r:q:p:t:u:e:a:z[:]:{:}:m:i::f:x", opts, NULL)) != -1) { switch(c) { case 'L': @@ -673,68 +713,99 @@ int main(int argc, char *argv[]) break; case 's': options |= CT_OPT_ORIG_SRC; - if (optarg) { - orig.l3protonum = - parse_inetaddr(optarg, &orig.src); - set_family(&family, orig.l3protonum); - if (orig.l3protonum == AF_INET) - l3flags |= IPV4_ORIG_SRC; - else if (orig.l3protonum == AF_INET6) - l3flags |= IPV6_ORIG_SRC; + if (!optarg) + break; + + l3protonum = parse_addr(optarg, &ad); + set_family(&family, l3protonum); + if (l3protonum == AF_INET) { + nfct_set_attr_u32(obj, + ATTR_ORIG_IPV4_SRC, + ad.v4); + } else if (l3protonum == AF_INET6) { + nfct_set_attr(obj, + ATTR_ORIG_IPV6_SRC, + &ad.v6); } + nfct_set_attr_u8(obj, ATTR_ORIG_L3PROTO, l3protonum); break; case 'd': options |= CT_OPT_ORIG_DST; - if (optarg) { - orig.l3protonum = - parse_inetaddr(optarg, &orig.dst); - set_family(&family, orig.l3protonum); - if (orig.l3protonum == AF_INET) - l3flags |= IPV4_ORIG_DST; - else if (orig.l3protonum == AF_INET6) - l3flags |= IPV6_ORIG_DST; + if (!optarg) + break; + + l3protonum = parse_addr(optarg, &ad); + set_family(&family, l3protonum); + if (l3protonum == AF_INET) { + nfct_set_attr_u32(obj, + ATTR_ORIG_IPV4_DST, + ad.v4); + } else if (l3protonum == AF_INET6) { + nfct_set_attr(obj, + ATTR_ORIG_IPV6_DST, + &ad.v6); } + nfct_set_attr_u8(obj, ATTR_ORIG_L3PROTO, l3protonum); break; case 'r': options |= CT_OPT_REPL_SRC; - if (optarg) { - reply.l3protonum = - parse_inetaddr(optarg, &reply.src); - set_family(&family, reply.l3protonum); - if (orig.l3protonum == AF_INET) - l3flags |= IPV4_REPL_SRC; - else if (orig.l3protonum == AF_INET6) - l3flags |= IPV6_REPL_SRC; + if (!optarg) + break; + + l3protonum = parse_addr(optarg, &ad); + set_family(&family, l3protonum); + if (l3protonum == AF_INET) { + nfct_set_attr_u32(obj, + ATTR_REPL_IPV4_SRC, + ad.v4); + } else if (l3protonum == AF_INET6) { + nfct_set_attr(obj, + ATTR_REPL_IPV6_SRC, + &ad.v6); } + nfct_set_attr_u8(obj, ATTR_REPL_L3PROTO, l3protonum); break; case 'q': options |= CT_OPT_REPL_DST; - if (optarg) { - reply.l3protonum = - parse_inetaddr(optarg, &reply.dst); - set_family(&family, reply.l3protonum); - if (orig.l3protonum == AF_INET) - l3flags |= IPV4_REPL_DST; - else if (orig.l3protonum == AF_INET6) - l3flags |= IPV6_REPL_DST; + if (!optarg) + break; + + l3protonum = parse_addr(optarg, &ad); + set_family(&family, l3protonum); + if (l3protonum == AF_INET) { + nfct_set_attr_u32(obj, + ATTR_REPL_IPV4_DST, + ad.v4); + } else if (l3protonum == AF_INET6) { + nfct_set_attr(obj, + ATTR_REPL_IPV6_DST, + &ad.v6); } + nfct_set_attr_u8(obj, ATTR_REPL_L3PROTO, l3protonum); break; case 'p': options |= CT_OPT_PROTO; h = findproto(optarg); if (!h) exit_error(PARAMETER_PROBLEM, "proto needed\n"); - orig.protonum = h->protonum; - reply.protonum = h->protonum; - exptuple.protonum = h->protonum; - mask.protonum = h->protonum; - opts = merge_options(opts, h->opts, - &h->option_offset); + + nfct_set_attr_u8(obj, ATTR_ORIG_L4PROTO, h->protonum); + nfct_set_attr_u8(obj, ATTR_REPL_L4PROTO, h->protonum); + nfct_set_attr_u8(exptuple, + ATTR_ORIG_L4PROTO, + h->protonum); + nfct_set_attr_u8(mask, + ATTR_ORIG_L4PROTO, + h->protonum); + opts = merge_options(opts, h->opts, &h->option_offset); break; case 't': options |= CT_OPT_TIMEOUT; - if (optarg) - timeout = atol(optarg); + if (!optarg) + continue; + + nfct_set_attr_u32(obj, ATTR_TIMEOUT, atol(optarg)); + nfexp_set_attr_u32(exp, ATTR_EXP_TIMEOUT, atol(optarg)); break; case 'u': { if (!optarg) @@ -742,6 +813,7 @@ int main(int argc, char *argv[]) options |= CT_OPT_STATUS; parse_parameter(optarg, &status, PARSE_STATUS); + nfct_set_attr_u32(obj, ATTR_STATUS, status); break; } case 'e': @@ -753,59 +825,102 @@ int main(int argc, char *argv[]) break; case '{': options |= CT_OPT_MASK_SRC; - if (optarg) { - mask.l3protonum = - parse_inetaddr(optarg, &mask.src); - set_family(&family, mask.l3protonum); + if (!optarg) + break; + + l3protonum = parse_addr(optarg, &ad); + set_family(&family, l3protonum); + if (l3protonum == AF_INET) { + nfct_set_attr_u32(mask, + ATTR_ORIG_IPV4_SRC, + ad.v4); + } else if (l3protonum == AF_INET6) { + nfct_set_attr(mask, + ATTR_ORIG_IPV6_SRC, + &ad.v6); } + nfct_set_attr_u8(mask, ATTR_ORIG_L3PROTO, l3protonum); break; case '}': options |= CT_OPT_MASK_DST; - if (optarg) { - mask.l3protonum = - parse_inetaddr(optarg, &mask.dst); - set_family(&family, mask.l3protonum); + if (!optarg) + break; + + l3protonum = parse_addr(optarg, &ad); + set_family(&family, l3protonum); + if (l3protonum == AF_INET) { + nfct_set_attr_u32(mask, + ATTR_ORIG_IPV4_DST, + ad.v4); + } else if (l3protonum == AF_INET6) { + nfct_set_attr(mask, + ATTR_ORIG_IPV6_DST, + &ad.v6); } + nfct_set_attr_u8(mask, ATTR_ORIG_L3PROTO, l3protonum); break; case '[': options |= CT_OPT_EXP_SRC; - if (optarg) { - exptuple.l3protonum = - parse_inetaddr(optarg, &exptuple.src); - set_family(&family, exptuple.l3protonum); + if (!optarg) + break; + + l3protonum = parse_addr(optarg, &ad); + set_family(&family, l3protonum); + if (l3protonum == AF_INET) { + nfct_set_attr_u32(exptuple, + ATTR_ORIG_IPV4_SRC, + ad.v4); + } else if (l3protonum == AF_INET6) { + nfct_set_attr(exptuple, + ATTR_ORIG_IPV6_SRC, + &ad.v6); } + nfct_set_attr_u8(exptuple, + ATTR_ORIG_L3PROTO, + l3protonum); break; case ']': options |= CT_OPT_EXP_DST; - if (optarg) { - exptuple.l3protonum = - parse_inetaddr(optarg, &exptuple.dst); - set_family(&family, exptuple.l3protonum); + if (!optarg) + break; + + l3protonum = parse_addr(optarg, &ad); + set_family(&family, l3protonum); + if (l3protonum == AF_INET) { + nfct_set_attr_u32(exptuple, + ATTR_ORIG_IPV4_DST, + ad.v4); + } else if (l3protonum == AF_INET6) { + nfct_set_attr(exptuple, + ATTR_ORIG_IPV6_DST, + &ad.v6); } + nfct_set_attr_u8(exptuple, + ATTR_ORIG_L3PROTO, + l3protonum); break; case 'a': - options |= CT_OPT_NATRANGE; + printf("warning: ignoring --nat-range, " + "use --src-nat or --dst-nat instead.\n"); + break; + case 'n': + options |= CT_OPT_SRC_NAT; set_family(&family, AF_INET); - nat_parse(optarg, 1, &range); + nat_parse(optarg, 1, obj, CT_OPT_SRC_NAT); break; + case 'g': + options |= CT_OPT_DST_NAT; + set_family(&family, AF_INET); + nat_parse(optarg, 1, obj, CT_OPT_DST_NAT); case 'm': options |= CT_OPT_MARK; - mark = atol(optarg); - metaflags |= NFCT_MARK; + if (!optarg) + continue; + nfct_set_attr_u32(obj, ATTR_MARK, atol(optarg)); break; - case 'i': { - char *s = NULL; - options |= CT_OPT_ID; - if (optarg) - break; - else if (optind < argc && argv[optind][0] != '-' - && argv[optind][0] != '!') - s = argv[optind++]; - - if (s) - id = atol(s); + case 'i': + printf("warning: ignoring --id. deprecated option.\n"); break; - } case 'f': options |= CT_OPT_FAMILY; if (strncmp(optarg, "ipv4", strlen("ipv4")) == 0) @@ -816,11 +931,14 @@ int main(int argc, char *argv[]) exit_error(PARAMETER_PROBLEM, "Unknown " "protocol family\n"); break; + case 'x': + options |= CT_OPT_XML; + output_flags = NFCT_O_XML; + break; default: if (h && h->parse_opts - &&!h->parse_opts(c - h->option_offset, argv, &orig, - &reply, &exptuple, &mask, &proto, - &l4flags)) + &&!h->parse_opts(c - h->option_offset, argv, obj, + exptuple, mask, &l4flags)) exit_error(PARAMETER_PROBLEM, "parse error\n"); /* Unknown argument... */ @@ -842,7 +960,7 @@ int main(int argc, char *argv[]) if (!(command & CT_HELP) && h && h->final_check - && !h->final_check(l4flags, command, &orig, &reply)) { + && !h->final_check(l4flags, command, obj)) { usage(argv[0]); extension_help(h); exit_error(PARAMETER_PROBLEM, "Missing protocol arguments!\n"); @@ -855,39 +973,18 @@ int main(int argc, char *argv[]) if (!cth) exit_error(OTHER_PROBLEM, "Can't open handler"); - if (options & CT_COMPARISON) { + if (options & CT_COMPARISON && + options & CT_OPT_ZERO) + exit_error(PARAMETER_PROBLEM, "Can't use -z with " + "filtering parameters"); - if (options & CT_OPT_ZERO) - exit_error(PARAMETER_PROBLEM, "Can't use -z " - "with filtering parameters"); + nfct_callback_register(cth, NFCT_T_ALL, dump_cb, obj); - ct = nfct_conntrack_alloc(&orig, &reply, timeout, - &proto, status, mark, id, - NULL); - if (!ct) - exit_error(OTHER_PROBLEM, "Not enough memory"); - - cmp.ct = ct; - cmp.flags = metaflags; - cmp.l3flags = l3flags; - cmp.l4flags = l4flags; - pcmp = &cmp; - } - - if (options & CT_OPT_ID) - nfct_register_callback(cth, - nfct_default_conntrack_display_id, - (void *) pcmp); - else - nfct_register_callback(cth, - nfct_default_conntrack_display, - (void *) pcmp); - if (options & CT_OPT_ZERO) - res = - nfct_dump_conntrack_table_reset_counters(cth, family); + res = nfct_query(cth, NFCT_Q_DUMP_RESET, &family); else - res = nfct_dump_conntrack_table(cth, family); + res = nfct_query(cth, NFCT_Q_DUMP, &family); + nfct_close(cth); break; @@ -895,96 +992,144 @@ int main(int argc, char *argv[]) cth = nfct_open(EXPECT, 0); if (!cth) exit_error(OTHER_PROBLEM, "Can't open handler"); - if (options & CT_OPT_ID) - nfct_register_callback(cth, - nfct_default_expect_display_id, - NULL); - else - nfct_register_callback(cth, - nfct_default_expect_display, - NULL); - res = nfct_dump_expect_list(cth, family); + + nfexp_callback_register(cth, NFCT_T_ALL, dump_exp_cb, NULL); + res = nfexp_query(cth, NFCT_Q_DUMP, &family); nfct_close(cth); break; case CT_CREATE: if ((options & CT_OPT_ORIG) && !(options & CT_OPT_REPL)) { - reply.l3protonum = orig.l3protonum; - memcpy(&reply.src, &orig.dst, sizeof(reply.src)); - memcpy(&reply.dst, &orig.src, sizeof(reply.dst)); + nfct_set_attr_u8(obj, + ATTR_REPL_L3PROTO, + nfct_get_attr_u8(obj, + ATTR_ORIG_L3PROTO)); + if (family == AF_INET) { + nfct_set_attr_u32(obj, + ATTR_REPL_IPV4_SRC, + nfct_get_attr_u32(obj, + ATTR_ORIG_IPV4_DST)); + nfct_set_attr_u32(obj, + ATTR_REPL_IPV4_DST, + nfct_get_attr_u32(obj, + ATTR_ORIG_IPV4_SRC)); + } else if (family == AF_INET6) { + nfct_set_attr(obj, + ATTR_REPL_IPV6_SRC, + nfct_get_attr(obj, + ATTR_ORIG_IPV6_DST)); + nfct_set_attr(obj, + ATTR_REPL_IPV6_DST, + nfct_get_attr(obj, + ATTR_ORIG_IPV6_SRC)); + } } else if (!(options & CT_OPT_ORIG) && (options & CT_OPT_REPL)) { - orig.l3protonum = reply.l3protonum; - memcpy(&orig.src, &reply.dst, sizeof(orig.src)); - memcpy(&orig.dst, &reply.src, sizeof(orig.dst)); + nfct_set_attr_u8(obj, + ATTR_ORIG_L3PROTO, + nfct_get_attr_u8(obj, + ATTR_REPL_L3PROTO)); + if (family == AF_INET) { + nfct_set_attr_u32(obj, + ATTR_ORIG_IPV4_SRC, + nfct_get_attr_u32(obj, + ATTR_REPL_IPV4_DST)); + nfct_set_attr_u32(obj, + ATTR_ORIG_IPV4_DST, + nfct_get_attr_u32(obj, + ATTR_REPL_IPV4_SRC)); + } else if (family == AF_INET6) { + nfct_set_attr(obj, + ATTR_ORIG_IPV6_SRC, + nfct_get_attr(obj, + ATTR_REPL_IPV6_DST)); + nfct_set_attr(obj, + ATTR_ORIG_IPV6_DST, + nfct_get_attr(obj, + ATTR_REPL_IPV6_SRC)); + } } - if (options & CT_OPT_NATRANGE) - ct = nfct_conntrack_alloc(&orig, &reply, timeout, - &proto, status, mark, id, - &range); - else - ct = nfct_conntrack_alloc(&orig, &reply, timeout, - &proto, status, mark, id, - NULL); - if (!ct) - exit_error(OTHER_PROBLEM, "Not Enough memory"); - + cth = nfct_open(CONNTRACK, 0); - if (!cth) { - nfct_conntrack_free(ct); + if (!cth) exit_error(OTHER_PROBLEM, "Can't open handler"); - } - res = nfct_create_conntrack(cth, ct); + + res = nfct_query(cth, NFCT_Q_CREATE, obj); nfct_close(cth); - nfct_conntrack_free(ct); break; case EXP_CREATE: - if (options & CT_OPT_ORIG) - exp = nfct_expect_alloc(&orig, &exptuple, - &mask, timeout, id); - else if (options & CT_OPT_REPL) - exp = nfct_expect_alloc(&reply, &exptuple, - &mask, timeout, id); - if (!exp) - exit_error(OTHER_PROBLEM, "Not enough memory"); + nfexp_set_attr(exp, ATTR_EXP_MASTER, obj); + nfexp_set_attr(exp, ATTR_EXP_EXPECTED, exptuple); + nfexp_set_attr(exp, ATTR_EXP_MASK, mask); cth = nfct_open(EXPECT, 0); - if (!cth) { - nfct_expect_free(exp); + if (!cth) exit_error(OTHER_PROBLEM, "Can't open handler"); - } - res = nfct_create_expectation(cth, exp); - nfct_expect_free(exp); + + res = nfexp_query(cth, NFCT_Q_CREATE, exp); nfct_close(cth); break; case CT_UPDATE: if ((options & CT_OPT_ORIG) && !(options & CT_OPT_REPL)) { - reply.l3protonum = orig.l3protonum; - memcpy(&reply.src, &orig.dst, sizeof(reply.src)); - memcpy(&reply.dst, &orig.src, sizeof(reply.dst)); + nfct_set_attr_u8(obj, + ATTR_REPL_L3PROTO, + nfct_get_attr_u8(obj, + ATTR_ORIG_L3PROTO)); + if (family == AF_INET) { + nfct_set_attr_u32(obj, + ATTR_REPL_IPV4_SRC, + nfct_get_attr_u32(obj, + ATTR_ORIG_IPV4_DST)); + nfct_set_attr_u32(obj, + ATTR_REPL_IPV4_DST, + nfct_get_attr_u32(obj, + ATTR_ORIG_IPV4_SRC)); + } else if (family == AF_INET6) { + nfct_set_attr(obj, + ATTR_REPL_IPV6_SRC, + nfct_get_attr(obj, + ATTR_ORIG_IPV6_DST)); + nfct_set_attr(obj, + ATTR_REPL_IPV6_DST, + nfct_get_attr(obj, + ATTR_ORIG_IPV6_SRC)); + } } else if (!(options & CT_OPT_ORIG) && (options & CT_OPT_REPL)) { - orig.l3protonum = reply.l3protonum; - memcpy(&orig.src, &reply.dst, sizeof(orig.src)); - memcpy(&orig.dst, &reply.src, sizeof(orig.dst)); + nfct_set_attr_u8(obj, + ATTR_ORIG_L3PROTO, + nfct_get_attr_u8(obj, + ATTR_REPL_L3PROTO)); + if (family == AF_INET) { + nfct_set_attr_u32(obj, + ATTR_ORIG_IPV4_SRC, + nfct_get_attr_u32(obj, + ATTR_REPL_IPV4_DST)); + nfct_set_attr_u32(obj, + ATTR_ORIG_IPV4_DST, + nfct_get_attr_u32(obj, + ATTR_REPL_IPV4_SRC)); + } else if (family == AF_INET6) { + nfct_set_attr(obj, + ATTR_ORIG_IPV6_SRC, + nfct_get_attr(obj, + ATTR_REPL_IPV6_DST)); + nfct_set_attr(obj, + ATTR_ORIG_IPV6_DST, + nfct_get_attr(obj, + ATTR_REPL_IPV6_SRC)); + } } - ct = nfct_conntrack_alloc(&orig, &reply, timeout, - &proto, status, mark, id, - NULL); - if (!ct) - exit_error(OTHER_PROBLEM, "Not enough memory"); - + cth = nfct_open(CONNTRACK, 0); - if (!cth) { - nfct_conntrack_free(ct); + if (!cth) exit_error(OTHER_PROBLEM, "Can't open handler"); - } - res = nfct_update_conntrack(cth, ct); - nfct_conntrack_free(ct); + + res = nfct_query(cth, NFCT_Q_UPDATE, obj); nfct_close(cth); break; @@ -995,25 +1140,19 @@ int main(int argc, char *argv[]) cth = nfct_open(CONNTRACK, 0); if (!cth) exit_error(OTHER_PROBLEM, "Can't open handler"); - if (options & CT_OPT_ORIG) - res = nfct_delete_conntrack(cth, &orig, - NFCT_DIR_ORIGINAL, - id); - else if (options & CT_OPT_REPL) - res = nfct_delete_conntrack(cth, &reply, - NFCT_DIR_REPLY, - id); + + res = nfct_query(cth, NFCT_Q_DESTROY, obj); nfct_close(cth); break; case EXP_DELETE: + nfexp_set_attr(exp, ATTR_EXP_EXPECTED, obj); + cth = nfct_open(EXPECT, 0); if (!cth) exit_error(OTHER_PROBLEM, "Can't open handler"); - if (options & CT_OPT_ORIG) - res = nfct_delete_expectation(cth, &orig, id); - else if (options & CT_OPT_REPL) - res = nfct_delete_expectation(cth, &reply, id); + + res = nfexp_query(cth, NFCT_Q_DESTROY, exp); nfct_close(cth); break; @@ -1021,27 +1160,21 @@ int main(int argc, char *argv[]) cth = nfct_open(CONNTRACK, 0); if (!cth) exit_error(OTHER_PROBLEM, "Can't open handler"); - nfct_register_callback(cth, nfct_default_conntrack_display, - NULL); - if (options & CT_OPT_ORIG) - res = nfct_get_conntrack(cth, &orig, - NFCT_DIR_ORIGINAL, id); - else if (options & CT_OPT_REPL) - res = nfct_get_conntrack(cth, &reply, - NFCT_DIR_REPLY, id); + + nfct_callback_register(cth, NFCT_T_ALL, dump_cb, obj); + res = nfct_query(cth, NFCT_Q_GET, obj); nfct_close(cth); break; case EXP_GET: + nfexp_set_attr(exp, ATTR_EXP_MASTER, obj); + cth = nfct_open(EXPECT, 0); if (!cth) exit_error(OTHER_PROBLEM, "Can't open handler"); - nfct_register_callback(cth, nfct_default_expect_display, - NULL); - if (options & CT_OPT_ORIG) - res = nfct_get_expectation(cth, &orig, id); - else if (options & CT_OPT_REPL) - res = nfct_get_expectation(cth, &reply, id); + + nfexp_callback_register(cth, NFCT_T_ALL, dump_exp_cb, NULL); + res = nfexp_query(cth, NFCT_Q_GET, exp); nfct_close(cth); break; @@ -1049,7 +1182,7 @@ int main(int argc, char *argv[]) cth = nfct_open(CONNTRACK, 0); if (!cth) exit_error(OTHER_PROBLEM, "Can't open handler"); - res = nfct_flush_conntrack_table(cth, AF_INET); + res = nfct_query(cth, NFCT_Q_FLUSH, &family); nfct_close(cth); break; @@ -1057,7 +1190,7 @@ int main(int argc, char *argv[]) cth = nfct_open(EXPECT, 0); if (!cth) exit_error(OTHER_PROBLEM, "Can't open handler"); - res = nfct_flush_expectation_table(cth, AF_INET); + res = nfexp_query(cth, NFCT_Q_FLUSH, &family); nfct_close(cth); break; @@ -1070,25 +1203,8 @@ int main(int argc, char *argv[]) if (!cth) exit_error(OTHER_PROBLEM, "Can't open handler"); signal(SIGINT, event_sighandler); - - if (options & CT_COMPARISON) { - ct = nfct_conntrack_alloc(&orig, &reply, timeout, - &proto, status, mark, id, - NULL); - if (!ct) - exit_error(OTHER_PROBLEM, "Not enough memory"); - - cmp.ct = ct; - cmp.flags = metaflags; - cmp.l3flags = l3flags; - cmp.l4flags = l4flags; - pcmp = &cmp; - } - - nfct_register_callback(cth, - nfct_default_conntrack_event_display, - (void *) pcmp); - res = nfct_event_conntrack(cth); + nfct_callback_register(cth, NFCT_T_ALL, event_cb, obj); + res = nfct_catch(cth); nfct_close(cth); break; @@ -1097,9 +1213,8 @@ int main(int argc, char *argv[]) if (!cth) exit_error(OTHER_PROBLEM, "Can't open handler"); signal(SIGINT, event_sighandler); - nfct_register_callback(cth, nfct_default_expect_display, - NULL); - res = nfct_event_expectation(cth); + nfexp_callback_register(cth, NFCT_T_ALL, dump_exp_cb, NULL); + res = nfexp_catch(cth); nfct_close(cth); break; @@ -1123,7 +1238,7 @@ int main(int argc, char *argv[]) } if (res < 0) { - fprintf(stderr, "Operation failed: %s\n", err2str(res, command)); + fprintf(stderr, "Operation failed: %s\n", err2str(-errno, command)); exit(OTHER_PROBLEM); } -- cgit v1.2.3 From 64823c027ee22b51f8d82e238679cb299222931b Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Sun, 6 May 2007 18:00:06 +0000 Subject: - update changelog - use positive logic in error handling --- ChangeLog | 12 ++++++++++++ src/conntrack.c | 26 +++++++++++++------------- 2 files changed, 25 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 2ef0535..59b297b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ version 0.9.3 (yet unreleased) ------------------------------ + += conntrackd = o fix commit of confirmed expectations (reported by Nishit Shah) o fix double increment of counters in cache_update_force() (Niko Tyni) o nl_dump_handler must return NFCT_CB_CONTINUE (Niko Tyni) @@ -28,6 +30,16 @@ o kill cache feature abuse: introduce nicer cache hooks for sync algorithms o fix oversized buffer allocated in the stack in the cache functions o add support to dump internal/external cache in XML format '-x' += conntrack = +o port conntrack to the new libnetfilter_conntrack API +o introduce '--xml' option for '-L', '-G' and '-E' +o deprecated '--id' +o replace '-a' by '--src-nat' and '--dst-nat' +o use positive logic in error handling +o remove sctp support until is fully supported in the kernel side +o update conntrack manpage +o update test.sh file in examples/cli/ + version 0.9.2 (2006/01/17) -------------------------- o remove spamming packet lost messages diff --git a/src/conntrack.c b/src/conntrack.c index f3aa06f..e9e8167 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -319,18 +319,18 @@ err2str(int err, enum action command) int err; const char *message; } table [] = - { { CT_LIST, -ENOTSUPP, "function not implemented" }, - { 0xFFFF, -EINVAL, "invalid parameters" }, - { CT_CREATE, -EEXIST, "Such conntrack exists, try -U to update" }, - { CT_CREATE|CT_GET|CT_DELETE, -ENOENT, + { { CT_LIST, ENOTSUPP, "function not implemented" }, + { 0xFFFF, EINVAL, "invalid parameters" }, + { CT_CREATE, EEXIST, "Such conntrack exists, try -U to update" }, + { CT_CREATE|CT_GET|CT_DELETE, ENOENT, "such conntrack doesn't exist" }, - { CT_CREATE|CT_GET, -ENOMEM, "not enough memory" }, - { CT_GET, -EAFNOSUPPORT, "protocol not supported" }, - { CT_CREATE, -ETIME, "conntrack has expired" }, - { EXP_CREATE, -ENOENT, "master conntrack not found" }, - { EXP_CREATE, -EINVAL, "invalid parameters" }, - { ~0UL, -EPERM, "sorry, you must be root or get " - "CAP_NET_ADMIN capability to do this"} + { CT_CREATE|CT_GET, ENOMEM, "not enough memory" }, + { CT_GET, EAFNOSUPPORT, "protocol not supported" }, + { CT_CREATE, ETIME, "conntrack has expired" }, + { EXP_CREATE, ENOENT, "master conntrack not found" }, + { EXP_CREATE, EINVAL, "invalid parameters" }, + { ~0UL, EPERM, "sorry, you must be root or get " + "CAP_NET_ADMIN capability to do this"} }; for (i = 0; i < sizeof(table)/sizeof(struct table_struct); i++) { @@ -338,7 +338,7 @@ err2str(int err, enum action command) return table[i].message; } - return strerror(-err); + return strerror(err); } #define PARSE_STATUS 0 @@ -1238,7 +1238,7 @@ int main(int argc, char *argv[]) } if (res < 0) { - fprintf(stderr, "Operation failed: %s\n", err2str(-errno, command)); + fprintf(stderr, "Operation failed: %s\n", err2str(errno, command)); exit(OTHER_PROBLEM); } -- cgit v1.2.3 From f5123f2db878808a7431b8cc25c8eaa7813ed77f Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Mon, 7 May 2007 23:36:45 +0000 Subject: o introduce '--output xml,extended,timestamp' option for '-L', '-G' and '-E' o several fixes for the output of usage messages --- ChangeLog | 3 ++- conntrack.8 | 28 +++++++++++++++++------ extensions/libct_proto_icmp.c | 21 +++-------------- extensions/libct_proto_tcp.c | 18 +++++++-------- extensions/libct_proto_udp.c | 16 ++++++------- include/conntrack.h | 17 +++++++++++--- src/conntrack.c | 53 +++++++++++++++++++++++++++++++------------ 7 files changed, 96 insertions(+), 60 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 59b297b..fb2d21b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -32,13 +32,14 @@ o add support to dump internal/external cache in XML format '-x' = conntrack = o port conntrack to the new libnetfilter_conntrack API -o introduce '--xml' option for '-L', '-G' and '-E' +o introduce '--output xml,extended,timestamp' option for '-L', '-G' and '-E' o deprecated '--id' o replace '-a' by '--src-nat' and '--dst-nat' o use positive logic in error handling o remove sctp support until is fully supported in the kernel side o update conntrack manpage o update test.sh file in examples/cli/ +o several fixes for the output of usage messages version 0.9.2 (2006/01/17) -------------------------- diff --git a/conntrack.8 b/conntrack.8 index 6c5d9d6..3a35613 100644 --- a/conntrack.8 +++ b/conntrack.8 @@ -4,7 +4,7 @@ .\" Maintained by Pablo Neira Ayuso l4dst.icmp.type = - invmap[orig->l4dst.icmp.type] - 1; - */ *flags |= ICMP_TYPE; break; case '2': diff --git a/extensions/libct_proto_tcp.c b/extensions/libct_proto_tcp.c index 736bcff..5a5c5c4 100644 --- a/extensions/libct_proto_tcp.c +++ b/extensions/libct_proto_tcp.c @@ -45,15 +45,15 @@ static const char *states[] = { static void help() { - fprintf(stdout, "--orig-port-src original source port\n"); - fprintf(stdout, "--orig-port-dst original destination port\n"); - fprintf(stdout, "--reply-port-src reply source port\n"); - fprintf(stdout, "--reply-port-dst reply destination port\n"); - fprintf(stdout, "--mask-port-src mask source port\n"); - fprintf(stdout, "--mask-port-dst mask destination port\n"); - fprintf(stdout, "--tuple-port-src expectation tuple src port\n"); - fprintf(stdout, "--tuple-port-src expectation tuple dst port\n"); - fprintf(stdout, "--state TCP state, fe. ESTABLISHED\n"); + fprintf(stdout, " --orig-port-src\t\toriginal source port\n"); + fprintf(stdout, " --orig-port-dst\t\toriginal destination port\n"); + fprintf(stdout, " --reply-port-src\t\treply source port\n"); + fprintf(stdout, " --reply-port-dst\t\treply destination port\n"); + fprintf(stdout, " --mask-port-src\t\tmask source port\n"); + fprintf(stdout, " --mask-port-dst\t\tmask destination port\n"); + fprintf(stdout, " --tuple-port-src\t\texpectation tuple src port\n"); + fprintf(stdout, " --tuple-port-src\t\texpectation tuple dst port\n"); + fprintf(stdout, " --state\t\t\tTCP state, fe. ESTABLISHED\n"); } static int parse_options(char c, char *argv[], diff --git a/extensions/libct_proto_udp.c b/extensions/libct_proto_udp.c index 1bc70d4..6e8d13c 100644 --- a/extensions/libct_proto_udp.c +++ b/extensions/libct_proto_udp.c @@ -31,14 +31,14 @@ static struct option opts[] = { static void help() { - fprintf(stdout, "--orig-port-src original source port\n"); - fprintf(stdout, "--orig-port-dst original destination port\n"); - fprintf(stdout, "--reply-port-src reply source port\n"); - fprintf(stdout, "--reply-port-dst reply destination port\n"); - fprintf(stdout, "--mask-port-src mask source port\n"); - fprintf(stdout, "--mask-port-dst mask destination port\n"); - fprintf(stdout, "--tuple-port-src expectation tuple src port\n"); - fprintf(stdout, "--tuple-port-src expectation tuple dst port\n"); + fprintf(stdout, " --orig-port-src\t\toriginal source port\n"); + fprintf(stdout, " --orig-port-dst\t\toriginal destination port\n"); + fprintf(stdout, " --reply-port-src\t\treply source port\n"); + fprintf(stdout, " --reply-port-dst\t\treply destination port\n"); + fprintf(stdout, " --mask-port-src\t\tmask source port\n"); + fprintf(stdout, " --mask-port-dst\t\tmask destination port\n"); + fprintf(stdout, " --tuple-port-src\t\texpectation tuple src port\n"); + fprintf(stdout, " --tuple-port-src\t\texpectation tuple dst port\n"); } static int parse_options(char c, char *argv[], diff --git a/include/conntrack.h b/include/conntrack.h index 50aec19..31f4f4f 100644 --- a/include/conntrack.h +++ b/include/conntrack.h @@ -124,13 +124,24 @@ enum options { CT_OPT_DST_NAT_BIT = 18, CT_OPT_DST_NAT = (1 << CT_OPT_DST_NAT_BIT), - CT_OPT_XML_BIT = 19, - CT_OPT_XML = (1 << CT_OPT_XML_BIT), + CT_OPT_OUTPUT_BIT = 19, + CT_OPT_OUTPUT = (1 << CT_OPT_OUTPUT_BIT), - CT_OPT_MAX = CT_OPT_XML_BIT + CT_OPT_MAX = CT_OPT_OUTPUT_BIT }; #define NUMBER_OF_OPT CT_OPT_MAX+1 +enum { + _O_XML_BIT = 0, + _O_XML = (1 << _O_XML_BIT), + + _O_EXT_BIT = 1, + _O_EXT = (1 << _O_EXT_BIT), + + _O_TMS_BIT = 2, + _O_TMS = (1 << _O_TMS_BIT), +}; + struct ctproto_handler { struct list_head head; diff --git a/src/conntrack.c b/src/conntrack.c index e9e8167..2339a2c 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -96,7 +96,7 @@ static struct option original_opts[] = { {"family", 1, 0, 'f'}, {"src-nat", 1, 0, 'n'}, {"dst-nat", 1, 0, 'g'}, - {"xml", 0, 0, 'x'}, + {"output", 0, 0, 'o'}, {0, 0, 0, 0} }; @@ -118,7 +118,7 @@ static unsigned int global_option_offset = 0; static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = /* Well, it's better than "Re: Linux vs FreeBSD" */ { - /* s d r q p t u z e x y k l a m i f n g x */ + /* s d r q p t u z e [ ] { } a m i f n g o */ /*CT_LIST*/ {2,2,2,2,2,0,0,2,0,0,0,0,0,0,2,2,2,0,0,2}, /*CT_CREATE*/ {2,2,2,2,1,1,1,0,0,0,0,0,0,2,2,0,0,2,2,0}, /*CT_UPDATE*/ {2,2,2,2,1,2,2,0,0,0,0,0,0,0,2,2,0,0,0,0}, @@ -343,7 +343,8 @@ err2str(int err, enum action command) #define PARSE_STATUS 0 #define PARSE_EVENT 1 -#define PARSE_MAX 2 +#define PARSE_OUTPUT 2 +#define PARSE_MAX 3 static struct parse_parameter { char *parameter[6]; @@ -355,6 +356,9 @@ static struct parse_parameter { { {"ALL", "NEW", "UPDATES", "DESTROY"}, 4, {~0U, NF_NETLINK_CONNTRACK_NEW, NF_NETLINK_CONNTRACK_UPDATE, NF_NETLINK_CONNTRACK_DESTROY} }, + { {"xml", "extended", "timestamp" }, 3, + { _O_XML, _O_EXT, _O_TMS }, + }, }; static int @@ -542,12 +546,12 @@ static const char usage_tables[] = static const char usage_conntrack_parameters[] = "Conntrack parameters and options:\n" - " -n, --src-nat ip\tsource NAT ip\n" - " -g, --dst-nat ip\tdestination NAT ip\n" + " -n, --src-nat ip\t\t\tsource NAT ip\n" + " -g, --dst-nat ip\t\t\tdestination NAT ip\n" " -m, --mark mark\t\t\tSet mark\n" " -e, --event-mask eventmask\t\tEvent mask, eg. NEW,DESTROY\n" " -z, --zero \t\t\t\tZero counters while listing\n" - " -x, --xml \t\t\t\tDisplay output in XML format\n"; + " -o, --output type[,...]\t\tOutput format, eg. xml\n"; ; static const char usage_expectation_parameters[] = @@ -571,7 +575,8 @@ static const char usage_parameters[] = void usage(char *prog) { - fprintf(stdout, "Tool to manipulate conntrack and expectations. Version %s\n", VERSION); + fprintf(stdout, "Command line interface for the connection " + "tracking system. Version %s\n", VERSION); fprintf(stdout, "Usage: %s [commands] [options]\n", prog); fprintf(stdout, "\n%s", usage_commands); @@ -581,7 +586,7 @@ void usage(char *prog) { fprintf(stdout, "\n%s", usage_parameters); } -unsigned int output_flags = NFCT_O_DEFAULT; +static unsigned int output_mask; static int event_cb(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, @@ -589,12 +594,25 @@ static int event_cb(enum nf_conntrack_msg_type type, { char buf[1024]; struct nf_conntrack *obj = data; + unsigned int output_type = NFCT_O_DEFAULT; + unsigned int output_flags = 0; if (options & CT_COMPARISON && !nfct_compare(obj, ct)) return NFCT_CB_CONTINUE; - nfct_snprintf(buf, 1024, ct, type, output_flags, 0); + if (output_mask & _O_XML) + output_type = NFCT_O_XML; + if (output_mask & _O_EXT) + output_flags = NFCT_OF_SHOW_LAYER3; + if ((output_mask & _O_TMS) && !(output_mask & _O_XML)) { + struct timeval tv; + gettimeofday(&tv, NULL); + printf("[%-8ld.%-6ld]\t", tv.tv_sec, tv.tv_usec); + } + + nfct_snprintf(buf, 1024, ct, type, output_type, output_flags); printf("%s\n", buf); + fflush(stdout); return NFCT_CB_CONTINUE; } @@ -605,11 +623,18 @@ static int dump_cb(enum nf_conntrack_msg_type type, { char buf[1024]; struct nf_conntrack *obj = data; + unsigned int output_type = NFCT_O_DEFAULT; + unsigned int output_flags = 0; if (options & CT_COMPARISON && !nfct_compare(obj, ct)) return NFCT_CB_CONTINUE; - nfct_snprintf(buf, 1024, ct, NFCT_T_UNKNOWN, output_flags, 0); + if (output_mask & _O_XML) + output_type = NFCT_O_XML; + if (output_mask & _O_EXT) + output_flags = NFCT_OF_SHOW_LAYER3; + + nfct_snprintf(buf, 1024, ct, NFCT_T_UNKNOWN, output_type, output_flags); printf("%s\n", buf); return NFCT_CB_CONTINUE; @@ -652,7 +677,7 @@ int main(int argc, char *argv[]) memset(__exp, 0, sizeof(__exp)); while ((c = getopt_long(argc, argv, - "L::I::U::D::G::E::F::hVs:d:r:q:p:t:u:e:a:z[:]:{:}:m:i::f:x", + "L::I::U::D::G::E::F::hVs:d:r:q:p:t:u:e:a:z[:]:{:}:m:i::f:o:", opts, NULL)) != -1) { switch(c) { case 'L': @@ -931,9 +956,9 @@ int main(int argc, char *argv[]) exit_error(PARAMETER_PROBLEM, "Unknown " "protocol family\n"); break; - case 'x': - options |= CT_OPT_XML; - output_flags = NFCT_O_XML; + case 'o': + options |= CT_OPT_OUTPUT; + parse_parameter(optarg, &output_mask, PARSE_OUTPUT); break; default: if (h && h->parse_opts -- cgit v1.2.3 From 2932c6b8e6952ae84b221b854b43810c61e5c8fa Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Fri, 18 May 2007 19:33:40 +0000 Subject: - remove dead code sync-mode.c - flush nack queue in the conntrackd -f path - do not increase add_fail counter for EEXIST errors - cleanup sync-nack code - improve mcast_recv_netmsg: sanity check before checksumming! --- include/sync.h | 4 ++- src/cache.c | 9 ++++--- src/cache_iterators.c | 6 ++++- src/network.c | 47 ++++++++++++++++++++++++---------- src/sync-mode.c | 51 ++++++++++-------------------------- src/sync-nack.c | 71 ++++++++++++++++++++++++--------------------------- src/sync-notrack.c | 4 ++- 7 files changed, 96 insertions(+), 96 deletions(-) (limited to 'src') diff --git a/include/sync.h b/include/sync.h index 7756c87..d8f1bca 100644 --- a/include/sync.h +++ b/include/sync.h @@ -14,7 +14,9 @@ struct sync_mode { void (*kill)(void); int (*local)(int fd, int type, void *data); int (*pre_recv)(const struct nlnetwork *net); - void (*post_send)(const struct nlnetwork *net, struct us_conntrack *u); + void (*post_send)(int type, + const struct nlnetwork *net, + struct us_conntrack *u); }; extern struct sync_mode notrack; diff --git a/src/cache.c b/src/cache.c index 6f7442b..32caee5 100644 --- a/src/cache.c +++ b/src/cache.c @@ -228,7 +228,7 @@ static struct us_conntrack *__add(struct cache *c, struct nf_conntrack *ct) data += c->features[i]->size; } - if (c->extra) + if (c->extra && c->extra->add) c->extra->add(u, ((void *) u) + c->extra_offset); return u; @@ -247,7 +247,8 @@ struct us_conntrack *__cache_add(struct cache *c, struct nf_conntrack *ct) c->add_ok++; return u; } - c->add_fail++; + if (errno != EEXIST) + c->add_fail++; return NULL; } @@ -281,7 +282,7 @@ static struct us_conntrack *__update(struct cache *c, struct nf_conntrack *ct) data += c->features[i]->size; } - if (c->extra) + if (c->extra && c->extra->update) c->extra->update(u, ((void *) u) + c->extra_offset); if (nfct_attr_is_set(ct, ATTR_STATUS)) @@ -380,7 +381,7 @@ static int __del(struct cache *c, struct nf_conntrack *ct) data += c->features[i]->size; } - if (c->extra) + if (c->extra && c->extra->destroy) c->extra->destroy(u, ((void *) u) + c->extra_offset); hashtable_del(c->h, u); diff --git a/src/cache_iterators.c b/src/cache_iterators.c index 5d5d22b..e1f3798 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -182,6 +182,10 @@ static int do_flush(void *data1, void *data2) c->features[i]->destroy(u, data); data += c->features[i]->size; } + + if (c->extra && c->extra->destroy) + c->extra->destroy(u, ((void *) u) + c->extra_offset); + free(u->ct); return 0; @@ -215,7 +219,7 @@ static int do_bulk(void *data1, void *data2) debug_ct(u->ct, "failed to build"); mcast_send_netmsg(STATE_SYNC(mcast_client), net); - STATE_SYNC(mcast_sync)->post_send(net, u); + STATE_SYNC(mcast_sync)->post_send(NFCT_T_UPDATE, net, u); /* keep iterating even if we have found errors */ return 0; diff --git a/src/network.c b/src/network.c index b9be318..51e89c7 100644 --- a/src/network.c +++ b/src/network.c @@ -70,7 +70,7 @@ int mcast_resend_netmsg(struct mcast_sock *m, void *data) { struct nlnetwork *net = data; struct nlmsghdr *nlh = data + sizeof(struct nlnetwork); - unsigned int len = htonl(nlh->nlmsg_len) + sizeof(struct nlnetwork); + unsigned int len; net->flags = ntohs(net->flags); @@ -80,10 +80,10 @@ int mcast_resend_netmsg(struct mcast_sock *m, void *data) net->flags |= NET_HELLO; } - if (net->flags & NET_NACK || net->flags & NET_ACK) { - struct nlnetwork_ack *nack = (struct nlnetwork_ack *) net; + if (net->flags & NET_NACK || net->flags & NET_ACK) len = sizeof(struct nlnetwork_ack); - } + else + len = sizeof(struct nlnetwork) + ntohl(nlh->nlmsg_len); net->flags = htons(net->flags); net->seq = htonl(cur_seq++); @@ -147,32 +147,44 @@ int mcast_recv_netmsg(struct mcast_sock *m, void *data, int len) if (ret <= 0) return ret; + /* message too small: no room for the header */ if (ret < sizeof(struct nlnetwork)) return -1; - if (!valid_checksum(data, ret)) - return -1; - - net->flags = ntohs(net->flags); - net->seq = ntohl(net->seq); - - if (net->flags & NET_HELLO) - STATE_SYNC(last_seq_recv) = net->seq-1; + if (ntohs(net->flags) & NET_HELLO) + STATE_SYNC(last_seq_recv) = ntohl(net->seq) - 1; - if (net->flags & NET_NACK || net->flags & NET_ACK) { + if (ntohs(net->flags) & NET_NACK || ntohs(net->flags) & NET_ACK) { struct nlnetwork_ack *nack = (struct nlnetwork_ack *) net; + /* message too small: no room for the header */ if (ret < sizeof(struct nlnetwork_ack)) return -1; + if (!valid_checksum(data, ret)) + return -1; + + /* host byte order conversion */ + net->flags = ntohs(net->flags); + net->seq = ntohl(net->seq); + + /* acknowledgement conversion */ nack->from = ntohl(nack->from); nack->to = ntohl(nack->to); return ret; } - if (net->flags & NET_RESYNC) + if (ntohs(net->flags) & NET_RESYNC) { + if (!valid_checksum(data, ret)) + return -1; + + /* host byte order conversion */ + net->flags = ntohs(net->flags); + net->seq = ntohl(net->seq); + return ret; + } /* information received is too small */ if (ret < NLMSG_SPACE(sizeof(struct nfgenmsg))) @@ -197,6 +209,13 @@ int mcast_recv_netmsg(struct mcast_sock *m, void *data, int len) if (nfhdr->version != NFNETLINK_V0) return -1; + if (!valid_checksum(data, ret)) + return -1; + + /* host byte order conversion */ + net->flags = ntohs(net->flags); + net->seq = ntohl(net->seq); + if (nlh_network2host(nlh) == -1) return -1; diff --git a/src/sync-mode.c b/src/sync-mode.c index b32bef7..0a195d7 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -282,18 +282,15 @@ static void mcast_send_sync(struct nlmsghdr *nlh, { char buf[4096]; struct nlnetwork *net = (struct nlnetwork *) buf; - int mangled = 0; memset(buf, 0, sizeof(buf)); if (!state_helper_verdict(type, ct)) return; - if (!mangled) - memcpy(buf + sizeof(struct nlnetwork), nlh, nlh->nlmsg_len); - + memcpy(buf + sizeof(struct nlnetwork), nlh, nlh->nlmsg_len); mcast_send_netmsg(STATE_SYNC(mcast_client), net); - STATE_SYNC(mcast_sync)->post_send(net, u); + STATE_SYNC(mcast_sync)->post_send(type, net, u); } static void overrun_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) @@ -333,7 +330,8 @@ retry: } else { if (errno == EEXIST) { char buf[4096]; - struct nlmsghdr *nlh = (struct nlmsghdr *) buf; + unsigned int size = sizeof(struct nlnetwork); + struct nlmsghdr *nlh = (struct nlmsghdr *) (buf + size); int ret = build_network_msg(NFCT_Q_DESTROY, STATE(subsys_event), @@ -344,9 +342,10 @@ retry: return; cache_del(STATE_SYNC(internal), ct); - mcast_send_sync(nlh, NULL, ct, NFCT_T_NEW); + mcast_send_sync(nlh, NULL, ct, NFCT_T_DESTROY); goto retry; } + dlog(STATE(log), "can't add to internal cache: " "%s\n", strerror(errno)); debug_ct(ct, "can't add"); @@ -360,19 +359,8 @@ static void event_update_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) nfct_attr_unset(ct, ATTR_TIMEOUT); if ((u = cache_update(STATE_SYNC(internal), ct)) == NULL) { - /* - * Perhaps we are losing events. If we are working - * in relax mode then add a new entry to the cache. - * - * FIXME: relax transitions not implemented yet - */ - if ((CONFIG(flags) & RELAX_TRANSITIONS) - && (u = cache_add(STATE_SYNC(internal), ct))) { - debug_ct(u->ct, "forcing internal update"); - } else { - debug_ct(ct, "can't update"); - return; - } + debug_ct(ct, "can't update"); + return; } debug_ct(u->ct, "internal update"); mcast_send_sync(nlh, u, ct, NFCT_T_UPDATE); @@ -382,24 +370,11 @@ static int event_destroy_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) { nfct_attr_unset(ct, ATTR_TIMEOUT); - if (CONFIG(flags) & DELAY_DESTROY_MSG) { - - nfct_set_attr_u32(ct, ATTR_STATUS, IPS_DYING); - - if (cache_update(STATE_SYNC(internal), ct)) { - debug_ct(ct, "delay internal destroy"); - return 1; - } else { - debug_ct(ct, "can't delay destroy!"); - return 0; - } - } else { - if (cache_del(STATE_SYNC(internal), ct)) { - mcast_send_sync(nlh, NULL, ct, NFCT_T_DESTROY); - debug_ct(ct, "internal destroy"); - } else - debug_ct(ct, "can't destroy"); - } + if (cache_del(STATE_SYNC(internal), ct)) { + mcast_send_sync(nlh, NULL, ct, NFCT_T_DESTROY); + debug_ct(ct, "internal destroy"); + } else + debug_ct(ct, "can't destroy"); } struct ct_mode sync_mode = { diff --git a/src/sync-nack.c b/src/sync-nack.c index 288dba4..73f6dc2 100644 --- a/src/sync-nack.c +++ b/src/sync-nack.c @@ -43,37 +43,24 @@ struct cache_nack { static void cache_nack_add(struct us_conntrack *u, void *data) { struct cache_nack *cn = data; - INIT_LIST_HEAD(&cn->head); - list_add(&cn->head, &queue); } -static void cache_nack_update(struct us_conntrack *u, void *data) +static void cache_nack_del(struct us_conntrack *u, void *data) { struct cache_nack *cn = data; - if (cn->head.next != LIST_POISON1 && - cn->head.prev != LIST_POISON2) - list_del(&cn->head); + if (cn->head.next == &cn->head && + cn->head.prev == &cn->head) + return; - INIT_LIST_HEAD(&cn->head); - list_add(&cn->head, &queue); -} - -static void cache_nack_destroy(struct us_conntrack *u, void *data) -{ - struct cache_nack *cn = data; - - if (cn->head.next != LIST_POISON1 && - cn->head.prev != LIST_POISON2) - list_del(&cn->head); + list_del(&cn->head); } static struct cache_extra cache_nack_extra = { .size = sizeof(struct cache_nack), .add = cache_nack_add, - .update = cache_nack_update, - .destroy = cache_nack_destroy + .destroy = cache_nack_del }; static int nack_init() @@ -200,7 +187,9 @@ static void queue_resend(struct cache *c, unsigned int from, unsigned int to) } mcast_send_netmsg(STATE_SYNC(mcast_client), buf); - STATE_SYNC(mcast_sync)->post_send(net, u); + STATE_SYNC(mcast_sync)->post_send(NFCT_T_UPDATE, + net, + u); dp("(newseq=%u)\n", *seq); } } @@ -224,6 +213,7 @@ static void queue_empty(struct cache *c, unsigned int from, unsigned int to) debug_ct(u->ct, "ack received: empty queue"); dp("queue: deleting from queue (seq=%u)\n", cn->seq); list_del(&cn->head); + INIT_LIST_HEAD(&cn->head); } } unlock(); @@ -272,28 +262,35 @@ static int nack_pre_recv(const struct nlnetwork *net) return 0; } -static void nack_post_send(const struct nlnetwork *net, struct us_conntrack *u) +static void nack_post_send(int type, + const struct nlnetwork *net, + struct us_conntrack *u) { - unsigned int size = sizeof(struct nlnetwork); - struct nlmsghdr *nlh = (struct nlmsghdr *) ((void *) net + size); - - if (NFNL_MSG_TYPE(ntohs(nlh->nlmsg_type)) == IPCTNL_MSG_CT_DELETE) { - buffer_add(STATE_SYNC(buffer), net, - ntohl(nlh->nlmsg_len) + size); - } else if (u != NULL) { - unsigned int *seq; - struct list_head *n; - struct cache_nack *cn; - - cn = (struct cache_nack *) + unsigned int size = sizeof(struct nlnetwork); + struct nlmsghdr *nlh = (struct nlmsghdr *) ((void *) net + size); + struct cache_nack *cn; + + size += ntohl(nlh->nlmsg_len); + + switch(type) { + case NFCT_T_NEW: + case NFCT_T_UPDATE: + cn = (struct cache_nack *) cache_get_extra(STATE_SYNC(internal), u); - cn->seq = ntohl(net->seq); - if (cn->head.next != LIST_POISON1 && - cn->head.prev != LIST_POISON2) - list_del(&cn->head); + if (cn->head.next == &cn->head && + cn->head.prev == &cn->head) + goto insert; + + list_del(&cn->head); INIT_LIST_HEAD(&cn->head); +insert: + cn->seq = ntohl(net->seq); list_add(&cn->head, &queue); + break; + case NFCT_T_DESTROY: + buffer_add(STATE_SYNC(buffer), net, size); + break; } } diff --git a/src/sync-notrack.c b/src/sync-notrack.c index 2b5ae38..cc56436 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -114,7 +114,9 @@ static int notrack_pre_recv(const struct nlnetwork *net) return 0; } -static void notrack_post_send(const struct nlnetwork *n, struct us_conntrack *u) +static void notrack_post_send(int type, + const struct nlnetwork *n, + struct us_conntrack *u) { } -- cgit v1.2.3 From 9f1b4b2d028129966f7e6f23cec6ac0712c2b1b6 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Sun, 20 May 2007 21:13:06 +0000 Subject: - introduce cache_iterate - empty debug_ct function if DEBUG_CT is not set - revisit overrun handler: this is a hard battle, just try to do our best here, call Patrick :) - explicit warning message when netlink_buffer_max_growth is reached - fix silly bug in stats-mode when dumping in XML format - fix UDP handler for conntrack --- extensions/libct_proto_udp.c | 54 +++++++++++++++++----------- include/cache.h | 1 + include/conntrackd.h | 4 +-- include/debug.h | 4 +++ src/cache.c | 9 +++++ src/cache_iterators.c | 6 ++-- src/netlink.c | 73 ++++++------------------------------- src/run.c | 11 +----- src/stats-mode.c | 48 +++++++++++++++++++++++-- src/sync-mode.c | 85 ++++++++++++++++++++++++++++++++++++++++++-- 10 files changed, 190 insertions(+), 105 deletions(-) (limited to 'src') diff --git a/extensions/libct_proto_udp.c b/extensions/libct_proto_udp.c index 6e8d13c..bae9bf8 100644 --- a/extensions/libct_proto_udp.c +++ b/extensions/libct_proto_udp.c @@ -43,12 +43,10 @@ static void help() static int parse_options(char c, char *argv[], struct nf_conntrack *ct, - struct nfct_tuple *exptuple, - struct nfct_tuple *mask, + struct nf_conntrack *exptuple, + struct nf_conntrack *mask, unsigned int *flags) { - int i; - switch(c) { case '1': if (!optarg) @@ -91,28 +89,44 @@ static int parse_options(char c, char *argv[], *flags |= UDP_REPL_DPORT; break; case '5': - if (optarg) { - mask->l4src.udp.port = htons(atoi(optarg)); - *flags |= UDP_MASK_SPORT; - } + if (!optarg) + break; + + nfct_set_attr_u16(mask, + ATTR_ORIG_PORT_SRC, + htons(atoi(optarg))); + + *flags |= UDP_MASK_SPORT; break; case '6': - if (optarg) { - mask->l4dst.udp.port = htons(atoi(optarg)); - *flags |= UDP_MASK_DPORT; - } + if (!optarg) + break; + + nfct_set_attr_u16(mask, + ATTR_ORIG_PORT_DST, + htons(atoi(optarg))); + + *flags |= UDP_MASK_DPORT; break; case '7': - if (optarg) { - exptuple->l4src.udp.port = htons(atoi(optarg)); - *flags |= UDP_EXPTUPLE_SPORT; - } + if (!optarg) + break; + + nfct_set_attr_u16(exptuple, + ATTR_ORIG_PORT_SRC, + htons(atoi(optarg))); + + *flags |= UDP_EXPTUPLE_SPORT; break; case '8': - if (optarg) { - exptuple->l4dst.udp.port = htons(atoi(optarg)); - *flags |= UDP_EXPTUPLE_DPORT; - } + if (!optarg) + break; + + nfct_set_attr_u16(exptuple, + ATTR_ORIG_PORT_DST, + htons(atoi(optarg))); + + *flags |= UDP_EXPTUPLE_DPORT; break; } return 1; diff --git a/include/cache.h b/include/cache.h index 7d9559a..e755dbe 100644 --- a/include/cache.h +++ b/include/cache.h @@ -82,6 +82,7 @@ int cache_test(struct cache *c, struct nf_conntrack *ct); void cache_stats(struct cache *c, int fd); struct us_conntrack *cache_get_conntrack(struct cache *, void *); void *cache_get_extra(struct cache *, void *); +void cache_iterate(struct cache *c, void *data, int (*iterate)(void *data1, void *data2)); /* iterators */ void cache_dump(struct cache *c, int fd, int type); diff --git a/include/conntrackd.h b/include/conntrackd.h index a5f7a3a..76b9747 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -102,11 +102,9 @@ struct ct_general_state { struct ignore_pool *ignore_pool; struct nfnl_handle *event; /* event handler */ - struct nfnl_handle *sync; /* sync handler */ struct nfnl_handle *dump; /* dump handler */ struct nfnl_subsys_handle *subsys_event; /* events */ - struct nfnl_subsys_handle *subsys_sync; /* resync */ struct nfnl_subsys_handle *subsys_dump; /* dump */ /* statistics */ @@ -159,7 +157,7 @@ struct ct_mode { int (*local)(int fd, int type, void *data); void (*kill)(void); void (*dump)(struct nf_conntrack *ct, struct nlmsghdr *nlh); - void (*overrun)(struct nf_conntrack *ct, struct nlmsghdr *nlh); + void (*overrun)(void); void (*event_new)(struct nf_conntrack *ct, struct nlmsghdr *nlh); void (*event_upd)(struct nf_conntrack *ct, struct nlmsghdr *nlh); int (*event_dst)(struct nf_conntrack *ct, struct nlmsghdr *nlh); diff --git a/include/debug.h b/include/debug.h index 67f2c71..4d1f44f 100644 --- a/include/debug.h +++ b/include/debug.h @@ -11,8 +11,11 @@ #include #include +#undef DEBUG_CT + static inline void debug_ct(struct nf_conntrack *ct, char *msg) { +#ifdef DEBUG_CT struct in_addr addr, addr2, addr3, addr4; debug("----%s (%p) ----\n", msg, ct); @@ -48,6 +51,7 @@ static inline void debug_ct(struct nf_conntrack *ct, char *msg) inet_ntoa(addr4), ntohs(nfct_get_attr_u16(ct, ATTR_REPL_PORT_DST))); debug("-------------------------\n"); +#endif } #endif diff --git a/src/cache.c b/src/cache.c index 32caee5..1b130c8 100644 --- a/src/cache.c +++ b/src/cache.c @@ -445,3 +445,12 @@ void cache_stats(struct cache *c, int fd) unlock(); send(fd, buf, size, 0); } + +void cache_iterate(struct cache *c, + void *data, + int (*iterate)(void *data1, void *data2)) +{ + lock(); + hashtable_iterate(c->h, data, iterate); + unlock(); +} diff --git a/src/cache_iterators.c b/src/cache_iterators.c index e1f3798..1c03fef 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -111,7 +111,7 @@ static int do_commit(void *data1, void *data2) */ nfct_set_attr_u32(ct, ATTR_TIMEOUT, CONFIG(commit_timeout)); - ret = nfct_build_query(STATE(subsys_sync), + ret = nfct_build_query(STATE(subsys_dump), NFCT_Q_CREATE, ct, nlh, @@ -125,7 +125,7 @@ static int do_commit(void *data1, void *data2) return 0; } - ret = nfnl_query(STATE(sync), nlh); + ret = nfnl_query(STATE(dump), nlh); if (ret == -1) { switch(errno) { case EEXIST: @@ -211,7 +211,7 @@ static int do_bulk(void *data1, void *data2) struct nlnetwork *net = (struct nlnetwork *) buf; ret = build_network_msg(NFCT_Q_UPDATE, - STATE(subsys_sync), + STATE(subsys_dump), u->ct, buf, sizeof(buf)); diff --git a/src/netlink.c b/src/netlink.c index 0bde632..94200b9 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -207,66 +207,6 @@ int nl_init_dump_handler(void) return 0; } -static int nl_overrun_handler(struct nlmsghdr *nlh, - struct nfattr *nfa[], - void *data) -{ - char buf[1024]; - struct nf_conntrack *ct = (struct nf_conntrack *) buf; - int type; - - memset(buf, 0, sizeof(buf)); - - if ((type = nfct_parse_conntrack(NFCT_T_ALL, nlh, ct)) == NFCT_T_ERROR) - return NFCT_CB_CONTINUE; - - /* - * Ignore this conntrack: it talks about a - * connection that is not interesting for us. - */ - if (ignore_conntrack(ct)) - return NFCT_CB_CONTINUE; - - switch(type) { - case NFCT_T_UPDATE: - if (STATE(mode)->overrun) - STATE(mode)->overrun(ct, nlh); - break; - default: - dlog(STATE(log), "received unknown msg from ctnetlink"); - break; - } - return NFCT_CB_CONTINUE; -} - -int nl_init_overrun_handler(void) -{ - struct nfnl_callback cb_sync = { - .call = nl_overrun_handler, - .attr_count = CTA_MAX - }; - - /* open sync netlink socket */ - STATE(sync) = nfnl_open(); - if (!STATE(sync)) - return -1; - - /* open synchronizer subsystem */ - STATE(subsys_sync) = nfnl_subsys_open(STATE(sync), - NFNL_SUBSYS_CTNETLINK, - IPCTNL_MSG_MAX, - 0); - if (STATE(subsys_sync) == NULL) - return -1; - - /* register callback for dumped entries */ - nfnl_callback_register(STATE(subsys_sync), - IPCTNL_MSG_CT_NEW, - &cb_sync); - - return 0; -} - static int warned = 0; void nl_resize_socket_buffer(struct nfnl_handle *h) @@ -278,7 +218,14 @@ void nl_resize_socket_buffer(struct nfnl_handle *h) return; if (s > CONFIG(netlink_buffer_size_max_grown)) { - dlog(STATE(log), "maximum netlink socket buffer size reached"); + dlog(STATE(log), "WARNING: maximum netlink socket buffer " + "size has been reached. We are likely to " + "be losing events, this may lead to " + "unsynchronized replicas. Please, consider " + "increasing netlink socket buffer size via " + "SocketBufferSize and " + "SocketBufferSizeMaxGrown clauses in " + "conntrackd.conf"); s = CONFIG(netlink_buffer_size_max_grown); warned = 1; } @@ -313,13 +260,13 @@ int nl_flush_master_conntrack_table(void) struct nfnlhdr req; memset(&req, 0, sizeof(req)); - nfct_build_query(STATE(subsys_sync), + nfct_build_query(STATE(subsys_dump), NFCT_Q_FLUSH, &CONFIG(family), &req, sizeof(req)); - if (nfnl_query(STATE(sync), &req.nlh) == -1) + if (nfnl_query(STATE(dump), &req.nlh) == -1) return -1; return 0; diff --git a/src/run.c b/src/run.c index 67437d8..b7dc543 100644 --- a/src/run.c +++ b/src/run.c @@ -32,10 +32,8 @@ void killer(int foo) nfnl_subsys_close(STATE(subsys_event)); nfnl_subsys_close(STATE(subsys_dump)); - nfnl_subsys_close(STATE(subsys_sync)); nfnl_close(STATE(event)); nfnl_close(STATE(dump)); - nfnl_close(STATE(sync)); ignore_pool_destroy(STATE(ignore_pool)); local_server_destroy(STATE(local)); @@ -120,12 +118,6 @@ int init(int mode) return -1; } - if (nl_init_overrun_handler() == -1) { - dlog(STATE(log), "[FAIL] can't open netlink handler! " - "no ctnetlink kernel support?"); - return -1; - } - /* Signals handling */ sigemptyset(&STATE(block)); sigaddset(&STATE(block), SIGTERM); @@ -196,8 +188,7 @@ static void __run(void) * size and resync with master conntrack table. */ nl_resize_socket_buffer(STATE(event)); - nl_dump_conntrack_table(STATE(sync), - STATE(subsys_sync)); + STATE(mode)->overrun(); break; case ENOENT: /* diff --git a/src/stats-mode.c b/src/stats-mode.c index 9647bbf..581c07d 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -1,5 +1,5 @@ /* - * (C) 2006 by Pablo Neira Ayuso + * (C) 2006-2007 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 @@ -65,7 +65,7 @@ static int local_handler_stats(int fd, int type, void *data) cache_dump(STATE_STATS(cache), fd, NFCT_O_PLAIN); break; case DUMP_INT_XML: - cache_dump(STATE_SYNC(internal), fd, NFCT_O_XML); + cache_dump(STATE_STATS(cache), fd, NFCT_O_XML); break; case FLUSH_CACHE: dlog(STATE(log), "[REQ] flushing caches"); @@ -92,6 +92,48 @@ static void dump_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh) debug_ct(ct, "resync entry"); } +static int overrun_cb(enum nf_conntrack_msg_type type, + struct nf_conntrack *ct, + void *data) +{ + /* This is required by kernels < 2.6.20 */ + nfct_attr_unset(ct, ATTR_TIMEOUT); + nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES); + nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS); + nfct_attr_unset(ct, ATTR_REPL_COUNTER_BYTES); + nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); + nfct_attr_unset(ct, ATTR_USE); + + if (!cache_test(STATE_STATS(cache), ct)) + if (!cache_update_force(STATE_STATS(cache), ct)) + debug_ct(ct, "overrun stats resync"); + + return NFCT_CB_CONTINUE; +} + +static void overrun_stats() +{ + int ret; + struct nfct_handle *h; + int family = CONFIG(family); + + h = nfct_open(CONNTRACK, 0); + if (!h) { + dlog(STATE(log), "can't open overrun handler"); + return; + } + + nfct_callback_register(h, NFCT_T_ALL, overrun_cb, NULL); + + cache_flush(STATE_STATS(cache)); + + ret = nfct_query(h, NFCT_Q_DUMP, &family); + if (ret == -1) + dlog(STATE(log), "overrun query error %s", strerror(errno)); + + nfct_close(h); +} + static void event_new_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh) { debug_ct(ct, "debug event"); @@ -144,7 +186,7 @@ struct ct_mode stats_mode = { .local = local_handler_stats, .kill = kill_stats, .dump = dump_stats, - .overrun = dump_stats, + .overrun = overrun_stats, .event_new = event_new_stats, .event_upd = event_update_stats, .event_dst = event_destroy_stats diff --git a/src/sync-mode.c b/src/sync-mode.c index 0a195d7..65a3c5b 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -1,5 +1,5 @@ /* - * (C) 2006 by Pablo Neira Ayuso + * (C) 2006-2007 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 @@ -293,7 +293,9 @@ static void mcast_send_sync(struct nlmsghdr *nlh, STATE_SYNC(mcast_sync)->post_send(type, net, u); } -static void overrun_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) +static int overrun_cb(enum nf_conntrack_msg_type type, + struct nf_conntrack *ct, + void *data) { struct us_conntrack *u; @@ -307,10 +309,87 @@ static void overrun_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) if (!cache_test(STATE_SYNC(internal), ct)) { if ((u = cache_update_force(STATE_SYNC(internal), ct))) { - debug_ct(ct, "overrun resync"); + int ret; + char buf[4096]; + struct nlnetwork *net = (struct nlnetwork *) buf; + unsigned int size = sizeof(struct nlnetwork); + struct nlmsghdr *nlh = (struct nlmsghdr *) (buf + size); + + debug_ct(u->ct, "overrun resync"); + + ret = build_network_msg(NFCT_Q_UPDATE, + STATE(subsys_dump), + u->ct, + buf, + sizeof(buf)); + + if (ret == -1) { + dlog(STATE(log), "can't build overrun"); + return NFCT_CB_CONTINUE; + } + mcast_send_sync(nlh, u, ct, NFCT_T_UPDATE); } } + + return NFCT_CB_CONTINUE; +} + +static int overrun_purge_step(void *data1, void *data2) +{ + int ret; + struct nfct_handle *h = data1; + struct us_conntrack *u = data2; + + ret = nfct_query(h, NFCT_Q_GET, u->ct); + if (ret == -1 && errno == ENOENT) { + char buf[4096]; + struct nlnetwork *net = (struct nlnetwork *) buf; + unsigned int size = sizeof(struct nlnetwork); + struct nlmsghdr *nlh = (struct nlmsghdr *) (buf + size); + + debug_ct(u->ct, "overrun purge resync"); + + ret = build_network_msg(NFCT_Q_DESTROY, + STATE(subsys_dump), + u->ct, + buf, + sizeof(buf)); + + if (ret == -1) + dlog(STATE(log), "failed to build network message"); + + mcast_send_sync(nlh, NULL, u->ct, NFCT_T_DESTROY); + __cache_del(STATE_SYNC(internal), u->ct); + } + + return 0; +} + +/* it's likely that we're losing events, just try to do our best here */ +static void overrun_sync() +{ + int ret; + struct nfct_handle *h; + int family = CONFIG(family); + + h = nfct_open(CONNTRACK, 0); + if (!h) { + dlog(STATE(log), "can't open overrun handler"); + return; + } + + nfct_callback_register(h, NFCT_T_ALL, overrun_cb, NULL); + + ret = nfct_query(h, NFCT_Q_DUMP, &family); + if (ret == -1) + dlog(STATE(log), "overrun query error %s", strerror(errno)); + + nfct_callback_unregister(h); + + cache_iterate(STATE_SYNC(internal), h, overrun_purge_step); + + nfct_close(h); } static void event_new_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) -- cgit v1.2.3 From 1af6ff8f04bf4db0a9d9207797bca8eaf660cbe2 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Mon, 21 May 2007 15:18:58 +0000 Subject: add missing ignore_conntrack in the overrun handler --- src/netlink.c | 2 +- src/stats-mode.c | 3 +++ src/sync-mode.c | 3 +++ 3 files changed, 7 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/netlink.c b/src/netlink.c index 94200b9..b1f9fd7 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -25,7 +25,7 @@ #include #include "network.h" -static int ignore_conntrack(struct nf_conntrack *ct) +int ignore_conntrack(struct nf_conntrack *ct) { /* ignore a certain protocol */ if (CONFIG(ignore_protocol)[nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO)]) diff --git a/src/stats-mode.c b/src/stats-mode.c index 581c07d..22474e2 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -96,6 +96,9 @@ static int overrun_cb(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data) { + if (ignore_conntrack(ct)) + return NFCT_CB_CONTINUE; + /* This is required by kernels < 2.6.20 */ nfct_attr_unset(ct, ATTR_TIMEOUT); nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES); diff --git a/src/sync-mode.c b/src/sync-mode.c index 65a3c5b..d7bee9d 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -299,6 +299,9 @@ static int overrun_cb(enum nf_conntrack_msg_type type, { struct us_conntrack *u; + if (ignore_conntrack(ct)) + return NFCT_CB_CONTINUE; + /* This is required by kernels < 2.6.20 */ nfct_attr_unset(ct, ATTR_TIMEOUT); nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES); -- cgit v1.2.3 From bc91f60fc288fe1fd0729f7bafe0596837c3e675 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Thu, 24 May 2007 11:32:53 +0000 Subject: simplify checksum code: use UDP/multicast checksum facilities --- ChangeLog | 8 +++++++- include/mcast.h | 1 + include/network.h | 1 - src/Makefile.am | 2 +- src/checksum.c | 32 -------------------------------- src/mcast.c | 8 ++++++++ src/network.c | 33 --------------------------------- src/read_config_yy.y | 3 ++- 8 files changed, 19 insertions(+), 69 deletions(-) delete mode 100644 src/checksum.c (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 370308c..9a90e3d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,10 @@ -version 0.9.3 (yet unreleased) +version 0.9.4 (yet unreleased) +------------------------------ + += conntrackd = +o simplify checksum code: use UDP/multicast checksum facilities + +version 0.9.3 (2006/05/22) ------------------------------ = conntrackd = diff --git a/include/mcast.h b/include/mcast.h index 0f3e3cd..be1d0cd 100644 --- a/include/mcast.h +++ b/include/mcast.h @@ -7,6 +7,7 @@ struct mcast_conf { int ipproto; int backlog; int reuseaddr; + int checksum; unsigned short port; union { struct in_addr inet_addr; diff --git a/include/network.h b/include/network.h index dab50db..176274e 100644 --- a/include/network.h +++ b/include/network.h @@ -5,7 +5,6 @@ struct nlnetwork { u_int16_t flags; - u_int16_t checksum; u_int32_t seq; }; diff --git a/src/Makefile.am b/src/Makefile.am index 381f8ac..a67e09a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -16,7 +16,7 @@ conntrackd_SOURCES = alarm.c main.c run.c hash.c buffer.c \ cache_lifetime.c cache_timer.c \ sync-mode.c sync-notrack.c sync-nack.c \ traffic_stats.c stats-mode.c \ - network.c checksum.c \ + network.c \ state_helper.c state_helper_tcp.c \ read_config_yy.y read_config_lex.l diff --git a/src/checksum.c b/src/checksum.c deleted file mode 100644 index 41866ff..0000000 --- a/src/checksum.c +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Extracted from RFC 1071 with some minor changes to fix compilation on GCC, - * this can probably be improved - * --pablo 11/feb/07 - */ - -#include - -unsigned short do_csum(const void *addr, unsigned int count) -{ - unsigned int sum = 0; - - /* checksumming disabled, just skip */ - if (CONFIG(flags) & DONT_CHECKSUM) - return 0; - - while(count > 1) { - /* This is the inner loop */ - sum += *((unsigned short *) addr++); - count -= 2; - } - - /* Add left-over byte, if any */ - if(count > 0) - sum += *((unsigned char *) addr); - - /* Fold 32-bit sum to 16 bits */ - while (sum>>16) - sum = (sum & 0xffff) + (sum >> 16); - - return ~sum; -} diff --git a/src/mcast.c b/src/mcast.c index 9904544..85992fb 100644 --- a/src/mcast.c +++ b/src/mcast.c @@ -192,6 +192,14 @@ struct mcast_sock *mcast_client_create(struct mcast_conf *conf) return NULL; } + if (setsockopt(m->fd, SOL_SOCKET, SO_NO_CHECK, &conf->checksum, + sizeof(int)) == -1) { + debug("mcast_sock_client_create:setsockopt1"); + close(m->fd); + free(m); + return NULL; + } + switch(conf->ipproto) { case AF_INET: ret = __mcast_client_create_ipv4(m, conf); diff --git a/src/network.c b/src/network.c index 51e89c7..d073428 100644 --- a/src/network.c +++ b/src/network.c @@ -60,9 +60,6 @@ int mcast_send_netmsg(struct mcast_sock *m, void *data) if (nlh_host2network(nlh) == -1) return -1; - net->checksum = 0; - net->checksum = ntohs(do_csum(data, len)); - return send_netmsg(m, data, len); } @@ -87,8 +84,6 @@ int mcast_resend_netmsg(struct mcast_sock *m, void *data) net->flags = htons(net->flags); net->seq = htonl(cur_seq++); - net->checksum = 0; - net->checksum = ntohs(do_csum(data, len)); return send_netmsg(m, data, len); } @@ -113,29 +108,10 @@ int mcast_send_error(struct mcast_sock *m, void *data) net->flags = htons(net->flags); net->seq = htonl(cur_seq++); - net->checksum = 0; - net->checksum = ntohs(do_csum(data, len)); return send_netmsg(m, data, len); } -static int valid_checksum(void *data, unsigned int len) -{ - struct nlnetwork *net = data; - unsigned short checksum, tmp; - - checksum = ntohs(net->checksum); - - /* no checksum, skip */ - if (!checksum) - return 1; - - net->checksum = 0; - tmp = do_csum(data, len); - - return tmp == checksum; -} - int mcast_recv_netmsg(struct mcast_sock *m, void *data, int len) { int ret; @@ -161,9 +137,6 @@ int mcast_recv_netmsg(struct mcast_sock *m, void *data, int len) if (ret < sizeof(struct nlnetwork_ack)) return -1; - if (!valid_checksum(data, ret)) - return -1; - /* host byte order conversion */ net->flags = ntohs(net->flags); net->seq = ntohl(net->seq); @@ -176,9 +149,6 @@ int mcast_recv_netmsg(struct mcast_sock *m, void *data, int len) } if (ntohs(net->flags) & NET_RESYNC) { - if (!valid_checksum(data, ret)) - return -1; - /* host byte order conversion */ net->flags = ntohs(net->flags); net->seq = ntohl(net->seq); @@ -209,9 +179,6 @@ int mcast_recv_netmsg(struct mcast_sock *m, void *data, int len) if (nfhdr->version != NFNETLINK_V0) return -1; - if (!valid_checksum(data, ret)) - return -1; - /* host byte order conversion */ net->flags = ntohs(net->flags); net->seq = ntohl(net->seq); diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 1668919..988b540 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -104,11 +104,12 @@ timeout: T_TIMEOUT T_NUMBER checksum: T_CHECKSUM T_ON { + conf.mcast.checksum = 0; }; checksum: T_CHECKSUM T_OFF { - conf.flags |= DONT_CHECKSUM; + conf.mcast.checksum = 1; }; ignore_traffic : T_IGNORE_TRAFFIC '{' ignore_traffic_options '}'; -- cgit v1.2.3 From 3b8af061583bd7cc4fbc3f2a615586befe74cdb9 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Tue, 29 May 2007 15:14:17 +0000 Subject: conntrack --output requires one parameter (Krzysztof Oledzki) --- src/conntrack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index 2339a2c..18baf96 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -96,7 +96,7 @@ static struct option original_opts[] = { {"family", 1, 0, 'f'}, {"src-nat", 1, 0, 'n'}, {"dst-nat", 1, 0, 'g'}, - {"output", 0, 0, 'o'}, + {"output", 1, 0, 'o'}, {0, 0, 0, 0} }; -- cgit v1.2.3 From ca3d12bf81c4b0424d977c06092db9e6f1fb0528 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Wed, 30 May 2007 15:43:15 +0000 Subject: fix silly bug in build_network_message: out of bound memset --- ChangeLog | 4 ++++ src/network.c | 1 + 2 files changed, 5 insertions(+) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 9a90e3d..bb159f0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,10 @@ version 0.9.4 (yet unreleased) = conntrackd = o simplify checksum code: use UDP/multicast checksum facilities +o fix silly bug in build_network_message: out of bound memset + += conntrack = +o fix segfault with conntrack --output (Krzysztof Oledzky) version 0.9.3 (2006/05/22) ------------------------------ diff --git a/src/network.c b/src/network.c index d073428..abd30fe 100644 --- a/src/network.c +++ b/src/network.c @@ -249,6 +249,7 @@ int build_network_msg(const int msg_type, { memset(buffer, 0, size); buffer += sizeof(struct nlnetwork); + size -= sizeof(struct nlnetwork); return nfct_build_query(ssh, msg_type, ct, buffer, size); } -- cgit v1.2.3 From cea33148e4ccf108f587e5796c026600aba35ab1 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Mon, 4 Jun 2007 15:19:42 +0000 Subject: o remove useless backlog parameter in multicast sockets o remove reminiscents of delay destroy message and relax transitions o remove confusing StripNAT parameter: NAT support enabled by default o relax event tracking: *_update callbacks use cache_update_force o use wraparound-aware functions after/before/between o lots of cleanups --- ChangeLog | 6 ++ configure.in | 2 +- examples/sync/nack/node1/conntrackd.conf | 6 -- examples/sync/nack/node2/conntrackd.conf | 6 -- examples/sync/persistent/node1/conntrackd.conf | 6 -- examples/sync/persistent/node2/conntrackd.conf | 6 -- include/conntrackd.h | 17 +--- include/mcast.h | 1 - include/network.h | 19 +++++ include/sync.h | 8 +- src/cache_iterators.c | 3 +- src/netlink.c | 6 +- src/network.c | 27 ++----- src/read_config_yy.y | 12 ++- src/stats-mode.c | 20 +---- src/sync-mode.c | 104 +++++++++++-------------- src/sync-nack.c | 27 ++++--- src/sync-notrack.c | 44 +++-------- 18 files changed, 122 insertions(+), 198 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 396d3a4..05348e1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,6 +5,12 @@ version 0.9.4 (yet unreleased) o simplify checksum code: use UDP/multicast checksum facilities o fix silly bug in build_network_message: out of bound memset o fix error message in configure.in (Eric Leblond) +o remove useless backlog parameter in multicast sockets +o remove reminiscents of delay destroy message and relax transitions +o remove confusing StripNAT parameter: NAT support enabled by default +o relax event tracking: *_update callbacks use cache_update_force +o use wraparound-aware functions after/before/between +o lots of cleanups = conntrack = o fix segfault with conntrack --output (Krzysztof Oledzky) diff --git a/configure.in b/configure.in index 7a1445d..37e7a9c 100644 --- a/configure.in +++ b/configure.in @@ -1,4 +1,4 @@ -AC_INIT(conntrack-tools, 0.9.3, pablo@netfilter.org) +AC_INIT(conntrack-tools, 0.9.4, pablo@netfilter.org) AC_CANONICAL_SYSTEM diff --git a/examples/sync/nack/node1/conntrackd.conf b/examples/sync/nack/node1/conntrackd.conf index f24fa7e..edec9cf 100644 --- a/examples/sync/nack/node1/conntrackd.conf +++ b/examples/sync/nack/node1/conntrackd.conf @@ -33,7 +33,6 @@ Sync { IPv4_address 225.0.0.50 IPv4_interface 192.168.100.100 # IP of dedicated link Group 3780 - Backlog 20 } # Enable/Disable message checksumming @@ -118,8 +117,3 @@ IgnoreProtocol { VRRP # numeric numbers also valid } - -# -# Strip NAT traffic -# -StripNAT diff --git a/examples/sync/nack/node2/conntrackd.conf b/examples/sync/nack/node2/conntrackd.conf index 4f15773..de5f4d2 100644 --- a/examples/sync/nack/node2/conntrackd.conf +++ b/examples/sync/nack/node2/conntrackd.conf @@ -32,7 +32,6 @@ Sync { IPv4_address 225.0.0.50 IPv4_interface 192.168.100.200 # IP of dedicated link Group 3780 - Backlog 20 } # Enable/Disable message checksumming @@ -117,8 +116,3 @@ IgnoreProtocol { VRRP # numeric numbers also valid } - -# -# Strip NAT traffic -# -StripNAT diff --git a/examples/sync/persistent/node1/conntrackd.conf b/examples/sync/persistent/node1/conntrackd.conf index 90afeb7..60f264b 100644 --- a/examples/sync/persistent/node1/conntrackd.conf +++ b/examples/sync/persistent/node1/conntrackd.conf @@ -38,7 +38,6 @@ Sync { IPv4_address 225.0.0.50 IPv4_interface 192.168.100.100 # IP of dedicated link Group 3780 - Backlog 20 } # Enable/Disable message checksumming @@ -123,8 +122,3 @@ IgnoreProtocol { VRRP # numeric numbers also valid } - -# -# Strip NAT traffic -# -StripNAT diff --git a/examples/sync/persistent/node2/conntrackd.conf b/examples/sync/persistent/node2/conntrackd.conf index aee4a29..6a1806b 100644 --- a/examples/sync/persistent/node2/conntrackd.conf +++ b/examples/sync/persistent/node2/conntrackd.conf @@ -38,7 +38,6 @@ Sync { IPv4_address 225.0.0.50 IPv4_interface 192.168.100.200 # IP of dedicated link Group 3780 - Backlog 20 } # Enable/Disable message checksumming @@ -123,8 +122,3 @@ IgnoreProtocol { VRRP # numeric numbers also valid } - -# -# Strip NAT traffic -# -StripNAT diff --git a/include/conntrackd.h b/include/conntrackd.h index 76b9747..a620400 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -30,22 +30,13 @@ #define DEFAULT_LOCKFILE "/var/lock/conntrackd.lock" enum { - STRIP_NAT_BIT = 0, - STRIP_NAT = (1 << STRIP_NAT_BIT), - - DELAY_DESTROY_MSG_BIT = 1, - DELAY_DESTROY_MSG = (1 << DELAY_DESTROY_MSG_BIT), - - RELAX_TRANSITIONS_BIT = 2, - RELAX_TRANSITIONS = (1 << RELAX_TRANSITIONS_BIT), - - SYNC_MODE_PERSISTENT_BIT = 3, + SYNC_MODE_PERSISTENT_BIT = 0, SYNC_MODE_PERSISTENT = (1 << SYNC_MODE_PERSISTENT_BIT), - SYNC_MODE_NACK_BIT = 4, + SYNC_MODE_NACK_BIT = 1, SYNC_MODE_NACK = (1 << SYNC_MODE_NACK_BIT), - DONT_CHECKSUM_BIT = 5, + DONT_CHECKSUM_BIT = 2, DONT_CHECKSUM = (1 << DONT_CHECKSUM_BIT), }; @@ -122,7 +113,7 @@ struct ct_sync_state { struct mcast_sock *mcast_server; /* multicast socket: incoming */ struct mcast_sock *mcast_client; /* multicast socket: outgoing */ - struct sync_mode *mcast_sync; + struct sync_mode *sync; /* sync mode */ struct buffer *buffer; u_int32_t last_seq_sent; /* last sequence number sent */ diff --git a/include/mcast.h b/include/mcast.h index be1d0cd..66676dc 100644 --- a/include/mcast.h +++ b/include/mcast.h @@ -5,7 +5,6 @@ struct mcast_conf { int ipproto; - int backlog; int reuseaddr; int checksum; unsigned short port; diff --git a/include/network.h b/include/network.h index 176274e..5ba808a 100644 --- a/include/network.h +++ b/include/network.h @@ -30,4 +30,23 @@ enum { NET_ACK = (1 << NET_ACK_BIT), }; +/* extracted from net/tcp.h */ + +/* + * The next routines deal with comparing 32 bit unsigned ints + * and worry about wraparound (automatic with unsigned arithmetic). + */ + +static inline int before(__u32 seq1, __u32 seq2) +{ + return (__s32)(seq1-seq2) < 0; +} +#define after(seq2, seq1) before(seq1, seq2) + +/* is s2<=s1<=s3 ? */ +static inline int between(__u32 seq1, __u32 seq2, __u32 seq3) +{ + return seq3 - seq2 >= seq1 - seq2; +} + #endif diff --git a/include/sync.h b/include/sync.h index d8f1bca..72f6313 100644 --- a/include/sync.h +++ b/include/sync.h @@ -13,10 +13,10 @@ struct sync_mode { int (*init)(void); void (*kill)(void); int (*local)(int fd, int type, void *data); - int (*pre_recv)(const struct nlnetwork *net); - void (*post_send)(int type, - const struct nlnetwork *net, - struct us_conntrack *u); + int (*recv)(const struct nlnetwork *net); /* recv callback */ + void (*send)(int type, /* send callback */ + const struct nlnetwork *net, + struct us_conntrack *u); }; extern struct sync_mode notrack; diff --git a/src/cache_iterators.c b/src/cache_iterators.c index 1c03fef..fd6694a 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -219,7 +219,8 @@ static int do_bulk(void *data1, void *data2) debug_ct(u->ct, "failed to build"); mcast_send_netmsg(STATE_SYNC(mcast_client), net); - STATE_SYNC(mcast_sync)->post_send(NFCT_T_UPDATE, net, u); + if (STATE_SYNC(sync)->send) + STATE_SYNC(sync)->send(NFCT_T_UPDATE, net, u); /* keep iterating even if we have found errors */ return 0; diff --git a/src/netlink.c b/src/netlink.c index b1f9fd7..5f7cbeb 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -32,15 +32,13 @@ int ignore_conntrack(struct nf_conntrack *ct) return 1; /* Accept DNAT'ed traffic: not really coming to the local machine */ - if ((CONFIG(flags) & STRIP_NAT) && - nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) { + if (nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) { debug_ct(ct, "DNAT"); return 0; } /* Accept SNAT'ed traffic: not really coming to the local machine */ - if ((CONFIG(flags) & STRIP_NAT) && - nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) { + if (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) { debug_ct(ct, "SNAT"); return 0; } diff --git a/src/network.c b/src/network.c index abd30fe..a7ce740 100644 --- a/src/network.c +++ b/src/network.c @@ -205,33 +205,16 @@ int mcast_track_seq(u_int32_t seq, u_int32_t *exp_seq) goto out; /* out of sequence: some messages got lost */ - if (seq > STATE_SYNC(last_seq_recv)+1) { + if (after(seq, STATE_SYNC(last_seq_recv)+1)) { STATE_SYNC(packets_lost) += seq-STATE_SYNC(last_seq_recv)+1; ret = 0; goto out; } - /* out of sequence: replayed or sequence wrapped around issues */ - if (seq < STATE_SYNC(last_seq_recv)+1) { - /* - * Check if the sequence has wrapped around. - * Perhaps it can be a replayed packet. - */ - if (STATE_SYNC(last_seq_recv)+1-seq > ~0U/2) { - /* - * Indeed, it is a wrapped around - */ - STATE_SYNC(packets_lost) += - ~0U-STATE_SYNC(last_seq_recv)+1+seq; - } else { - /* - * It is a delayed packet - */ - dlog(STATE(log), "delayed packet? exp=%u rcv=%u", - STATE_SYNC(last_seq_recv)+1, seq); - } - ret = 0; - } + /* out of sequence: replayed/delayed packet? */ + if (before(seq, STATE_SYNC(last_seq_recv)+1)) + dlog(STATE(log), "delayed packet? exp=%u rcv=%u", + STATE_SYNC(last_seq_recv)+1, seq); out: *exp_seq = STATE_SYNC(last_seq_recv)+1; diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 988b540..57250b4 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -84,7 +84,8 @@ lock : T_LOCK T_PATH_VAL strip_nat: T_STRIP_NAT { - conf.flags |= STRIP_NAT; + fprintf(stderr, "Notice: StripNAT clause is obsolete. " + "Please, remove it from conntrackd.conf\n"); }; refreshtime : T_REFRESH T_NUMBER @@ -228,7 +229,8 @@ multicast_option : T_IPV6_IFACE T_IP multicast_option : T_BACKLOG T_NUMBER { - conf.mcast.backlog = $2; + fprintf(stderr, "Notice: Backlog option inside Multicast clause is " + "obsolete. Please, remove it from conntrackd.conf.\n"); }; multicast_option : T_GROUP T_NUMBER @@ -354,12 +356,14 @@ window_size: T_WINDOWSIZE T_NUMBER relax_transitions: T_RELAX_TRANSITIONS { - conf.flags |= RELAX_TRANSITIONS; + fprintf(stderr, "Notice: RelaxTransitions clause is obsolete. " + "Please, remove it from conntrackd.conf\n"); }; delay_destroy_msgs: T_DELAY { - conf.flags |= DELAY_DESTROY_MSG; + fprintf(stderr, "Notice: DelayDestroyMessages clause is obsolete. " + "Please, remove it from conntrackd.conf\n"); }; listen_to: T_LISTEN_TO T_IP diff --git a/src/stats-mode.c b/src/stats-mode.c index 22474e2..f65fbdb 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -139,7 +139,6 @@ static void overrun_stats() static void event_new_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh) { - debug_ct(ct, "debug event"); if (cache_add(STATE_STATS(cache), ct)) { debug_ct(ct, "cache new"); } else { @@ -151,22 +150,9 @@ static void event_new_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh) static void event_update_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh) { - debug_ct(ct, "update"); - - if (!cache_update(STATE_STATS(cache), ct)) { - /* - * Perhaps we are losing events. If we are working - * in relax mode then add a new entry to the cache. - * - * FIXME: relax transitions not implemented yet - */ - if ((CONFIG(flags) & RELAX_TRANSITIONS) - && cache_add(STATE_STATS(cache), ct)) { - debug_ct(ct, "forcing cache update"); - } else { - debug_ct(ct, "can't update"); - return; - } + if (!cache_update_force(STATE_STATS(cache), ct)) { + debug_ct(ct, "can't update"); + return; } debug_ct(ct, "update"); } diff --git a/src/sync-mode.c b/src/sync-mode.c index d7bee9d..cb95392 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -32,26 +32,25 @@ static void mcast_handler() { int ret; - char buf[4096], tmp[256]; - struct mcast_sock *m = STATE_SYNC(mcast_server); - unsigned int type; - struct nlnetwork *net = (struct nlnetwork *) buf; - unsigned int size = sizeof(struct nlnetwork); - struct nlmsghdr *nlh = (struct nlmsghdr *) (buf + size); - struct nf_conntrack *ct = (struct nf_conntrack *) tmp; + unsigned int type, size = sizeof(struct nlnetwork); + char __net[4096]; + struct nlnetwork *net = (struct nlnetwork *) __net; + struct nlmsghdr *nlh = (struct nlmsghdr *) (__net + size); + char __ct[nfct_maxsize()]; + struct nf_conntrack *ct = (struct nf_conntrack *) __ct; struct us_conntrack *u = NULL; - memset(tmp, 0, sizeof(tmp)); - - ret = mcast_recv_netmsg(m, buf, sizeof(buf)); + ret = mcast_recv_netmsg(STATE_SYNC(mcast_server), net, sizeof(__net)); if (ret <= 0) { STATE(malformed)++; return; } - if (STATE_SYNC(mcast_sync)->pre_recv(net)) + if (STATE_SYNC(sync)->recv(net)) return; + memset(ct, 0, sizeof(__ct)); + if ((type = parse_network_msg(ct, nlh)) == NFCT_T_ERROR) { STATE(malformed)++; return; @@ -111,19 +110,19 @@ static int init_sync(void) memset(state.sync, 0, sizeof(struct ct_sync_state)); if (CONFIG(flags) & SYNC_MODE_NACK) - STATE_SYNC(mcast_sync) = &nack; + STATE_SYNC(sync) = &nack; else /* default to persistent mode */ - STATE_SYNC(mcast_sync) = ¬rack; + STATE_SYNC(sync) = ¬rack; - if (STATE_SYNC(mcast_sync)->init) - STATE_SYNC(mcast_sync)->init(); + if (STATE_SYNC(sync)->init) + STATE_SYNC(sync)->init(); STATE_SYNC(internal) = cache_create("internal", - STATE_SYNC(mcast_sync)->internal_cache_flags, + STATE_SYNC(sync)->internal_cache_flags, CONFIG(family), - STATE_SYNC(mcast_sync)->internal_cache_extra); + STATE_SYNC(sync)->internal_cache_extra); if (!STATE_SYNC(internal)) { dlog(STATE(log), "[FAIL] can't allocate memory for " @@ -133,7 +132,7 @@ static int init_sync(void) STATE_SYNC(external) = cache_create("external", - STATE_SYNC(mcast_sync)->external_cache_flags, + STATE_SYNC(sync)->external_cache_flags, CONFIG(family), NULL); @@ -192,8 +191,8 @@ static void kill_sync() destroy_alarm_thread(); - if (STATE_SYNC(mcast_sync)->kill) - STATE_SYNC(mcast_sync)->kill(); + if (STATE_SYNC(sync)->kill) + STATE_SYNC(sync)->kill(); } static dump_stats_sync(int fd) @@ -253,8 +252,8 @@ static int local_handler_sync(int fd, int type, void *data) cache_bulk(STATE_SYNC(internal)); break; default: - if (STATE_SYNC(mcast_sync)->local) - ret = STATE_SYNC(mcast_sync)->local(fd, type, data); + if (STATE_SYNC(sync)->local) + ret = STATE_SYNC(sync)->local(fd, type, data); break; } @@ -280,17 +279,18 @@ static void mcast_send_sync(struct nlmsghdr *nlh, struct nf_conntrack *ct, int type) { - char buf[4096]; - struct nlnetwork *net = (struct nlnetwork *) buf; + char __net[4096]; + struct nlnetwork *net = (struct nlnetwork *) __net; - memset(buf, 0, sizeof(buf)); + memset(__net, 0, sizeof(__net)); if (!state_helper_verdict(type, ct)) return; - memcpy(buf + sizeof(struct nlnetwork), nlh, nlh->nlmsg_len); - mcast_send_netmsg(STATE_SYNC(mcast_client), net); - STATE_SYNC(mcast_sync)->post_send(type, net, u); + memcpy(__net + sizeof(struct nlnetwork), nlh, nlh->nlmsg_len); + mcast_send_netmsg(STATE_SYNC(mcast_client), net); + if (STATE_SYNC(sync)->send) + STATE_SYNC(sync)->send(type, net, u); } static int overrun_cb(enum nf_conntrack_msg_type type, @@ -313,18 +313,16 @@ static int overrun_cb(enum nf_conntrack_msg_type type, if (!cache_test(STATE_SYNC(internal), ct)) { if ((u = cache_update_force(STATE_SYNC(internal), ct))) { int ret; - char buf[4096]; - struct nlnetwork *net = (struct nlnetwork *) buf; - unsigned int size = sizeof(struct nlnetwork); - struct nlmsghdr *nlh = (struct nlmsghdr *) (buf + size); + char __nlh[4096]; + struct nlmsghdr *nlh = (struct nlmsghdr *) __nlh; debug_ct(u->ct, "overrun resync"); - ret = build_network_msg(NFCT_Q_UPDATE, - STATE(subsys_dump), - u->ct, - buf, - sizeof(buf)); + ret = nfct_build_query(STATE(subsys_dump), + NFCT_Q_UPDATE, + u->ct, + __nlh, + sizeof(__nlh)); if (ret == -1) { dlog(STATE(log), "can't build overrun"); @@ -346,18 +344,16 @@ static int overrun_purge_step(void *data1, void *data2) ret = nfct_query(h, NFCT_Q_GET, u->ct); if (ret == -1 && errno == ENOENT) { - char buf[4096]; - struct nlnetwork *net = (struct nlnetwork *) buf; - unsigned int size = sizeof(struct nlnetwork); - struct nlmsghdr *nlh = (struct nlmsghdr *) (buf + size); + char __nlh[4096]; + struct nlmsghdr *nlh = (struct nlmsghdr *) (__nlh); debug_ct(u->ct, "overrun purge resync"); - - ret = build_network_msg(NFCT_Q_DESTROY, - STATE(subsys_dump), - u->ct, - buf, - sizeof(buf)); + + ret = nfct_build_query(STATE(subsys_dump), + NFCT_Q_DESTROY, + u->ct, + __nlh, + sizeof(__nlh)); if (ret == -1) dlog(STATE(log), "failed to build network message"); @@ -411,18 +407,6 @@ retry: debug_ct(u->ct, "internal new"); } else { if (errno == EEXIST) { - char buf[4096]; - unsigned int size = sizeof(struct nlnetwork); - struct nlmsghdr *nlh = (struct nlmsghdr *) (buf + size); - - int ret = build_network_msg(NFCT_Q_DESTROY, - STATE(subsys_event), - ct, - buf, - sizeof(buf)); - if (ret == -1) - return; - cache_del(STATE_SYNC(internal), ct); mcast_send_sync(nlh, NULL, ct, NFCT_T_DESTROY); goto retry; @@ -440,7 +424,7 @@ static void event_update_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) nfct_attr_unset(ct, ATTR_TIMEOUT); - if ((u = cache_update(STATE_SYNC(internal), ct)) == NULL) { + if ((u = cache_update_force(STATE_SYNC(internal), ct)) == NULL) { debug_ct(ct, "can't update"); return; } diff --git a/src/sync-nack.c b/src/sync-nack.c index 73f6dc2..e435b09 100644 --- a/src/sync-nack.c +++ b/src/sync-nack.c @@ -136,7 +136,7 @@ static int buffer_compare(void *data1, void *data2) unsigned old_seq = ntohl(net->seq); - if (ntohl(net->seq) >= nack->from && ntohl(net->seq) <= nack->to) { + if (between(ntohl(net->seq), nack->from, nack->to)) { if (mcast_resend_netmsg(STATE_SYNC(mcast_client), net)) dp("resend destroy (old seq=%u) (seq=%u)\n", old_seq, ntohl(net->seq)); @@ -149,7 +149,7 @@ static int buffer_remove(void *data1, void *data2) struct nlnetwork *net = data1; struct nlnetwork_ack *h = data2; - if (ntohl(net->seq) >= h->from && ntohl(net->seq) <= h->to) { + if (between(ntohl(net->seq), h->from, h->to)) { dp("remove from buffer (seq=%u)\n", ntohl(net->seq)); __buffer_del(STATE_SYNC(buffer), data1); } @@ -169,7 +169,7 @@ static void queue_resend(struct cache *c, unsigned int from, unsigned int to) u = cache_get_conntrack(STATE_SYNC(internal), cn); - if (cn->seq >= from && cn->seq <= to) { + if (between(cn->seq, from, to)) { debug_ct(u->ct, "resend nack"); dp("resending nack'ed (oldseq=%u) ", cn->seq); @@ -186,10 +186,9 @@ static void queue_resend(struct cache *c, unsigned int from, unsigned int to) break; } - mcast_send_netmsg(STATE_SYNC(mcast_client), buf); - STATE_SYNC(mcast_sync)->post_send(NFCT_T_UPDATE, - net, - u); + mcast_send_netmsg(STATE_SYNC(mcast_client), buf); + if (STATE_SYNC(sync)->send) + STATE_SYNC(sync)->send(NFCT_T_UPDATE, net, u); dp("(newseq=%u)\n", *seq); } } @@ -208,7 +207,7 @@ static void queue_empty(struct cache *c, unsigned int from, unsigned int to) struct cache_nack *cn = (struct cache_nack *) n; u = cache_get_conntrack(STATE_SYNC(internal), cn); - if (cn->seq >= from && cn->seq <= to) { + if (between(cn->seq, from, to)) { dp("remove %u\n", cn->seq); debug_ct(u->ct, "ack received: empty queue"); dp("queue: deleting from queue (seq=%u)\n", cn->seq); @@ -219,7 +218,7 @@ static void queue_empty(struct cache *c, unsigned int from, unsigned int to) unlock(); } -static int nack_pre_recv(const struct nlnetwork *net) +static int nack_recv(const struct nlnetwork *net) { static unsigned int window = 0; unsigned int exp_seq; @@ -262,9 +261,9 @@ static int nack_pre_recv(const struct nlnetwork *net) return 0; } -static void nack_post_send(int type, - const struct nlnetwork *net, - struct us_conntrack *u) +static void nack_send(int type, + const struct nlnetwork *net, + struct us_conntrack *u) { unsigned int size = sizeof(struct nlnetwork); struct nlmsghdr *nlh = (struct nlmsghdr *) ((void *) net + size); @@ -301,6 +300,6 @@ struct sync_mode nack = { .init = nack_init, .kill = nack_kill, .local = nack_local, - .pre_recv = nack_pre_recv, - .post_send = nack_post_send, + .recv = nack_recv, + .send = nack_send, }; diff --git a/src/sync-notrack.c b/src/sync-notrack.c index cc56436..4a470f9 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -25,33 +25,18 @@ static void refresher(struct alarm_list *a, void *data) { struct us_conntrack *u = data; - char buf[8192]; + char __net[4096]; int size; - if (nfct_get_attr_u32(u->ct, ATTR_STATUS) & IPS_DYING) { - - debug_ct(u->ct, "persistence destroy"); + debug_ct(u->ct, "persistence update"); - size = build_network_msg(NFCT_Q_DESTROY, - STATE(subsys_event), - u->ct, - buf, - sizeof(buf)); - - __cache_del(u->cache, u->ct); - mcast_send_netmsg(STATE_SYNC(mcast_client), buf); - } else { - - debug_ct(u->ct, "persistence update"); - - a->expires = random() % CONFIG(refresh) + 1; - size = build_network_msg(NFCT_Q_UPDATE, - STATE(subsys_event), - u->ct, - buf, - sizeof(buf)); - mcast_send_netmsg(STATE_SYNC(mcast_client), buf); - } + a->expires = random() % CONFIG(refresh) + 1; + size = build_network_msg(NFCT_Q_UPDATE, + STATE(subsys_event), + u->ct, + __net, + sizeof(__net)); + mcast_send_netmsg(STATE_SYNC(mcast_client), __net); } static void cache_notrack_add(struct us_conntrack *u, void *data) @@ -84,7 +69,7 @@ static struct cache_extra cache_notrack_extra = { .destroy = cache_notrack_destroy }; -static int notrack_pre_recv(const struct nlnetwork *net) +static int notrack_recv(const struct nlnetwork *net) { unsigned int exp_seq; @@ -114,16 +99,9 @@ static int notrack_pre_recv(const struct nlnetwork *net) return 0; } -static void notrack_post_send(int type, - const struct nlnetwork *n, - struct us_conntrack *u) -{ -} - struct sync_mode notrack = { .internal_cache_flags = LIFETIME, .external_cache_flags = TIMER | LIFETIME, .internal_cache_extra = &cache_notrack_extra, - .pre_recv = notrack_pre_recv, - .post_send = notrack_post_send, + .recv = notrack_recv, }; -- cgit v1.2.3 From 96e24fbed8e9e45c82e500eb4d34293696dced23 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Mon, 4 Jun 2007 17:02:36 +0000 Subject: o use NFCT_SOPT_SETUP_* facilities: nfct_setobjopt o remove bogus option to get a conntrack in test.sh example file --- ChangeLog | 2 + examples/cli/test.sh | 3 +- src/conntrack.c | 110 ++++----------------------------------------------- 3 files changed, 11 insertions(+), 104 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 05348e1..aafd981 100644 --- a/ChangeLog +++ b/ChangeLog @@ -14,6 +14,8 @@ o lots of cleanups = conntrack = o fix segfault with conntrack --output (Krzysztof Oledzky) +o use NFCT_SOPT_SETUP_* facilities: nfct_setobjopt +o remove bogus option to get a conntrack in test.sh example file version 0.9.3 (2006/05/22) ------------------------------ diff --git a/examples/cli/test.sh b/examples/cli/test.sh index 36c4826..cb449bf 100644 --- a/examples/cli/test.sh +++ b/examples/cli/test.sh @@ -37,8 +37,7 @@ case $1 in get) echo "getting a conntrack" $CONNTRACK -G --orig-src $SRC --orig-dst $DST \ - -p tcp --orig-port-src $SPORT --orig-port-dst $DPORT \ - --reply-port-src $DPORT --reply-port-dst $SPORT + -p tcp --orig-port-src $SPORT --orig-port-dst $DPORT ;; change) echo "change a conntrack" diff --git a/src/conntrack.c b/src/conntrack.c index 18baf96..2555f2e 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -1024,57 +1024,10 @@ int main(int argc, char *argv[]) break; case CT_CREATE: - if ((options & CT_OPT_ORIG) - && !(options & CT_OPT_REPL)) { - nfct_set_attr_u8(obj, - ATTR_REPL_L3PROTO, - nfct_get_attr_u8(obj, - ATTR_ORIG_L3PROTO)); - if (family == AF_INET) { - nfct_set_attr_u32(obj, - ATTR_REPL_IPV4_SRC, - nfct_get_attr_u32(obj, - ATTR_ORIG_IPV4_DST)); - nfct_set_attr_u32(obj, - ATTR_REPL_IPV4_DST, - nfct_get_attr_u32(obj, - ATTR_ORIG_IPV4_SRC)); - } else if (family == AF_INET6) { - nfct_set_attr(obj, - ATTR_REPL_IPV6_SRC, - nfct_get_attr(obj, - ATTR_ORIG_IPV6_DST)); - nfct_set_attr(obj, - ATTR_REPL_IPV6_DST, - nfct_get_attr(obj, - ATTR_ORIG_IPV6_SRC)); - } - } else if (!(options & CT_OPT_ORIG) - && (options & CT_OPT_REPL)) { - nfct_set_attr_u8(obj, - ATTR_ORIG_L3PROTO, - nfct_get_attr_u8(obj, - ATTR_REPL_L3PROTO)); - if (family == AF_INET) { - nfct_set_attr_u32(obj, - ATTR_ORIG_IPV4_SRC, - nfct_get_attr_u32(obj, - ATTR_REPL_IPV4_DST)); - nfct_set_attr_u32(obj, - ATTR_ORIG_IPV4_DST, - nfct_get_attr_u32(obj, - ATTR_REPL_IPV4_SRC)); - } else if (family == AF_INET6) { - nfct_set_attr(obj, - ATTR_ORIG_IPV6_SRC, - nfct_get_attr(obj, - ATTR_REPL_IPV6_DST)); - nfct_set_attr(obj, - ATTR_ORIG_IPV6_DST, - nfct_get_attr(obj, - ATTR_REPL_IPV6_SRC)); - } - } + if ((options & CT_OPT_ORIG) && !(options & CT_OPT_REPL)) + nfct_setobjopt(obj, NFCT_SOPT_SETUP_REPLY); + else if (!(options & CT_OPT_ORIG) && (options & CT_OPT_REPL)) + nfct_setobjopt(obj, NFCT_SOPT_SETUP_ORIGINAL); cth = nfct_open(CONNTRACK, 0); if (!cth) @@ -1098,57 +1051,10 @@ int main(int argc, char *argv[]) break; case CT_UPDATE: - if ((options & CT_OPT_ORIG) - && !(options & CT_OPT_REPL)) { - nfct_set_attr_u8(obj, - ATTR_REPL_L3PROTO, - nfct_get_attr_u8(obj, - ATTR_ORIG_L3PROTO)); - if (family == AF_INET) { - nfct_set_attr_u32(obj, - ATTR_REPL_IPV4_SRC, - nfct_get_attr_u32(obj, - ATTR_ORIG_IPV4_DST)); - nfct_set_attr_u32(obj, - ATTR_REPL_IPV4_DST, - nfct_get_attr_u32(obj, - ATTR_ORIG_IPV4_SRC)); - } else if (family == AF_INET6) { - nfct_set_attr(obj, - ATTR_REPL_IPV6_SRC, - nfct_get_attr(obj, - ATTR_ORIG_IPV6_DST)); - nfct_set_attr(obj, - ATTR_REPL_IPV6_DST, - nfct_get_attr(obj, - ATTR_ORIG_IPV6_SRC)); - } - } else if (!(options & CT_OPT_ORIG) - && (options & CT_OPT_REPL)) { - nfct_set_attr_u8(obj, - ATTR_ORIG_L3PROTO, - nfct_get_attr_u8(obj, - ATTR_REPL_L3PROTO)); - if (family == AF_INET) { - nfct_set_attr_u32(obj, - ATTR_ORIG_IPV4_SRC, - nfct_get_attr_u32(obj, - ATTR_REPL_IPV4_DST)); - nfct_set_attr_u32(obj, - ATTR_ORIG_IPV4_DST, - nfct_get_attr_u32(obj, - ATTR_REPL_IPV4_SRC)); - } else if (family == AF_INET6) { - nfct_set_attr(obj, - ATTR_ORIG_IPV6_SRC, - nfct_get_attr(obj, - ATTR_REPL_IPV6_DST)); - nfct_set_attr(obj, - ATTR_ORIG_IPV6_DST, - nfct_get_attr(obj, - ATTR_REPL_IPV6_SRC)); - } - } + if ((options & CT_OPT_ORIG) && !(options & CT_OPT_REPL)) + nfct_setobjopt(obj, NFCT_SOPT_SETUP_REPLY); + else if (!(options & CT_OPT_ORIG) && (options & CT_OPT_REPL)) + nfct_setobjopt(obj, NFCT_SOPT_SETUP_ORIGINAL); cth = nfct_open(CONNTRACK, 0); if (!cth) -- cgit v1.2.3 From 8004cfdaa8c8467980d4390e9c9048937831595c Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Thu, 7 Jun 2007 18:47:43 +0000 Subject: commit phase: if conntrack exists, update it --- ChangeLog | 1 + src/cache_iterators.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 1350833..c252d1a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -10,6 +10,7 @@ o remove reminiscents of delay destroy message and relax transitions o remove confusing StripNAT parameter: NAT support enabled by default o relax event tracking: *_update callbacks use cache_update_force o use wraparound-aware functions after/before/between +o commit phase: if conntrack exists, update it o lots of cleanups = conntrack = diff --git a/src/cache_iterators.c b/src/cache_iterators.c index fd6694a..279ddab 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -112,7 +112,7 @@ static int do_commit(void *data1, void *data2) nfct_set_attr_u32(ct, ATTR_TIMEOUT, CONFIG(commit_timeout)); ret = nfct_build_query(STATE(subsys_dump), - NFCT_Q_CREATE, + NFCT_Q_CREATE_UPDATE, ct, nlh, sizeof(buf)); -- cgit v1.2.3 From 3e093dbcb66b3bca23f603836510b1b3032d92a5 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Sat, 9 Jun 2007 17:52:50 +0000 Subject: - add support for `-L --src-nat' and `-L --dst-nat' to show natted connections - update conntrack(8) manpage --- ChangeLog | 2 ++ conntrack.8 | 14 +++++++++----- src/conntrack.c | 36 ++++++++++++++++++++++++++++++++---- 3 files changed, 43 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index c252d1a..78af5b2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -18,6 +18,8 @@ o fix segfault with conntrack --output (Krzysztof Oledzky) o use NFCT_SOPT_SETUP_* facilities: nfct_setobjopt o remove bogus option to get a conntrack in test.sh example file o add aliases --sport and --dport to make it more iptables-like +o add support for `-L --src-nat' and `-L --dst-nat' to show natted connections +o update conntrack(8) manpage version 0.9.3 (2006/05/22) ------------------------------ diff --git a/conntrack.8 b/conntrack.8 index 3a35613..bb9b0e0 100644 --- a/conntrack.8 +++ b/conntrack.8 @@ -107,13 +107,14 @@ This option is only required in conjunction with "-L, --dump". If this option is .BI "-t, --timeout " "TIMEOUT" Specify the timeout. .TP -.BI "-u, --status " "[ASSURED|SEEN_REPLY|UNSET|SRC_NAT|DST_NAT][,...]" +.BI "-u, --status " "[ASSURED|SEEN_REPLY|UNSET][,...]" Specify the conntrack status. .TP -.BI "-i, --id " "ID" -Specify the conntrack ID. -. -This option can only be used in conjunction with "-L, --dump" to display the conntrack IDs. +.BI "-n, --src-nat " +Filter source NAT connections. +.TP +.BI "-g, --dst-nat " +Filter destination NAT connections. .TP .BI "--tuple-src " IP_ADDRESS Specify the tuple source address of an expectation. @@ -144,6 +145,9 @@ Dump the connection tracking table in XML .B conntrack \-L -f ipv6 -o extended Only dump IPv6 connections in /proc/net/nf_conntrack format .TP +.B conntrack \-L --src-nat +Dump source NAT connections +.TP .B conntrack \-E \-o timestamp Show connection events together with the timestamp .SH BUGS diff --git a/src/conntrack.c b/src/conntrack.c index 2555f2e..a14ee4b 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -94,8 +94,8 @@ static struct option original_opts[] = { {"mark", 1, 0, 'm'}, {"id", 2, 0, 'i'}, /* deprecated */ {"family", 1, 0, 'f'}, - {"src-nat", 1, 0, 'n'}, - {"dst-nat", 1, 0, 'g'}, + {"src-nat", 2, 0, 'n'}, + {"dst-nat", 2, 0, 'g'}, {"output", 1, 0, 'o'}, {0, 0, 0, 0} }; @@ -119,13 +119,13 @@ static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = /* Well, it's better than "Re: Linux vs FreeBSD" */ { /* s d r q p t u z e [ ] { } a m i f n g o */ -/*CT_LIST*/ {2,2,2,2,2,0,0,2,0,0,0,0,0,0,2,2,2,0,0,2}, +/*CT_LIST*/ {2,2,2,2,2,0,0,2,0,0,0,0,0,0,2,2,2,2,2,2}, /*CT_CREATE*/ {2,2,2,2,1,1,1,0,0,0,0,0,0,2,2,0,0,2,2,0}, /*CT_UPDATE*/ {2,2,2,2,1,2,2,0,0,0,0,0,0,0,2,2,0,0,0,0}, /*CT_DELETE*/ {2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0}, /*CT_GET*/ {2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,2,0,0,0,2}, /*CT_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*CT_EVENT*/ {2,2,2,2,2,0,0,0,2,0,0,0,0,0,2,0,0,0,0,2}, +/*CT_EVENT*/ {2,2,2,2,2,0,0,0,2,0,0,0,0,0,2,0,0,2,2,2}, /*VERSION*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, /*HELP*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, /*EXP_LIST*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,0,0,0}, @@ -597,6 +597,18 @@ static int event_cb(enum nf_conntrack_msg_type type, unsigned int output_type = NFCT_O_DEFAULT; unsigned int output_flags = 0; + if (options & CT_OPT_SRC_NAT && options & CT_OPT_DST_NAT) { + if (!nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT) && + !nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) + return NFCT_CB_CONTINUE; + } else if (options & CT_OPT_SRC_NAT && + !nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) { + return NFCT_CB_CONTINUE; + } else if (options & CT_OPT_DST_NAT && + !nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) { + return NFCT_CB_CONTINUE; + } + if (options & CT_COMPARISON && !nfct_compare(obj, ct)) return NFCT_CB_CONTINUE; @@ -626,6 +638,18 @@ static int dump_cb(enum nf_conntrack_msg_type type, unsigned int output_type = NFCT_O_DEFAULT; unsigned int output_flags = 0; + if (options & CT_OPT_SRC_NAT && options & CT_OPT_DST_NAT) { + if (!nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT) && + !nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) + return NFCT_CB_CONTINUE; + } else if (options & CT_OPT_SRC_NAT && + !nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) { + return NFCT_CB_CONTINUE; + } else if (options & CT_OPT_DST_NAT && + !nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) { + return NFCT_CB_CONTINUE; + } + if (options & CT_COMPARISON && !nfct_compare(obj, ct)) return NFCT_CB_CONTINUE; @@ -930,11 +954,15 @@ int main(int argc, char *argv[]) break; case 'n': options |= CT_OPT_SRC_NAT; + if (!optarg) + break; set_family(&family, AF_INET); nat_parse(optarg, 1, obj, CT_OPT_SRC_NAT); break; case 'g': options |= CT_OPT_DST_NAT; + if (!optarg) + break; set_family(&family, AF_INET); nat_parse(optarg, 1, obj, CT_OPT_DST_NAT); case 'm': -- cgit v1.2.3 From 7e28837a6073600129d2fc06c23c40726ef5976a Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Sat, 9 Jun 2007 19:24:07 +0000 Subject: remove dlopen infrastructure: simplification, it was too much for it --- ChangeLog | 1 + Makefile.am | 2 +- configure.in | 9 --------- extensions/Makefile.am | 16 +++++----------- extensions/libct_proto_icmp.c | 4 +--- extensions/libct_proto_tcp.c | 4 +--- extensions/libct_proto_udp.c | 4 +--- include/conntrack.h | 4 ++++ src/Makefile.am | 2 +- src/conntrack.c | 20 ++++---------------- 10 files changed, 19 insertions(+), 47 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index c045f1f..86a9a46 100644 --- a/ChangeLog +++ b/ChangeLog @@ -22,6 +22,7 @@ o remove bogus option to get a conntrack in test.sh example file o add aliases --sport and --dport to make it more iptables-like o add support for `-L --src-nat' and `-L --dst-nat' to show natted connections o update conntrack(8) manpage +o remove dlopen infrastructure version 0.9.3 (2006/05/22) ------------------------------ diff --git a/Makefile.am b/Makefile.am index 6f0e6fb..05c311f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -7,7 +7,7 @@ AUTOMAKE_OPTIONS = foreign dist-bzip2 1.6 man_MANS = conntrack.8 EXTRA_DIST = $(man_MANS) Make_global.am ChangeLog TODO examples -SUBDIRS = src extensions +SUBDIRS = extensions src DIST_SUBDIRS = include src extensions LINKOPTS = -lnfnetlink -lnetfilter_conntrack -lpthread AM_CFLAGS = -g diff --git a/configure.in b/configure.in index 06c787f..41a001c 100644 --- a/configure.in +++ b/configure.in @@ -98,15 +98,6 @@ dnl AC_FUNC_MALLOC dnl AC_FUNC_VPRINTF dnl AC_CHECK_FUNCS([memset]) -dnl-------------------------------- - -if test ! -z "$libdir"; then - MODULE_DIR="\\\"$libdir/conntrack-tools/\\\"" - CFLAGS="$CFLAGS -DCONNTRACK_LIB_DIR=$MODULE_DIR" -fi - -dnl-------------------------------- - dnl AC_CONFIG_FILES([Makefile dnl debug/Makefile dnl debug/src/Makefile diff --git a/extensions/Makefile.am b/extensions/Makefile.am index db97c4d..cf45688 100644 --- a/extensions/Makefile.am +++ b/extensions/Makefile.am @@ -1,14 +1,8 @@ include $(top_srcdir)/Make_global.am -AM_CFLAGS=-fPIC -Wall -LIBS= +noinst_LTLIBRARIES = libct_proto_tcp.la libct_proto_udp.la \ + libct_proto_icmp.la -pkglib_LTLIBRARIES = ct_proto_tcp.la ct_proto_udp.la \ - ct_proto_icmp.la - -ct_proto_tcp_la_SOURCES = libct_proto_tcp.c -ct_proto_tcp_la_LDFLAGS = -module -avoid-version -ct_proto_udp_la_SOURCES = libct_proto_udp.c -ct_proto_udp_la_LDFLAGS = -module -avoid-version -ct_proto_icmp_la_SOURCES = libct_proto_icmp.c -ct_proto_icmp_la_LDFLAGS = -module -avoid-version +libct_proto_tcp_la_SOURCES = libct_proto_tcp.c +libct_proto_udp_la_SOURCES = libct_proto_udp.c +libct_proto_icmp_la_SOURCES = libct_proto_icmp.c diff --git a/extensions/libct_proto_icmp.c b/extensions/libct_proto_icmp.c index 5c7717a..765ced4 100644 --- a/extensions/libct_proto_icmp.c +++ b/extensions/libct_proto_icmp.c @@ -91,9 +91,7 @@ static struct ctproto_handler icmp = { .version = VERSION, }; -static void __attribute__ ((constructor)) init(void); - -static void init(void) +void register_icmp(void) { register_proto(&icmp); } diff --git a/extensions/libct_proto_tcp.c b/extensions/libct_proto_tcp.c index 1f0cde6..5a40cef 100644 --- a/extensions/libct_proto_tcp.c +++ b/extensions/libct_proto_tcp.c @@ -215,9 +215,7 @@ static struct ctproto_handler tcp = { .version = VERSION, }; -static void __attribute__ ((constructor)) init(void); - -static void init(void) +void register_tcp(void) { register_proto(&tcp); } diff --git a/extensions/libct_proto_udp.c b/extensions/libct_proto_udp.c index ff9c3d2..cb131d6 100644 --- a/extensions/libct_proto_udp.c +++ b/extensions/libct_proto_udp.c @@ -176,9 +176,7 @@ static struct ctproto_handler udp = { .version = VERSION, }; -static void __attribute__ ((constructor)) init(void); - -static void init(void) +void register_udp(void) { register_proto(&udp); } diff --git a/include/conntrack.h b/include/conntrack.h index 31f4f4f..f344d72 100644 --- a/include/conntrack.h +++ b/include/conntrack.h @@ -170,4 +170,8 @@ struct ctproto_handler { extern void register_proto(struct ctproto_handler *h); +extern void register_tcp(void); +extern void register_udp(void); +extern void register_icmp(void); + #endif diff --git a/src/Makefile.am b/src/Makefile.am index a67e09a..8647d04 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -7,7 +7,7 @@ CLEANFILES = read_config_yy.c read_config_lex.c sbin_PROGRAMS = conntrack conntrackd conntrack_SOURCES = conntrack.c -conntrack_LDFLAGS = -rdynamic +conntrack_LDADD = ../extensions/libct_proto_tcp.la ../extensions/libct_proto_udp.la ../extensions/libct_proto_icmp.la conntrackd_SOURCES = alarm.c main.c run.c hash.c buffer.c \ local.c log.c mcast.c netlink.c proxy.c lock.c \ diff --git a/src/conntrack.c b/src/conntrack.c index a14ee4b..eece45b 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -136,8 +136,6 @@ static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = /*EXP_EVENT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, }; -static char *lib_dir = CONNTRACK_LIB_DIR; - static LIST_HEAD(proto_list); static unsigned int options; @@ -163,10 +161,6 @@ static struct ctproto_handler *findproto(char *name) if (!name) return handler; - lib_dir = getenv("CONNTRACK_LIB_DIR"); - if (!lib_dir) - lib_dir = CONNTRACK_LIB_DIR; - list_for_each(i, &proto_list) { cur = (struct ctproto_handler *) i; if (strcmp(cur->name, name) == 0) { @@ -175,16 +169,6 @@ static struct ctproto_handler *findproto(char *name) } } - if (!handler) { - char path[sizeof("ct_proto_.so") - + strlen(name) + strlen(lib_dir)]; - sprintf(path, "%s/ct_proto_%s.so", lib_dir, name); - if (dlopen(path, RTLD_NOW)) - handler = findproto(name); - else - fprintf(stderr, "%s\n", dlerror()); - } - return handler; } @@ -700,6 +684,10 @@ int main(int argc, char *argv[]) memset(__mask, 0, sizeof(__mask)); memset(__exp, 0, sizeof(__exp)); + register_tcp(); + register_udp(); + register_icmp(); + while ((c = getopt_long(argc, argv, "L::I::U::D::G::E::F::hVs:d:r:q:p:t:u:e:a:z[:]:{:}:m:i::f:o:", opts, NULL)) != -1) { -- cgit v1.2.3 From e6f0851b184123ebf04df45e2f29a59f0cb827eb Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Wed, 13 Jun 2007 19:46:11 +0000 Subject: - local requests return EXIT_FAILURE if it can't connect to the daemon - several cleanups --- ChangeLog | 1 + include/network.h | 5 +++-- src/main.c | 4 +++- src/network.c | 46 ++++++++++++---------------------------------- src/sync-nack.c | 40 ++++++++++------------------------------ 5 files changed, 29 insertions(+), 67 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 86a9a46..f1ae81f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -13,6 +13,7 @@ o remove confusing StripNAT parameter: NAT support enabled by default o relax event tracking: *_update callbacks use cache_update_force o use wraparound-aware functions after/before/between o commit phase: if conntrack exists, update it +o local requests return EXIT_FAILURE if it can't connect to the daemon o lots of cleanups = conntrack = diff --git a/include/network.h b/include/network.h index 5ba808a..243815a 100644 --- a/include/network.h +++ b/include/network.h @@ -4,13 +4,14 @@ #include struct nlnetwork { - u_int16_t flags; + u_int16_t flags; + u_int16_t padding; u_int32_t seq; }; struct nlnetwork_ack { u_int16_t flags; - u_int16_t checksum; + u_int16_t padding; u_int32_t seq; u_int32_t from; u_int32_t to; diff --git a/src/main.c b/src/main.c index 1c75970..a039793 100644 --- a/src/main.c +++ b/src/main.c @@ -252,9 +252,11 @@ int main(int argc, char *argv[]) } if (type == REQUEST) { - if (do_local_request(action, &conf.local, local_step) == -1) + if (do_local_request(action, &conf.local, local_step) == -1) { fprintf(stderr, "can't connect: is conntrackd " "running? appropiate permissions?\n"); + exit(EXIT_FAILURE); + } exit(EXIT_SUCCESS); } diff --git a/src/network.c b/src/network.c index a7ce740..37f437e 100644 --- a/src/network.c +++ b/src/network.c @@ -19,20 +19,25 @@ #include "conntrackd.h" #include "network.h" -#if 0 -#define _TEST_DROP -#else -#undef _TEST_DROP -#endif - -static int drop = 0; /* debugging purposes */ static unsigned int seq_set, cur_seq; static int send_netmsg(struct mcast_sock *m, void *data, unsigned int len) { struct nlnetwork *net = data; + if (!seq_set) { + seq_set = 1; + cur_seq = time(NULL); + net->flags |= NET_HELLO; + } + + net->flags = htons(net->flags); + net->seq = htonl(cur_seq++); + +#undef _TEST_DROP #ifdef _TEST_DROP + static int drop = 0; + if (++drop > 10) { drop = 0; printf("dropping resend (seq=%u)\n", ntohl(net->seq)); @@ -48,15 +53,6 @@ int mcast_send_netmsg(struct mcast_sock *m, void *data) unsigned int len = nlh->nlmsg_len + sizeof(struct nlnetwork); struct nlnetwork *net = data; - if (!seq_set) { - seq_set = 1; - cur_seq = time(NULL); - net->flags |= NET_HELLO; - } - - net->flags = htons(net->flags); - net->seq = htonl(cur_seq++); - if (nlh_host2network(nlh) == -1) return -1; @@ -71,20 +67,11 @@ int mcast_resend_netmsg(struct mcast_sock *m, void *data) net->flags = ntohs(net->flags); - if (!seq_set) { - seq_set = 1; - cur_seq = time(NULL); - net->flags |= NET_HELLO; - } - if (net->flags & NET_NACK || net->flags & NET_ACK) len = sizeof(struct nlnetwork_ack); else len = sizeof(struct nlnetwork) + ntohl(nlh->nlmsg_len); - net->flags = htons(net->flags); - net->seq = htonl(cur_seq++); - return send_netmsg(m, data, len); } @@ -93,12 +80,6 @@ int mcast_send_error(struct mcast_sock *m, void *data) struct nlnetwork *net = data; unsigned int len = sizeof(struct nlnetwork); - if (!seq_set) { - seq_set = 1; - cur_seq = time(NULL); - net->flags |= NET_HELLO; - } - if (net->flags & NET_NACK || net->flags & NET_ACK) { struct nlnetwork_ack *nack = (struct nlnetwork_ack *) net; nack->from = htonl(nack->from); @@ -106,9 +87,6 @@ int mcast_send_error(struct mcast_sock *m, void *data) len = sizeof(struct nlnetwork_ack); } - net->flags = htons(net->flags); - net->seq = htonl(cur_seq++); - return send_netmsg(m, data, len); } diff --git a/src/sync-nack.c b/src/sync-nack.c index e435b09..1f62294 100644 --- a/src/sync-nack.c +++ b/src/sync-nack.c @@ -77,47 +77,25 @@ static void nack_kill() buffer_destroy(STATE_SYNC(buffer)); } -static void mcast_send_nack(u_int32_t expt_seq, u_int32_t recv_seq) -{ - struct nlnetwork_ack nack = { - .flags = NET_NACK, - .from = expt_seq, - .to = recv_seq, - }; - - mcast_send_error(STATE_SYNC(mcast_client), &nack); - buffer_add(STATE_SYNC(buffer), &nack, sizeof(struct nlnetwork_ack)); -} - -static void mcast_send_ack(u_int32_t from, u_int32_t to) +static void mcast_send_control(u_int32_t flags, u_int32_t from, u_int32_t to) { struct nlnetwork_ack ack = { - .flags = NET_ACK, - .from = from, - .to = to, + .flags = flags, + .from = from, + .to = to, }; mcast_send_error(STATE_SYNC(mcast_client), &ack); buffer_add(STATE_SYNC(buffer), &ack, sizeof(struct nlnetwork_ack)); } -static void mcast_send_resync() -{ - struct nlnetwork net = { - .flags = NET_RESYNC, - }; - - mcast_send_error(STATE_SYNC(mcast_client), &net); - buffer_add(STATE_SYNC(buffer), &net, sizeof(struct nlnetwork)); -} - -int nack_local(int fd, int type, void *data) +static int nack_local(int fd, int type, void *data) { int ret = 1; switch(type) { case REQUEST_DUMP: - mcast_send_resync(); + mcast_send_control(NET_RESYNC, 0, 0); dlog(STATE(log), "[REQ] request resync"); break; default: @@ -228,13 +206,15 @@ static int nack_recv(const struct nlnetwork *net) if (!mcast_track_seq(net->seq, &exp_seq)) { dp("OOS: sending nack (seq=%u)\n", exp_seq); - mcast_send_nack(exp_seq, net->seq - 1); + mcast_send_control(NET_NACK, exp_seq, net->seq - 1); window = CONFIG(window_size); } else { /* received a window, send an acknowledgement */ if (--window == 0) { dp("sending ack (seq=%u)\n", net->seq); - mcast_send_ack(net->seq-CONFIG(window_size), net->seq); + mcast_send_control(NET_ACK, + net->seq - CONFIG(window_size), + net->seq); } } -- cgit v1.2.3 From 3f3a6701978df8ca16ebb5988eb7a46771deb964 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Tue, 19 Jun 2007 17:00:44 +0000 Subject: - more cleanups and code refactorization - remove several debug calls - create a child to dispatch dump requests: this will help to simplify the current locking schema. Later. --- ChangeLog | 2 ++ include/network.h | 22 +++++++------ include/sync.h | 6 ++-- src/cache.c | 1 - src/cache_iterators.c | 22 ++----------- src/ignore_pool.c | 1 - src/local.c | 19 +++-------- src/network.c | 89 ++++++++++++++++++++++++++++++++++++--------------- src/run.c | 13 ++++++-- src/stats-mode.c | 8 +++-- src/sync-mode.c | 69 ++++++++++++++++----------------------- src/sync-nack.c | 63 +++++++++++++----------------------- src/sync-notrack.c | 13 ++------ 13 files changed, 156 insertions(+), 172 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index f1ae81f..aa93d4c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -14,6 +14,8 @@ o relax event tracking: *_update callbacks use cache_update_force o use wraparound-aware functions after/before/between o commit phase: if conntrack exists, update it o local requests return EXIT_FAILURE if it can't connect to the daemon +o remove several debug statements +o fork when internal/external dump cache requests are received o lots of cleanups = conntrack = diff --git a/include/network.h b/include/network.h index 243815a..31903a5 100644 --- a/include/network.h +++ b/include/network.h @@ -3,32 +3,34 @@ #include -struct nlnetwork { +struct nethdr { u_int16_t flags; u_int16_t padding; u_int32_t seq; }; +#define NETHDR_SIZ sizeof(struct nethdr) -struct nlnetwork_ack { +struct nethdr_ack { u_int16_t flags; u_int16_t padding; u_int32_t seq; u_int32_t from; u_int32_t to; }; +#define NETHDR_ACK_SIZ sizeof(struct nethdr_ack) enum { - NET_HELLO_BIT = 0, - NET_HELLO = (1 << NET_HELLO_BIT), + NET_F_HELLO_BIT = 0, + NET_F_HELLO = (1 << NET_F_HELLO_BIT), - NET_RESYNC_BIT = 1, - NET_RESYNC = (1 << NET_RESYNC_BIT), + NET_F_RESYNC_BIT = 1, + NET_F_RESYNC = (1 << NET_F_RESYNC_BIT), - NET_NACK_BIT = 2, - NET_NACK = (1 << NET_NACK_BIT), + NET_F_NACK_BIT = 2, + NET_F_NACK = (1 << NET_F_NACK_BIT), - NET_ACK_BIT = 3, - NET_ACK = (1 << NET_ACK_BIT), + NET_F_ACK_BIT = 3, + NET_F_ACK = (1 << NET_F_ACK_BIT), }; /* extracted from net/tcp.h */ diff --git a/include/sync.h b/include/sync.h index 72f6313..a737e81 100644 --- a/include/sync.h +++ b/include/sync.h @@ -1,7 +1,7 @@ #ifndef _SYNC_HOOKS_H_ #define _SYNC_HOOKS_H_ -struct nlnetwork; +struct nethdr; struct us_conntrack; struct sync_mode { @@ -13,9 +13,9 @@ struct sync_mode { int (*init)(void); void (*kill)(void); int (*local)(int fd, int type, void *data); - int (*recv)(const struct nlnetwork *net); /* recv callback */ + int (*recv)(const struct nethdr *net); /* recv callback */ void (*send)(int type, /* send callback */ - const struct nlnetwork *net, + const struct nethdr *net, struct us_conntrack *u); }; diff --git a/src/cache.c b/src/cache.c index 1b130c8..3bf331c 100644 --- a/src/cache.c +++ b/src/cache.c @@ -23,7 +23,6 @@ #include #include "us-conntrack.h" #include "cache.h" -#include "debug.h" static u_int32_t hash(const void *data, struct hashtable *table) { diff --git a/src/cache_iterators.c b/src/cache_iterators.c index 279ddab..7ae25fa 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -23,7 +23,6 @@ #include #include #include "us-conntrack.h" -#include "debug.h" struct __dump_container { int fd; @@ -120,8 +119,7 @@ static int do_commit(void *data1, void *data2) free(ct); if (ret == -1) { - /* XXX: Please cleanup this debug crap, default in logfile */ - debug("--- failed to build: %s --- \n", strerror(errno)); + dlog(STATE(log), "failed to build: %s", strerror(errno)); return 0; } @@ -135,10 +133,8 @@ static int do_commit(void *data1, void *data2) c->commit_fail++; break; } - debug("--- failed to commit: %s --- \n", strerror(errno)); } else { c->commit_ok++; - debug("----- commit -----\n"); } /* keep iterating even if we have found errors */ @@ -207,20 +203,8 @@ static int do_bulk(void *data1, void *data2) { int ret; struct us_conntrack *u = data2; - char buf[4096]; - struct nlnetwork *net = (struct nlnetwork *) buf; - - ret = build_network_msg(NFCT_Q_UPDATE, - STATE(subsys_dump), - u->ct, - buf, - sizeof(buf)); - if (ret == -1) - debug_ct(u->ct, "failed to build"); - - mcast_send_netmsg(STATE_SYNC(mcast_client), net); - if (STATE_SYNC(sync)->send) - STATE_SYNC(sync)->send(NFCT_T_UPDATE, net, u); + + mcast_build_send_update(u); /* keep iterating even if we have found errors */ return 0; diff --git a/src/ignore_pool.c b/src/ignore_pool.c index 5946617..d6f0e93 100644 --- a/src/ignore_pool.c +++ b/src/ignore_pool.c @@ -20,7 +20,6 @@ #include "hash.h" #include "conntrackd.h" #include "ignore.h" -#include "debug.h" #include #define IGNORE_POOL_SIZE 32 diff --git a/src/local.c b/src/local.c index eef70ad..be51b9e 100644 --- a/src/local.c +++ b/src/local.c @@ -1,5 +1,5 @@ /* - * (C) 2006 by Pablo Neira Ayuso + * (C) 2006-2007 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 @@ -22,7 +22,6 @@ #include #include #include -#include "debug.h" #include "local.h" @@ -32,14 +31,11 @@ int local_server_create(struct local_conf *conf) int len; struct sockaddr_un local; - if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { - debug("local_server_create:socket"); + if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) return -1; - } if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &conf->reuseaddr, sizeof(conf->reuseaddr)) == -1) { - debug("local_server_create:setsockopt"); close(fd); return -1; } @@ -50,14 +46,12 @@ int local_server_create(struct local_conf *conf) unlink(conf->path); if (bind(fd, (struct sockaddr *) &local, len) == -1) { - debug("local_server_create:bind"); close(fd); return -1; } if (listen(fd, conf->backlog) == -1) { close(fd); - debug("local_server_create:listen"); return -1; } @@ -76,10 +70,8 @@ int do_local_server_step(int fd, void *data, struct sockaddr_un local; size_t sin_size = sizeof(struct sockaddr_un); - if ((rfd = accept(fd, (struct sockaddr *)&local, &sin_size)) == -1) { - debug("do_local_server_step:accept"); + if ((rfd = accept(fd, (struct sockaddr *)&local, &sin_size)) == -1) return -1; - } process(rfd, data); close(rfd); @@ -102,7 +94,6 @@ int local_client_create(struct local_conf *conf) if (connect(fd, (struct sockaddr *) &local, len) == -1) { close(fd); - debug("local_client_create: connect: "); return -1; } @@ -146,10 +137,8 @@ int do_local_request(int request, return -1; ret = send(fd, &request, sizeof(int), 0); - if (ret == -1) { - debug("send:"); + if (ret == -1) return -1; - } do_local_client_step(fd, step); diff --git a/src/network.c b/src/network.c index 37f437e..159bdf3 100644 --- a/src/network.c +++ b/src/network.c @@ -23,12 +23,12 @@ static unsigned int seq_set, cur_seq; static int send_netmsg(struct mcast_sock *m, void *data, unsigned int len) { - struct nlnetwork *net = data; + struct nethdr *net = data; if (!seq_set) { seq_set = 1; cur_seq = time(NULL); - net->flags |= NET_HELLO; + net->flags |= NET_F_HELLO; } net->flags = htons(net->flags); @@ -49,9 +49,9 @@ static int send_netmsg(struct mcast_sock *m, void *data, unsigned int len) int mcast_send_netmsg(struct mcast_sock *m, void *data) { - struct nlmsghdr *nlh = data + sizeof(struct nlnetwork); - unsigned int len = nlh->nlmsg_len + sizeof(struct nlnetwork); - struct nlnetwork *net = data; + struct nlmsghdr *nlh = data + NETHDR_SIZ; + unsigned int len = nlh->nlmsg_len + NETHDR_SIZ; + struct nethdr *net = data; if (nlh_host2network(nlh) == -1) return -1; @@ -61,40 +61,77 @@ int mcast_send_netmsg(struct mcast_sock *m, void *data) int mcast_resend_netmsg(struct mcast_sock *m, void *data) { - struct nlnetwork *net = data; - struct nlmsghdr *nlh = data + sizeof(struct nlnetwork); + struct nethdr *net = data; + struct nlmsghdr *nlh = data + NETHDR_SIZ; unsigned int len; net->flags = ntohs(net->flags); - if (net->flags & NET_NACK || net->flags & NET_ACK) - len = sizeof(struct nlnetwork_ack); + if (net->flags & NET_F_NACK || net->flags & NET_F_ACK) + len = NETHDR_ACK_SIZ; else - len = sizeof(struct nlnetwork) + ntohl(nlh->nlmsg_len); + len = ntohl(nlh->nlmsg_len) + NETHDR_SIZ; return send_netmsg(m, data, len); } int mcast_send_error(struct mcast_sock *m, void *data) { - struct nlnetwork *net = data; - unsigned int len = sizeof(struct nlnetwork); + struct nethdr *net = data; + unsigned int len = NETHDR_SIZ; - if (net->flags & NET_NACK || net->flags & NET_ACK) { - struct nlnetwork_ack *nack = (struct nlnetwork_ack *) net; + if (net->flags & NET_F_NACK || net->flags & NET_F_ACK) { + struct nethdr_ack *nack = (struct nethdr_ack *) net; nack->from = htonl(nack->from); nack->to = htonl(nack->to); - len = sizeof(struct nlnetwork_ack); + len = NETHDR_ACK_SIZ; } return send_netmsg(m, data, len); } +#include "us-conntrack.h" +#include "sync.h" + +static int __build_send(struct us_conntrack *u, int type, int query) +{ + char __net[4096]; + struct nethdr *net = (struct nethdr *) __net; + + if (!state_helper_verdict(type, u->ct)) + return 0; + + int ret = build_network_msg(query, + STATE(subsys_event), + u->ct, + __net, + sizeof(__net)); + + if (ret == -1) + return -1; + + mcast_send_netmsg(STATE_SYNC(mcast_client), __net); + if (STATE_SYNC(sync)->send) + STATE_SYNC(sync)->send(type, net, u); + + return 0; +} + +int mcast_build_send_update(struct us_conntrack *u) +{ + return __build_send(u, NFCT_T_UPDATE, NFCT_Q_UPDATE); +} + +int mcast_build_send_destroy(struct us_conntrack *u) +{ + return __build_send(u, NFCT_T_DESTROY, NFCT_Q_DESTROY); +} + int mcast_recv_netmsg(struct mcast_sock *m, void *data, int len) { int ret; - struct nlnetwork *net = data; - struct nlmsghdr *nlh = data + sizeof(struct nlnetwork); + struct nethdr *net = data; + struct nlmsghdr *nlh = data + NETHDR_SIZ; struct nfgenmsg *nfhdr; ret = mcast_recv(m, net, len); @@ -102,17 +139,17 @@ int mcast_recv_netmsg(struct mcast_sock *m, void *data, int len) return ret; /* message too small: no room for the header */ - if (ret < sizeof(struct nlnetwork)) + if (ret < NETHDR_SIZ) return -1; - if (ntohs(net->flags) & NET_HELLO) + if (ntohs(net->flags) & NET_F_HELLO) STATE_SYNC(last_seq_recv) = ntohl(net->seq) - 1; - if (ntohs(net->flags) & NET_NACK || ntohs(net->flags) & NET_ACK) { - struct nlnetwork_ack *nack = (struct nlnetwork_ack *) net; + if (ntohs(net->flags) & NET_F_NACK || ntohs(net->flags) & NET_F_ACK) { + struct nethdr_ack *nack = (struct nethdr_ack *) net; /* message too small: no room for the header */ - if (ret < sizeof(struct nlnetwork_ack)) + if (ret < NETHDR_ACK_SIZ) return -1; /* host byte order conversion */ @@ -126,7 +163,7 @@ int mcast_recv_netmsg(struct mcast_sock *m, void *data, int len) return ret; } - if (ntohs(net->flags) & NET_RESYNC) { + if (ntohs(net->flags) & NET_F_RESYNC) { /* host byte order conversion */ net->flags = ntohs(net->flags); net->seq = ntohl(net->seq); @@ -139,7 +176,7 @@ int mcast_recv_netmsg(struct mcast_sock *m, void *data, int len) return -1; /* information received and message length does not match */ - if (ret != ntohl(nlh->nlmsg_len) + sizeof(struct nlnetwork)) + if (ret != ntohl(nlh->nlmsg_len) + NETHDR_SIZ) return -1; /* this message does not come from ctnetlink */ @@ -209,8 +246,8 @@ int build_network_msg(const int msg_type, unsigned int size) { memset(buffer, 0, size); - buffer += sizeof(struct nlnetwork); - size -= sizeof(struct nlnetwork); + buffer += NETHDR_SIZ; + size -= NETHDR_SIZ; return nfct_build_query(ssh, msg_type, ct, buffer, size); } diff --git a/src/run.c b/src/run.c index b7dc543..0173c9f 100644 --- a/src/run.c +++ b/src/run.c @@ -47,6 +47,11 @@ void killer(int foo) exit(0); } +static void child(int foo) +{ + while(wait(NULL) > 0); +} + void local_handler(int fd, void *data) { int ret; @@ -54,11 +59,11 @@ void local_handler(int fd, void *data) ret = read(fd, &type, sizeof(type)); if (ret == -1) { - dlog(STATE(log), "can't read from unix socket\n"); + dlog(STATE(log), "can't read from unix socket"); return; } if (ret == 0) { - debug("nothing to process\n"); + dlog(STATE(log), "local request: nothing to process?"); return; } @@ -122,6 +127,7 @@ int init(int mode) sigemptyset(&STATE(block)); sigaddset(&STATE(block), SIGTERM); sigaddset(&STATE(block), SIGINT); + sigaddset(&STATE(block), SIGCHLD); if (signal(SIGINT, killer) == SIG_ERR) return -1; @@ -133,6 +139,9 @@ int init(int mode) if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) return -1; + if (signal(SIGCHLD, child) == SIG_ERR) + return -1; + dlog(STATE(log), "[OK] initialization completed"); return 0; diff --git a/src/stats-mode.c b/src/stats-mode.c index f65fbdb..92794cd 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -142,9 +142,11 @@ static void event_new_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh) if (cache_add(STATE_STATS(cache), ct)) { debug_ct(ct, "cache new"); } else { - dlog(STATE(log), "can't add to cache cache: " - "%s\n", strerror(errno)); - debug_ct(ct, "can't add"); + if (errno != EEXIST) { + dlog(STATE(log), "can't add to cache cache: " + "%s\n", strerror(errno)); + debug_ct(ct, "can't add"); + } } } diff --git a/src/sync-mode.c b/src/sync-mode.c index cb95392..8433532 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -32,10 +32,10 @@ static void mcast_handler() { int ret; - unsigned int type, size = sizeof(struct nlnetwork); + unsigned int type; char __net[4096]; - struct nlnetwork *net = (struct nlnetwork *) __net; - struct nlmsghdr *nlh = (struct nlmsghdr *) (__net + size); + struct nethdr *net = (struct nethdr *) __net; + struct nlmsghdr *nlh = (struct nlmsghdr *) (__net + NETHDR_SIZ); char __ct[nfct_maxsize()]; struct nf_conntrack *ct = (struct nf_conntrack *) __ct; struct us_conntrack *u = NULL; @@ -93,7 +93,7 @@ retry: debug_ct(ct, "can't destroy"); break; default: - debug("unknown type %d\n", type); + dlog(STATE(log), "mcast received unknown msg type %d\n", type); break; } } @@ -216,16 +216,32 @@ static int local_handler_sync(int fd, int type, void *data) switch(type) { case DUMP_INTERNAL: - cache_dump(STATE_SYNC(internal), fd, NFCT_O_PLAIN); + ret = fork(); + if (ret == 0) { + cache_dump(STATE_SYNC(internal), fd, NFCT_O_PLAIN); + exit(EXIT_SUCCESS); + } break; case DUMP_EXTERNAL: - cache_dump(STATE_SYNC(external), fd, NFCT_O_PLAIN); + ret = fork(); + if (ret == 0) { + cache_dump(STATE_SYNC(external), fd, NFCT_O_PLAIN); + exit(EXIT_SUCCESS); + } break; case DUMP_INT_XML: - cache_dump(STATE_SYNC(internal), fd, NFCT_O_XML); + ret = fork(); + if (ret == 0) { + cache_dump(STATE_SYNC(internal), fd, NFCT_O_XML); + exit(EXIT_SUCCESS); + } break; case DUMP_EXT_XML: - cache_dump(STATE_SYNC(external), fd, NFCT_O_XML); + ret = fork(); + if (ret == 0) { + cache_dump(STATE_SYNC(external), fd, NFCT_O_XML); + exit(EXIT_SUCCESS); + } break; case COMMIT: dlog(STATE(log), "[REQ] commit external cache to master table"); @@ -280,14 +296,14 @@ static void mcast_send_sync(struct nlmsghdr *nlh, int type) { char __net[4096]; - struct nlnetwork *net = (struct nlnetwork *) __net; + struct nethdr *net = (struct nethdr *) __net; memset(__net, 0, sizeof(__net)); if (!state_helper_verdict(type, ct)) return; - memcpy(__net + sizeof(struct nlnetwork), nlh, nlh->nlmsg_len); + memcpy(__net + NETHDR_SIZ, nlh, nlh->nlmsg_len); mcast_send_netmsg(STATE_SYNC(mcast_client), net); if (STATE_SYNC(sync)->send) STATE_SYNC(sync)->send(type, net, u); @@ -312,24 +328,8 @@ static int overrun_cb(enum nf_conntrack_msg_type type, if (!cache_test(STATE_SYNC(internal), ct)) { if ((u = cache_update_force(STATE_SYNC(internal), ct))) { - int ret; - char __nlh[4096]; - struct nlmsghdr *nlh = (struct nlmsghdr *) __nlh; - debug_ct(u->ct, "overrun resync"); - - ret = nfct_build_query(STATE(subsys_dump), - NFCT_Q_UPDATE, - u->ct, - __nlh, - sizeof(__nlh)); - - if (ret == -1) { - dlog(STATE(log), "can't build overrun"); - return NFCT_CB_CONTINUE; - } - - mcast_send_sync(nlh, u, ct, NFCT_T_UPDATE); + mcast_build_send_update(u); } } @@ -344,21 +344,8 @@ static int overrun_purge_step(void *data1, void *data2) ret = nfct_query(h, NFCT_Q_GET, u->ct); if (ret == -1 && errno == ENOENT) { - char __nlh[4096]; - struct nlmsghdr *nlh = (struct nlmsghdr *) (__nlh); - debug_ct(u->ct, "overrun purge resync"); - - ret = nfct_build_query(STATE(subsys_dump), - NFCT_Q_DESTROY, - u->ct, - __nlh, - sizeof(__nlh)); - - if (ret == -1) - dlog(STATE(log), "failed to build network message"); - - mcast_send_sync(nlh, NULL, u->ct, NFCT_T_DESTROY); + mcast_build_send_destroy(u); __cache_del(STATE_SYNC(internal), u->ct); } diff --git a/src/sync-nack.c b/src/sync-nack.c index 1f62294..20ad1f4 100644 --- a/src/sync-nack.c +++ b/src/sync-nack.c @@ -79,14 +79,14 @@ static void nack_kill() static void mcast_send_control(u_int32_t flags, u_int32_t from, u_int32_t to) { - struct nlnetwork_ack ack = { + struct nethdr_ack ack = { .flags = flags, .from = from, .to = to, }; mcast_send_error(STATE_SYNC(mcast_client), &ack); - buffer_add(STATE_SYNC(buffer), &ack, sizeof(struct nlnetwork_ack)); + buffer_add(STATE_SYNC(buffer), &ack, NETHDR_ACK_SIZ); } static int nack_local(int fd, int type, void *data) @@ -95,7 +95,7 @@ static int nack_local(int fd, int type, void *data) switch(type) { case REQUEST_DUMP: - mcast_send_control(NET_RESYNC, 0, 0); + mcast_send_control(NET_F_RESYNC, 0, 0); dlog(STATE(log), "[REQ] request resync"); break; default: @@ -108,9 +108,9 @@ static int nack_local(int fd, int type, void *data) static int buffer_compare(void *data1, void *data2) { - struct nlnetwork *net = data1; - struct nlnetwork_ack *nack = data2; - struct nlmsghdr *nlh = data1 + sizeof(struct nlnetwork); + struct nethdr *net = data1; + struct nethdr_ack *nack = data2; + struct nlmsghdr *nlh = data1 + NETHDR_SIZ; unsigned old_seq = ntohl(net->seq); @@ -124,8 +124,8 @@ static int buffer_compare(void *data1, void *data2) static int buffer_remove(void *data1, void *data2) { - struct nlnetwork *net = data1; - struct nlnetwork_ack *h = data2; + struct nethdr *net = data1; + struct nethdr_ack *h = data2; if (between(ntohl(net->seq), h->from, h->to)) { dp("remove from buffer (seq=%u)\n", ntohl(net->seq)); @@ -138,9 +138,7 @@ static void queue_resend(struct cache *c, unsigned int from, unsigned int to) { struct list_head *n; struct us_conntrack *u; - unsigned int *seq; - lock(); list_for_each(n, &queue) { struct cache_nack *cn = (struct cache_nack *) n; struct us_conntrack *u; @@ -151,35 +149,19 @@ static void queue_resend(struct cache *c, unsigned int from, unsigned int to) debug_ct(u->ct, "resend nack"); dp("resending nack'ed (oldseq=%u) ", cn->seq); - char buf[4096]; - struct nlnetwork *net = (struct nlnetwork *) buf; - - int ret = build_network_msg(NFCT_Q_UPDATE, - STATE(subsys_event), - u->ct, - buf, - sizeof(buf)); - if (ret == -1) { - unlock(); - break; - } - - mcast_send_netmsg(STATE_SYNC(mcast_client), buf); - if (STATE_SYNC(sync)->send) - STATE_SYNC(sync)->send(NFCT_T_UPDATE, net, u); - dp("(newseq=%u)\n", *seq); + if (mcast_build_send_update(u) == -1) + continue; + + dp("(newseq=%u)\n", cn->seq); } } - unlock(); } static void queue_empty(struct cache *c, unsigned int from, unsigned int to) { struct list_head *n, *tmp; struct us_conntrack *u; - unsigned int *seq; - lock(); dp("ACK from %u to %u\n", from, to); list_for_each_safe(n, tmp, &queue) { struct cache_nack *cn = (struct cache_nack *) n; @@ -193,10 +175,9 @@ static void queue_empty(struct cache *c, unsigned int from, unsigned int to) INIT_LIST_HEAD(&cn->head); } } - unlock(); } -static int nack_recv(const struct nlnetwork *net) +static int nack_recv(const struct nethdr *net) { static unsigned int window = 0; unsigned int exp_seq; @@ -206,31 +187,31 @@ static int nack_recv(const struct nlnetwork *net) if (!mcast_track_seq(net->seq, &exp_seq)) { dp("OOS: sending nack (seq=%u)\n", exp_seq); - mcast_send_control(NET_NACK, exp_seq, net->seq - 1); + mcast_send_control(NET_F_NACK, exp_seq, net->seq - 1); window = CONFIG(window_size); } else { /* received a window, send an acknowledgement */ if (--window == 0) { dp("sending ack (seq=%u)\n", net->seq); - mcast_send_control(NET_ACK, + mcast_send_control(NET_F_ACK, net->seq - CONFIG(window_size), net->seq); } } - if (net->flags & NET_NACK) { - struct nlnetwork_ack *nack = (struct nlnetwork_ack *) net; + if (net->flags & NET_F_NACK) { + struct nethdr_ack *nack = (struct nethdr_ack *) net; dp("NACK: from seq=%u to seq=%u\n", nack->from, nack->to); queue_resend(STATE_SYNC(internal), nack->from, nack->to); buffer_iterate(STATE_SYNC(buffer), nack, buffer_compare); return 1; - } else if (net->flags & NET_RESYNC) { + } else if (net->flags & NET_F_RESYNC) { dp("RESYNC ALL\n"); cache_bulk(STATE_SYNC(internal)); return 1; - } else if (net->flags & NET_ACK) { - struct nlnetwork_ack *h = (struct nlnetwork_ack *) net; + } else if (net->flags & NET_F_ACK) { + struct nethdr_ack *h = (struct nethdr_ack *) net; dp("ACK: from seq=%u to seq=%u\n", h->from, h->to); queue_empty(STATE_SYNC(internal), h->from, h->to); @@ -242,10 +223,10 @@ static int nack_recv(const struct nlnetwork *net) } static void nack_send(int type, - const struct nlnetwork *net, + const struct nethdr *net, struct us_conntrack *u) { - unsigned int size = sizeof(struct nlnetwork); + int size = NETHDR_SIZ; struct nlmsghdr *nlh = (struct nlmsghdr *) ((void *) net + size); struct cache_nack *cn; diff --git a/src/sync-notrack.c b/src/sync-notrack.c index 4a470f9..1d6eba8 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -25,18 +25,11 @@ static void refresher(struct alarm_list *a, void *data) { struct us_conntrack *u = data; - char __net[4096]; - int size; debug_ct(u->ct, "persistence update"); a->expires = random() % CONFIG(refresh) + 1; - size = build_network_msg(NFCT_Q_UPDATE, - STATE(subsys_event), - u->ct, - __net, - sizeof(__net)); - mcast_send_netmsg(STATE_SYNC(mcast_client), __net); + mcast_build_send_update(u); } static void cache_notrack_add(struct us_conntrack *u, void *data) @@ -69,7 +62,7 @@ static struct cache_extra cache_notrack_extra = { .destroy = cache_notrack_destroy }; -static int notrack_recv(const struct nlnetwork *net) +static int notrack_recv(const struct nethdr *net) { unsigned int exp_seq; @@ -78,7 +71,7 @@ static int notrack_recv(const struct nlnetwork *net) * generated in notrack mode, we don't want to crash the daemon * if someone nuts mixes nack and notrack. */ - if (net->flags & (NET_RESYNC | NET_NACK)) + if (net->flags) return 1; /* -- cgit v1.2.3 From 6575518b416eb625b562fa9f3d35533dfa8c1ca4 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Mon, 25 Jun 2007 14:55:18 +0000 Subject: fork when internal/external dump and commit requests are received --- ChangeLog | 2 +- src/cache_iterators.c | 6 ++---- src/sync-mode.c | 8 ++++++-- 3 files changed, 9 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index aa93d4c..8bd6c59 100644 --- a/ChangeLog +++ b/ChangeLog @@ -15,7 +15,7 @@ o use wraparound-aware functions after/before/between o commit phase: if conntrack exists, update it o local requests return EXIT_FAILURE if it can't connect to the daemon o remove several debug statements -o fork when internal/external dump cache requests are received +o fork when internal/external dump and commit requests are received o lots of cleanups = conntrack = diff --git a/src/cache_iterators.c b/src/cache_iterators.c index 7ae25fa..446cac8 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -71,9 +71,8 @@ void cache_dump(struct cache *c, int fd, int type) .type = type }; - lock(); + /* does not require locking: called inside fork() */ hashtable_iterate(c->h, (void *) &tmp, do_dump); - unlock(); } static int do_commit(void *data1, void *data2) @@ -147,9 +146,8 @@ void cache_commit(struct cache *c) unsigned int commit_exist = c->commit_exist; unsigned int commit_fail = c->commit_fail; - lock(); + /* does not require locking: called inside fork() */ hashtable_iterate(c->h, c, do_commit); - unlock(); /* calculate new entries committed */ commit_ok = c->commit_ok - commit_ok; diff --git a/src/sync-mode.c b/src/sync-mode.c index 8433532..38ab016 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -244,8 +244,12 @@ static int local_handler_sync(int fd, int type, void *data) } break; case COMMIT: - dlog(STATE(log), "[REQ] commit external cache to master table"); - cache_commit(STATE_SYNC(external)); + ret = fork(); + if (ret == 0) { + dlog(STATE(log), "[REQ] committing external cache"); + cache_commit(STATE_SYNC(external)); + exit(EXIT_SUCCESS); + } break; case FLUSH_CACHE: dlog(STATE(log), "[REQ] flushing caches"); -- cgit v1.2.3 From 96084e1a1f2e0a49c961bbddb9fffd2e03bfae3f Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Mon, 9 Jul 2007 19:11:53 +0000 Subject: - conntrack-tools requires libnetfilter_conntrack >= 0.0.81 - add len field to nethdr - implement buffered send/recv to batch messages - stop using netlink format for network messages: use similar TLV-based format - reduce synchronization messages size up to 60% - introduce periodic alive messages for sync-nack protocol - timeslice alarm implementation: remove alarm pthread, remove locking - simplify debugging functions: use nfct_snprintf instead - remove major use of libnfnetlink functions: use libnetfilter_conntrack API - deprecate conntrackd -F, use conntrack -F instead - major rework of the network infrastructure: much simple, less messy --- ChangeLog | 16 ++++ configure.in | 4 +- include/Makefile.am | 2 +- include/buffer.h | 5 +- include/conntrackd.h | 21 ++-- include/debug.h | 56 ++--------- include/network.h | 106 +++++++++++++++++++- include/sync.h | 7 +- include/timer.h | 17 ++++ src/Makefile.am | 7 +- src/alarm.c | 37 ++----- src/buffer.c | 26 ++--- src/build.c | 113 ++++++++++++++++++++++ src/cache.c | 40 +------- src/cache_iterators.c | 54 +---------- src/cache_timer.c | 2 +- src/lock.c | 32 ------- src/main.c | 1 + src/mcast.c | 1 - src/netlink.c | 137 ++++++-------------------- src/network.c | 238 +++++++++++++++++---------------------------- src/parse.c | 76 +++++++++++++++ src/proxy.c | 124 ------------------------ src/run.c | 72 ++++++++++---- src/state_helper.c | 2 +- src/stats-mode.c | 10 +- src/sync-mode.c | 152 +++++++++++++++++------------ src/sync-nack.c | 260 ++++++++++++++++++++++++++++++++++---------------- src/sync-notrack.c | 6 +- src/timer.c | 75 +++++++++++++++ 30 files changed, 909 insertions(+), 790 deletions(-) create mode 100644 include/timer.h create mode 100644 src/build.c create mode 100644 src/parse.c delete mode 100644 src/proxy.c create mode 100644 src/timer.c (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 0166c97..b65966b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +version 0.9.5 (yet unreleased) +------------------------------ + += conntrackd = +o conntrack-tools requires libnetfilter_conntrack >= 0.0.81 +o add len field to nethdr +o implement buffered send/recv to batch messages +o stop using netlink format for network messages: use similar TLV-based format +o reduce synchronization messages size up to 60% +o introduce periodic alive messages for sync-nack protocol +o timeslice alarm implementation: remove alarm pthread, remove locking +o simplify debugging functions: use nfct_snprintf instead +o remove major use of libnfnetlink functions: use libnetfilter_conntrack API +o deprecate conntrackd -F, use conntrack -F instead +o major rework of the network infrastructure: much simple, less messy + version 0.9.4 (2007/07/02) ------------------------------ diff --git a/configure.in b/configure.in index 41a001c..7e1cd20 100644 --- a/configure.in +++ b/configure.in @@ -1,4 +1,4 @@ -AC_INIT(conntrack-tools, 0.9.4, pablo@netfilter.org) +AC_INIT(conntrack-tools, 0.9.5, pablo@netfilter.org) AC_CANONICAL_SYSTEM @@ -18,7 +18,7 @@ esac dnl Dependencies LIBNFNETLINK_REQUIRED=0.0.25 -LIBNETFILTER_CONNTRACK_REQUIRED=0.0.80 +LIBNETFILTER_CONNTRACK_REQUIRED=0.0.81 PKG_CHECK_MODULES(LIBNFNETLINK, libnfnetlink >= $LIBNFNETLINK_REQUIRED,, AC_MSG_ERROR(Cannot find libnfnetlink >= $LIBNFNETLINK_REQUIRED)) diff --git a/include/Makefile.am b/include/Makefile.am index a7716d9..7b6bc14 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -2,5 +2,5 @@ noinst_HEADERS = alarm.h jhash.h slist.h cache.h linux_list.h \ sync.h conntrackd.h local.h us-conntrack.h \ debug.h log.h hash.h mcast.h buffer.h conntrack.h \ - state_helper.h network.h ignore.h + state_helper.h network.h ignore.h timer.h diff --git a/include/buffer.h b/include/buffer.h index 8d72dfb..cb42f51 100644 --- a/include/buffer.h +++ b/include/buffer.h @@ -4,13 +4,12 @@ #include #include #include -#include #include "linux_list.h" struct buffer { - pthread_mutex_t lock; size_t max_size; size_t cur_size; + unsigned int num_elems; struct list_head head; }; @@ -22,9 +21,9 @@ struct buffer_node { struct buffer *buffer_create(size_t max_size); void buffer_destroy(struct buffer *b); +unsigned int buffer_len(struct buffer *b); int buffer_add(struct buffer *b, const void *data, size_t size); void buffer_del(struct buffer *b, void *data); -void __buffer_del(struct buffer *b, void *data); void buffer_iterate(struct buffer *b, void *data, int (*iterate)(void *data1, void *data2)); diff --git a/include/conntrackd.h b/include/conntrackd.h index a620400..e89fc79 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -10,6 +10,7 @@ #include "debug.h" #include #include "state_helper.h" +#include "linux_list.h" #include /* UNIX facilities */ @@ -92,11 +93,8 @@ struct ct_general_state { struct ct_mode *mode; struct ignore_pool *ignore_pool; - struct nfnl_handle *event; /* event handler */ - struct nfnl_handle *dump; /* dump handler */ - - struct nfnl_subsys_handle *subsys_event; /* events */ - struct nfnl_subsys_handle *subsys_dump; /* dump */ + struct nfct_handle *event; /* event handler */ + struct nfct_handle *dump; /* dump handler */ /* statistics */ u_int64_t malformed; @@ -114,7 +112,6 @@ struct ct_sync_state { struct mcast_sock *mcast_client; /* multicast socket: outgoing */ struct sync_mode *sync; /* sync mode */ - struct buffer *buffer; u_int32_t last_seq_sent; /* last sequence number sent */ u_int32_t last_seq_recv; /* last sequence number recv */ @@ -141,17 +138,19 @@ extern struct ct_general_state st; #define IPPROTO_VRRP 112 #endif +#define STEPS_PER_SECONDS 5 + struct ct_mode { int (*init)(void); int (*add_fds_to_set)(fd_set *readfds); - void (*step)(fd_set *readfds); + void (*run)(fd_set *readfds, int step); int (*local)(int fd, int type, void *data); void (*kill)(void); - void (*dump)(struct nf_conntrack *ct, struct nlmsghdr *nlh); + void (*dump)(struct nf_conntrack *ct); void (*overrun)(void); - void (*event_new)(struct nf_conntrack *ct, struct nlmsghdr *nlh); - void (*event_upd)(struct nf_conntrack *ct, struct nlmsghdr *nlh); - int (*event_dst)(struct nf_conntrack *ct, struct nlmsghdr *nlh); + void (*event_new)(struct nf_conntrack *ct); + void (*event_upd)(struct nf_conntrack *ct); + int (*event_dst)(struct nf_conntrack *ct); }; /* conntrackd modes */ diff --git a/include/debug.h b/include/debug.h index 4d1f44f..1ffd9ac 100644 --- a/include/debug.h +++ b/include/debug.h @@ -1,57 +1,21 @@ #ifndef _DEBUG_H #define _DEBUG_H -#if 0 -#define debug printf -#else -#define debug -#endif - -#include -#include #include #undef DEBUG_CT -static inline void debug_ct(struct nf_conntrack *ct, char *msg) -{ #ifdef DEBUG_CT - struct in_addr addr, addr2, addr3, addr4; - - debug("----%s (%p) ----\n", msg, ct); - memcpy(&addr, - nfct_get_attr(ct, ATTR_ORIG_IPV4_SRC), - sizeof(u_int32_t)); - memcpy(&addr2, - nfct_get_attr(ct, ATTR_ORIG_IPV4_DST), - sizeof(u_int32_t)); - memcpy(&addr3, - nfct_get_attr(ct, ATTR_REPL_IPV4_SRC), - sizeof(u_int32_t)); - memcpy(&addr4, - nfct_get_attr(ct, ATTR_REPL_IPV4_DST), - sizeof(u_int32_t)); - - debug("status: %x\n", nfct_get_attr_u32(ct, ATTR_STATUS)); - debug("l3:%d l4:%d ", - nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO), - nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO)); - debug("%s:%hu ->", inet_ntoa(addr), - ntohs(nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC))); - debug("%s:%hu\n", - inet_ntoa(addr2), - ntohs(nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST))); - debug("l3:%d l4:%d ", - nfct_get_attr_u8(ct, ATTR_REPL_L3PROTO), - nfct_get_attr_u8(ct, ATTR_REPL_L4PROTO)); - debug("%s:%hu ->", - inet_ntoa(addr3), - ntohs(nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC))); - debug("%s:%hu\n", - inet_ntoa(addr4), - ntohs(nfct_get_attr_u16(ct, ATTR_REPL_PORT_DST))); - debug("-------------------------\n"); +#define debug_ct(ct, msg) \ +({ \ + char buf[1024]; \ + nfct_snprintf(buf, 1024, ct, NFCT_T_ALL, 0, 0); \ + printf("[%s]: %s\n", msg, buf); \ +}) +#define debug printf +#else +#define debug_ct(ct, msg) +#define debug #endif -} #endif diff --git a/include/network.h b/include/network.h index 31903a5..bc9431d 100644 --- a/include/network.h +++ b/include/network.h @@ -5,14 +5,17 @@ struct nethdr { u_int16_t flags; - u_int16_t padding; + u_int16_t len; u_int32_t seq; }; #define NETHDR_SIZ sizeof(struct nethdr) +#define NETHDR_DATA(x) \ + (struct netpld *)(((char *)x) + sizeof(struct nethdr)) + struct nethdr_ack { u_int16_t flags; - u_int16_t padding; + u_int16_t len; u_int32_t seq; u_int32_t from; u_int32_t to; @@ -31,8 +34,59 @@ enum { NET_F_ACK_BIT = 3, NET_F_ACK = (1 << NET_F_ACK_BIT), + + NET_F_ALIVE_BIT = 4, + NET_F_ALIVE = (1 << NET_F_ALIVE_BIT), }; +#define BUILD_NETMSG(ct, query) \ +({ \ + char __net[4096]; \ + memset(__net, 0, sizeof(__net)); \ + build_netmsg(ct, query, (struct nethdr *) __net); \ + (struct nethdr *) __net; \ +}) + +struct us_conntrack; +struct mcast_sock; + +void build_netmsg(struct nf_conntrack *ct, int query, struct nethdr *net); +int prepare_send_netmsg(struct mcast_sock *m, void *data); +int mcast_send_netmsg(struct mcast_sock *m, void *data); +int mcast_recv_netmsg(struct mcast_sock *m, void *data, int len); + +#define IS_DATA(x) ((x->flags & ~NET_F_HELLO) == 0) +#define IS_ACK(x) (x->flags & NET_F_ACK) +#define IS_NACK(x) (x->flags & NET_F_NACK) +#define IS_RESYNC(x) (x->flags & NET_F_RESYNC) +#define IS_ALIVE(x) (x->flags & NET_F_ALIVE) +#define IS_CTL(x) IS_ACK(x) || IS_NACK(x) || IS_RESYNC(x) || IS_ALIVE(x) +#define IS_HELLO(x) (x->flags & NET_F_HELLO) + +#define HDR_NETWORK2HOST(x) \ +({ \ + x->flags = ntohs(x->flags); \ + x->len = ntohs(x->len); \ + x->seq = ntohl(x->seq); \ + if (IS_CTL(x)) { \ + struct nethdr_ack *__ack = (struct nethdr_ack *) x; \ + __ack->from = ntohl(__ack->from); \ + __ack->to = ntohl(__ack->to); \ + } \ +}) + +#define HDR_HOST2NETWORK(x) \ +({ \ + if (IS_CTL(x)) { \ + struct nethdr_ack *__ack = (struct nethdr_ack *) x; \ + __ack->from = htonl(__ack->from); \ + __ack->to = htonl(__ack->to); \ + } \ + x->flags = htons(x->flags); \ + x->len = htons(x->len); \ + x->seq = htonl(x->seq); \ +}) + /* extracted from net/tcp.h */ /* @@ -52,4 +106,52 @@ static inline int between(__u32 seq1, __u32 seq2, __u32 seq3) return seq3 - seq2 >= seq1 - seq2; } +struct netpld { + u_int16_t len; + u_int16_t query; +}; +#define NETPLD_SIZ sizeof(struct netpld) + +#define PLD_NETWORK2HOST(x) \ +({ \ + x->len = ntohs(x->len); \ + x->query = ntohs(x->query); \ +}) + +#define PLD_HOST2NETWORK(x) \ +({ \ + x->len = htons(x->len); \ + x->query = htons(x->query); \ +}) + +struct netattr { + u_int16_t nta_len; + u_int16_t nta_attr; +}; + +#define ATTR_NETWORK2HOST(x) \ +({ \ + x->nta_len = ntohs(x->nta_len); \ + x->nta_attr = ntohs(x->nta_attr); \ +}) + +#define PLD_DATA(x) \ + (struct netattr *)(((char *)x) + sizeof(struct netpld)) + +#define PLD_TAIL(x) \ + (struct netattr *)(((char *)x) + sizeof(struct netpld) + x->len) + +#define NTA_DATA(x) \ + (void *)(((char *)x) + sizeof(struct netattr)) + +#define NTA_NEXT(x, len) \ +({ \ + len -= NTA_ALIGN(NTA_LENGTH(x->nta_len)); \ + (struct netattr *)(((char *)x) + NTA_ALIGN(NTA_LENGTH(x->nta_len))); \ +}) + +#define NTA_ALIGNTO 4 +#define NTA_ALIGN(len) (((len) + NTA_ALIGNTO - 1) & ~(NTA_ALIGNTO - 1)) +#define NTA_LENGTH(len) (NTA_ALIGN(sizeof(struct netattr)) + (len)) + #endif diff --git a/include/sync.h b/include/sync.h index a737e81..6345513 100644 --- a/include/sync.h +++ b/include/sync.h @@ -13,10 +13,9 @@ struct sync_mode { int (*init)(void); void (*kill)(void); int (*local)(int fd, int type, void *data); - int (*recv)(const struct nethdr *net); /* recv callback */ - void (*send)(int type, /* send callback */ - const struct nethdr *net, - struct us_conntrack *u); + int (*recv)(const struct nethdr *net); + void (*send)(struct nethdr *net, struct us_conntrack *u); + void (*run)(int step); }; extern struct sync_mode notrack; diff --git a/include/timer.h b/include/timer.h new file mode 100644 index 0000000..37b0fc9 --- /dev/null +++ b/include/timer.h @@ -0,0 +1,17 @@ +#ifndef _TIMER_H_ +#define _TIMER_H_ + +#include + +struct timer { + long credits; + struct timeval start; + struct timeval stop; + struct timeval diff; +}; + +#define GET_CREDITS(x) x.credits +#define GET_STARTTIME(x) x.start +#define GET_STOPTIME(x) x.stop + +#endif diff --git a/src/Makefile.am b/src/Makefile.am index 8647d04..d71e23c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -10,7 +10,7 @@ conntrack_SOURCES = conntrack.c conntrack_LDADD = ../extensions/libct_proto_tcp.la ../extensions/libct_proto_udp.la ../extensions/libct_proto_icmp.la conntrackd_SOURCES = alarm.c main.c run.c hash.c buffer.c \ - local.c log.c mcast.c netlink.c proxy.c lock.c \ + local.c log.c mcast.c netlink.c \ ignore_pool.c \ cache.c cache_iterators.c \ cache_lifetime.c cache_timer.c \ @@ -18,9 +18,10 @@ conntrackd_SOURCES = alarm.c main.c run.c hash.c buffer.c \ traffic_stats.c stats-mode.c \ network.c \ state_helper.c state_helper_tcp.c \ + timer.c \ + build.c parse.c \ read_config_yy.y read_config_lex.l -conntrackd_LDFLAGS = $(all_libraries) -lnfnetlink -lnetfilter_conntrack \ - -lpthread +conntrackd_LDFLAGS = $(all_libraries) -lnfnetlink -lnetfilter_conntrack EXTRA_DIST = read_config_yy.h diff --git a/src/alarm.c b/src/alarm.c index 1a465c2..b4db167 100644 --- a/src/alarm.c +++ b/src/alarm.c @@ -22,17 +22,13 @@ #include "conntrackd.h" #include "alarm.h" #include "jhash.h" -#include #include #include /* alarm cascade */ -#define ALARM_CASCADE_SIZE 10 +#define ALARM_CASCADE_SIZE STEPS_PER_SECONDS static struct list_head *alarm_cascade; -/* thread stuff */ -static pthread_t alarm_thread; - struct alarm_list *create_alarm() { return (struct alarm_list *) malloc(sizeof(struct alarm_list)); @@ -86,24 +82,11 @@ int mod_alarm(struct alarm_list *alarm, unsigned long expires) return 0; } -void __run_alarms() +void do_alarm_run(int step) { struct list_head *i, *tmp; struct alarm_list *t; - struct timespec req = {0, 1000000000 / ALARM_CASCADE_SIZE}; - struct timespec rem; - static int step = 0; - -retry: - if (nanosleep(&req, &rem) == -1) { - /* interrupted syscall: retry with remaining time */ - if (errno == EINTR) { - memcpy(&req, &rem, sizeof(struct timespec)); - goto retry; - } - } - lock(); list_for_each_safe(i, tmp, &alarm_cascade[step]) { t = (struct alarm_list *) i; @@ -111,17 +94,9 @@ retry: if (t->expires == 0) t->function(t, t->data); } - step = (step + 1) < ALARM_CASCADE_SIZE ? step + 1 : 0; - unlock(); -} - -void *run_alarms(void *foo) -{ - while(1) - __run_alarms(); } -int create_alarm_thread() +int init_alarm_scheduler() { int i; @@ -132,10 +107,10 @@ int create_alarm_thread() for (i=0; imax_size = max_size; INIT_LIST_HEAD(&b->head); - pthread_mutex_init(&b->lock, NULL); return b; } @@ -39,14 +38,12 @@ void buffer_destroy(struct buffer *b) struct list_head *i, *tmp; struct buffer_node *node; - pthread_mutex_lock(&b->lock); + /* XXX: set cur_size and num_elems */ list_for_each_safe(i, tmp, &b->head) { node = (struct buffer_node *) i; list_del(i); free(node); } - pthread_mutex_unlock(&b->lock); - pthread_mutex_destroy(&b->lock); free(b); } @@ -70,8 +67,6 @@ int buffer_add(struct buffer *b, const void *data, size_t size) int ret = 0; struct buffer_node *n; - pthread_mutex_lock(&b->lock); - /* does it fit this buffer? */ if (size > b->max_size) { errno = ENOSPC; @@ -97,28 +92,22 @@ retry: list_add(&n->head, &b->head); b->cur_size += size; + b->num_elems++; err: - pthread_mutex_unlock(&b->lock); return ret; } -void __buffer_del(struct buffer *b, void *data) +void buffer_del(struct buffer *b, void *data) { struct buffer_node *n = container_of(data, struct buffer_node, data); list_del(&n->head); b->cur_size -= n->size; + b->num_elems--; free(n); } -void buffer_del(struct buffer *b, void *data) -{ - pthread_mutex_lock(&b->lock); - buffer_del(b, data); - pthread_mutex_unlock(&b->lock); -} - void buffer_iterate(struct buffer *b, void *data, int (*iterate)(void *data1, void *data2)) @@ -126,11 +115,14 @@ void buffer_iterate(struct buffer *b, struct list_head *i, *tmp; struct buffer_node *n; - pthread_mutex_lock(&b->lock); list_for_each_safe(i, tmp, &b->head) { n = (struct buffer_node *) i; if (iterate(n->data, data)) break; } - pthread_mutex_unlock(&b->lock); +} + +unsigned int buffer_len(struct buffer *b) +{ + return b->num_elems; } diff --git a/src/build.c b/src/build.c new file mode 100644 index 0000000..b77dbc2 --- /dev/null +++ b/src/build.c @@ -0,0 +1,113 @@ +/* + * (C) 2006-2007 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include "network.h" + +static void addattr(struct netpld *pld, int attr, const void *data, int len) +{ + struct netattr *nta; + int tlen = NTA_LENGTH(len); + + nta = PLD_TAIL(pld); + nta->nta_attr = htons(attr); + nta->nta_len = htons(len); + memcpy(NTA_DATA(nta), data, len); + pld->len += NTA_ALIGN(tlen); +} + +static void __build_u8(const struct nf_conntrack *ct, + struct netpld *pld, + int attr) +{ + u_int8_t data = nfct_get_attr_u8(ct, attr); + addattr(pld, attr, &data, sizeof(u_int8_t)); +} + +static void __build_u16(const struct nf_conntrack *ct, + struct netpld *pld, + int attr) +{ + u_int16_t data = nfct_get_attr_u16(ct, attr); + data = htons(data); + addattr(pld, attr, &data, sizeof(u_int16_t)); +} + +static void __build_u32(const struct nf_conntrack *ct, + struct netpld *pld, + int attr) +{ + u_int32_t data = nfct_get_attr_u32(ct, attr); + data = htonl(data); + addattr(pld, attr, &data, sizeof(u_int32_t)); +} + +/* XXX: IPv6 and ICMP not supported */ +void build_netpld(struct nf_conntrack *ct, struct netpld *pld, int query) +{ + /* undo NAT */ + if (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) + nfct_setobjopt(ct, NFCT_SOPT_UNDO_SNAT); + if (nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) + nfct_setobjopt(ct, NFCT_SOPT_UNDO_DNAT); + if (nfct_getobjopt(ct, NFCT_GOPT_IS_SPAT)) + nfct_setobjopt(ct, NFCT_SOPT_UNDO_SPAT); + if (nfct_getobjopt(ct, NFCT_GOPT_IS_DPAT)) + nfct_setobjopt(ct, NFCT_SOPT_UNDO_DPAT); + + /* build message */ + if (nfct_attr_is_set(ct, ATTR_IPV4_SRC)) + __build_u32(ct, pld, ATTR_IPV4_SRC); + if (nfct_attr_is_set(ct, ATTR_IPV4_DST)) + __build_u32(ct, pld, ATTR_IPV4_DST); + if (nfct_attr_is_set(ct, ATTR_L3PROTO)) + __build_u8(ct, pld, ATTR_L3PROTO); + if (nfct_attr_is_set(ct, ATTR_PORT_SRC)) + __build_u16(ct, pld, ATTR_PORT_SRC); + if (nfct_attr_is_set(ct, ATTR_PORT_DST)) + __build_u16(ct, pld, ATTR_PORT_DST); + if (nfct_attr_is_set(ct, ATTR_L4PROTO)) { + u_int8_t proto; + + __build_u8(ct, pld, ATTR_L4PROTO); + proto = nfct_get_attr_u8(ct, ATTR_L4PROTO); + if (proto == IPPROTO_TCP) { + if (nfct_attr_is_set(ct, ATTR_TCP_STATE)) + __build_u8(ct, pld, ATTR_TCP_STATE); + } + } + if (nfct_attr_is_set(ct, ATTR_SNAT_IPV4)) + __build_u32(ct, pld, ATTR_SNAT_IPV4); + if (nfct_attr_is_set(ct, ATTR_DNAT_IPV4)) + __build_u32(ct, pld, ATTR_DNAT_IPV4); + if (nfct_attr_is_set(ct, ATTR_SNAT_PORT)) + __build_u16(ct, pld, ATTR_SNAT_PORT); + if (nfct_attr_is_set(ct, ATTR_DNAT_PORT)) + __build_u16(ct, pld, ATTR_DNAT_PORT); + if (nfct_attr_is_set(ct, ATTR_TIMEOUT)) + __build_u32(ct, pld, ATTR_TIMEOUT); + if (nfct_attr_is_set(ct, ATTR_MARK)) + __build_u32(ct, pld, ATTR_MARK); + if (nfct_attr_is_set(ct, ATTR_STATUS)) + __build_u32(ct, pld, ATTR_STATUS); + + pld->query = query; + + PLD_HOST2NETWORK(pld); +} diff --git a/src/cache.c b/src/cache.c index 3bf331c..1e20d95 100644 --- a/src/cache.c +++ b/src/cache.c @@ -193,9 +193,7 @@ struct cache *cache_create(char *name, void cache_destroy(struct cache *c) { - lock(); hashtable_destroy(c->h); - unlock(); free(c->features); free(c->feature_offset); free(c); @@ -237,7 +235,7 @@ static struct us_conntrack *__add(struct cache *c, struct nf_conntrack *ct) return NULL; } -struct us_conntrack *__cache_add(struct cache *c, struct nf_conntrack *ct) +struct us_conntrack *cache_add(struct cache *c, struct nf_conntrack *ct) { struct us_conntrack *u; @@ -252,17 +250,6 @@ struct us_conntrack *__cache_add(struct cache *c, struct nf_conntrack *ct) return NULL; } -struct us_conntrack *cache_add(struct cache *c, struct nf_conntrack *ct) -{ - struct us_conntrack *u; - - lock(); - u = __cache_add(c, ct); - unlock(); - - return u; -} - static struct us_conntrack *__update(struct cache *c, struct nf_conntrack *ct) { size_t size = c->h->datasize; @@ -317,9 +304,7 @@ struct us_conntrack *cache_update(struct cache *c, struct nf_conntrack *ct) { struct us_conntrack *u; - lock(); u = __cache_update(c, ct); - unlock(); return u; } @@ -329,19 +314,15 @@ struct us_conntrack *cache_update_force(struct cache *c, { struct us_conntrack *u; - lock(); if ((u = __update(c, ct)) != NULL) { c->upd_ok++; - unlock(); return u; } if ((u = __add(c, ct)) != NULL) { c->add_ok++; - unlock(); return u; } c->add_fail++; - unlock(); return NULL; } @@ -354,9 +335,7 @@ int cache_test(struct cache *c, struct nf_conntrack *ct) u->ct = ct; - lock(); ret = hashtable_test(c->h, u); - unlock(); return ret != NULL; } @@ -390,7 +369,7 @@ static int __del(struct cache *c, struct nf_conntrack *ct) return 0; } -int __cache_del(struct cache *c, struct nf_conntrack *ct) +int cache_del(struct cache *c, struct nf_conntrack *ct) { if (__del(c, ct)) { c->del_ok++; @@ -401,17 +380,6 @@ int __cache_del(struct cache *c, struct nf_conntrack *ct) return 0; } -int cache_del(struct cache *c, struct nf_conntrack *ct) -{ - int ret; - - lock(); - ret = __cache_del(c, ct); - unlock(); - - return ret; -} - struct us_conntrack *cache_get_conntrack(struct cache *c, void *data) { return data - c->extra_offset; @@ -427,7 +395,6 @@ void cache_stats(struct cache *c, int fd) char buf[512]; int size; - lock(); size = sprintf(buf, "cache %s:\n" "current active connections:\t%12u\n" "connections created:\t\t%12u\tfailed:\t%12u\n" @@ -441,7 +408,6 @@ void cache_stats(struct cache *c, int fd) c->upd_fail, c->del_ok, c->del_fail); - unlock(); send(fd, buf, size, 0); } @@ -449,7 +415,5 @@ void cache_iterate(struct cache *c, void *data, int (*iterate)(void *data1, void *data2)) { - lock(); hashtable_iterate(c->h, data, iterate); - unlock(); } diff --git a/src/cache_iterators.c b/src/cache_iterators.c index 446cac8..1d1b2e8 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -71,37 +71,25 @@ void cache_dump(struct cache *c, int fd, int type) .type = type }; - /* does not require locking: called inside fork() */ hashtable_iterate(c->h, (void *) &tmp, do_dump); } +/* no need to clone, called from child process */ static int do_commit(void *data1, void *data2) { int ret; struct cache *c = data1; struct us_conntrack *u = data2; - struct nf_conntrack *ct; - char buf[4096]; - struct nlmsghdr *nlh = (struct nlmsghdr *)buf; - - ct = nfct_clone(u->ct); - if (ct == NULL) - return 0; + struct nf_conntrack *ct = u->ct; + /* XXX: related connections */ if (nfct_attr_is_set(ct, ATTR_STATUS)) { u_int32_t status = nfct_get_attr_u32(ct, ATTR_STATUS); status &= ~IPS_EXPECTED; nfct_set_attr_u32(ct, ATTR_STATUS, status); } - if (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) - nfct_setobjopt(ct, NFCT_SOPT_UNDO_SNAT); - if (nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) - nfct_setobjopt(ct, NFCT_SOPT_UNDO_DNAT); - if (nfct_getobjopt(ct, NFCT_GOPT_IS_SPAT)) - nfct_setobjopt(ct, NFCT_SOPT_UNDO_SPAT); - if (nfct_getobjopt(ct, NFCT_GOPT_IS_DPAT)) - nfct_setobjopt(ct, NFCT_SOPT_UNDO_DPAT); + nfct_setobjopt(ct, NFCT_SOPT_SETUP_REPLY); /* * Set a reduced timeout for candidate-to-be-committed @@ -109,20 +97,12 @@ static int do_commit(void *data1, void *data2) */ nfct_set_attr_u32(ct, ATTR_TIMEOUT, CONFIG(commit_timeout)); - ret = nfct_build_query(STATE(subsys_dump), - NFCT_Q_CREATE_UPDATE, - ct, - nlh, - sizeof(buf)); - - free(ct); - if (ret == -1) { dlog(STATE(log), "failed to build: %s", strerror(errno)); return 0; } - ret = nfnl_query(STATE(dump), nlh); + ret = nfct_query(STATE(dump), NFCT_Q_CREATE_UPDATE, ct); if (ret == -1) { switch(errno) { case EEXIST: @@ -146,7 +126,6 @@ void cache_commit(struct cache *c) unsigned int commit_exist = c->commit_exist; unsigned int commit_fail = c->commit_fail; - /* does not require locking: called inside fork() */ hashtable_iterate(c->h, c, do_commit); /* calculate new entries committed */ @@ -187,30 +166,7 @@ static int do_flush(void *data1, void *data2) void cache_flush(struct cache *c) { - lock(); hashtable_iterate(c->h, c, do_flush); hashtable_flush(c->h); c->flush++; - unlock(); -} - -#include "sync.h" -#include "network.h" - -static int do_bulk(void *data1, void *data2) -{ - int ret; - struct us_conntrack *u = data2; - - mcast_build_send_update(u); - - /* keep iterating even if we have found errors */ - return 0; -} - -void cache_bulk(struct cache *c) -{ - lock(); - hashtable_iterate(c->h, NULL, do_bulk); - unlock(); } diff --git a/src/cache_timer.c b/src/cache_timer.c index 213b59a..f3940f3 100644 --- a/src/cache_timer.c +++ b/src/cache_timer.c @@ -27,7 +27,7 @@ static void timeout(struct alarm_list *a, void *data) struct us_conntrack *u = data; debug_ct(u->ct, "expired timeout"); - __cache_del(u->cache, u->ct); + cache_del(u->cache, u->ct); } static void timer_add(struct us_conntrack *u, void *data) diff --git a/src/lock.c b/src/lock.c index cd68baf..e69de29 100644 --- a/src/lock.c +++ b/src/lock.c @@ -1,32 +0,0 @@ -/* - * (C) 2006 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include - -static pthread_mutex_t global_lock = PTHREAD_MUTEX_INITIALIZER; - -void lock() -{ - pthread_mutex_lock(&global_lock); -} - -void unlock() -{ - pthread_mutex_unlock(&global_lock); -} diff --git a/src/main.c b/src/main.c index a039793..007b76e 100644 --- a/src/main.c +++ b/src/main.c @@ -187,6 +187,7 @@ int main(int argc, char *argv[]) case 'F': set_operation_mode(&type, REQUEST, argv); action = FLUSH_MASTER; + break; case 'f': set_operation_mode(&type, REQUEST, argv); action = FLUSH_CACHE; diff --git a/src/mcast.c b/src/mcast.c index 85992fb..6193a59 100644 --- a/src/mcast.c +++ b/src/mcast.c @@ -87,7 +87,6 @@ struct mcast_sock *mcast_server_create(struct mcast_conf *conf) return NULL; } - switch(conf->ipproto) { case AF_INET: if (setsockopt(m->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, diff --git a/src/netlink.c b/src/netlink.c index 5f7cbeb..be5f82e 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -52,19 +52,10 @@ int ignore_conntrack(struct nf_conntrack *ct) return 0; } -static int nl_event_handler(struct nlmsghdr *nlh, - struct nfattr *nfa[], - void *data) +static int event_handler(enum nf_conntrack_msg_type type, + struct nf_conntrack *ct, + void *data) { - char tmp[1024]; - struct nf_conntrack *ct = (struct nf_conntrack *) tmp; - int type; - - memset(tmp, 0, sizeof(tmp)); - - if ((type = nfct_parse_conntrack(NFCT_T_ALL, nlh, ct)) == NFCT_T_ERROR) - return NFCT_CB_STOP; - /* * Ignore this conntrack: it talks about a * connection that is not interesting for us. @@ -74,13 +65,13 @@ static int nl_event_handler(struct nlmsghdr *nlh, switch(type) { case NFCT_T_NEW: - STATE(mode)->event_new(ct, nlh); + STATE(mode)->event_new(ct); break; case NFCT_T_UPDATE: - STATE(mode)->event_upd(ct, nlh); + STATE(mode)->event_upd(ct); break; case NFCT_T_DESTROY: - if (STATE(mode)->event_dst(ct, nlh)) + if (STATE(mode)->event_dst(ct)) update_traffic_stats(ct); break; default: @@ -88,30 +79,31 @@ static int nl_event_handler(struct nlmsghdr *nlh, break; } - return NFCT_CB_STOP; + return NFCT_CB_CONTINUE; } +#include +#include +#include + int nl_init_event_handler(void) { - struct nfnl_callback cb_events = { - .call = nl_event_handler, - .attr_count = CTA_MAX - }; - - /* open event netlink socket */ - STATE(event) = nfnl_open(); + STATE(event) = nfct_open(CONNTRACK, NFCT_ALL_CT_GROUPS); if (!STATE(event)) return -1; + fcntl(nfct_fd(STATE(event)), F_SETFL, O_NONBLOCK); + /* set up socket buffer size */ if (CONFIG(netlink_buffer_size)) - nfnl_rcvbufsiz(STATE(event), CONFIG(netlink_buffer_size)); + nfnl_rcvbufsiz(nfct_nfnlh(STATE(event)), + CONFIG(netlink_buffer_size)); else { socklen_t socklen = sizeof(unsigned int); unsigned int read_size; /* get current buffer size */ - getsockopt(nfnl_fd(STATE(event)), SOL_SOCKET, + getsockopt(nfct_fd(STATE(event)), SOL_SOCKET, SO_RCVBUF, &read_size, &socklen); CONFIG(netlink_buffer_size) = read_size; @@ -122,40 +114,16 @@ int nl_init_event_handler(void) CONFIG(netlink_buffer_size_max_grown) = CONFIG(netlink_buffer_size); - /* open event subsystem */ - STATE(subsys_event) = nfnl_subsys_open(STATE(event), - NFNL_SUBSYS_CTNETLINK, - IPCTNL_MSG_MAX, - NFCT_ALL_CT_GROUPS); - if (STATE(subsys_event) == NULL) - return -1; - - /* register callback for new and update events */ - nfnl_callback_register(STATE(subsys_event), - IPCTNL_MSG_CT_NEW, - &cb_events); - - /* register callback for delete events */ - nfnl_callback_register(STATE(subsys_event), - IPCTNL_MSG_CT_DELETE, - &cb_events); + /* register callback for events */ + nfct_callback_register(STATE(event), NFCT_T_ALL, event_handler, NULL); return 0; } -static int nl_dump_handler(struct nlmsghdr *nlh, - struct nfattr *nfa[], - void *data) +static int dump_handler(enum nf_conntrack_msg_type type, + struct nf_conntrack *ct, + void *data) { - char buf[1024]; - struct nf_conntrack *ct = (struct nf_conntrack *) buf; - int type; - - memset(buf, 0, sizeof(buf)); - - if ((type = nfct_parse_conntrack(NFCT_T_ALL, nlh, ct)) == NFCT_T_ERROR) - return NFCT_CB_CONTINUE; - /* * Ignore this conntrack: it talks about a * connection that is not interesting for us. @@ -165,7 +133,7 @@ static int nl_dump_handler(struct nlmsghdr *nlh, switch(type) { case NFCT_T_UPDATE: - STATE(mode)->dump(ct, nlh); + STATE(mode)->dump(ct); break; default: dlog(STATE(log), "received unknown msg from ctnetlink"); @@ -176,30 +144,15 @@ static int nl_dump_handler(struct nlmsghdr *nlh, int nl_init_dump_handler(void) { - struct nfnl_callback cb_dump = { - .call = nl_dump_handler, - .attr_count = CTA_MAX - }; - /* open dump netlink socket */ - STATE(dump) = nfnl_open(); + STATE(dump) = nfct_open(CONNTRACK, 0); if (!STATE(dump)) return -1; - /* open dump subsystem */ - STATE(subsys_dump) = nfnl_subsys_open(STATE(dump), - NFNL_SUBSYS_CTNETLINK, - IPCTNL_MSG_MAX, - 0); - if (STATE(subsys_dump) == NULL) - return -1; - /* register callback for dumped entries */ - nfnl_callback_register(STATE(subsys_dump), - IPCTNL_MSG_CT_NEW, - &cb_dump); + nfct_callback_register(STATE(dump), NFCT_T_ALL, dump_handler, NULL); - if (nl_dump_conntrack_table(STATE(dump), STATE(subsys_dump)) == -1) + if (nl_dump_conntrack_table() == -1) return -1; return 0; @@ -207,7 +160,7 @@ int nl_init_dump_handler(void) static int warned = 0; -void nl_resize_socket_buffer(struct nfnl_handle *h) +void nl_resize_socket_buffer(struct nfct_handle *h) { unsigned int s = CONFIG(netlink_buffer_size) * 2; @@ -228,44 +181,14 @@ void nl_resize_socket_buffer(struct nfnl_handle *h) warned = 1; } - CONFIG(netlink_buffer_size) = nfnl_rcvbufsiz(h, s); + CONFIG(netlink_buffer_size) = nfnl_rcvbufsiz(nfct_nfnlh(h), s); /* notify the sysadmin */ dlog(STATE(log), "netlink socket buffer size has been set to %u bytes", CONFIG(netlink_buffer_size)); } -int nl_dump_conntrack_table(struct nfnl_handle *h, - struct nfnl_subsys_handle *subsys) +int nl_dump_conntrack_table(void) { - struct nfnlhdr req; - - memset(&req, 0, sizeof(req)); - nfct_build_query(subsys, - NFCT_Q_DUMP, - &CONFIG(family), - &req, - sizeof(req)); - - if (nfnl_query(h, &req.nlh) == -1) - return -1; - - return 0; -} - -int nl_flush_master_conntrack_table(void) -{ - struct nfnlhdr req; - - memset(&req, 0, sizeof(req)); - nfct_build_query(STATE(subsys_dump), - NFCT_Q_FLUSH, - &CONFIG(family), - &req, - sizeof(req)); - - if (nfnl_query(STATE(dump), &req.nlh) == -1) - return -1; - - return 0; + return nfct_query(STATE(dump), NFCT_Q_DUMP, &CONFIG(family)); } diff --git a/src/network.c b/src/network.c index 159bdf3..d162839 100644 --- a/src/network.c +++ b/src/network.c @@ -18,190 +18,159 @@ #include "conntrackd.h" #include "network.h" +#include "us-conntrack.h" +#include "sync.h" static unsigned int seq_set, cur_seq; -static int send_netmsg(struct mcast_sock *m, void *data, unsigned int len) +static int __do_send(struct mcast_sock *m, void *data, int len) { struct nethdr *net = data; - if (!seq_set) { - seq_set = 1; - cur_seq = time(NULL); - net->flags |= NET_F_HELLO; - } - - net->flags = htons(net->flags); - net->seq = htonl(cur_seq++); - #undef _TEST_DROP #ifdef _TEST_DROP static int drop = 0; - if (++drop > 10) { + if (++drop >= 10) { + printf("drop sq: %u fl:%u len:%u\n", + ntohl(net->seq), ntohs(net->flags), + ntohs(net->len)); drop = 0; - printf("dropping resend (seq=%u)\n", ntohl(net->seq)); return 0; } #endif + debug("send sq: %u fl:%u len:%u\n", + ntohl(net->seq), ntohs(net->flags), + ntohs(net->len)); + return mcast_send(m, net, len); } -int mcast_send_netmsg(struct mcast_sock *m, void *data) +static int __do_prepare(struct mcast_sock *m, void *data, int len) { - struct nlmsghdr *nlh = data + NETHDR_SIZ; - unsigned int len = nlh->nlmsg_len + NETHDR_SIZ; struct nethdr *net = data; - if (nlh_host2network(nlh) == -1) - return -1; + if (!seq_set) { + seq_set = 1; + cur_seq = time(NULL); + net->flags |= NET_F_HELLO; + } + net->len = len; + net->seq = cur_seq++; + HDR_HOST2NETWORK(net); - return send_netmsg(m, data, len); + return len; } -int mcast_resend_netmsg(struct mcast_sock *m, void *data) +static int __prepare_ctl(struct mcast_sock *m, void *data) { - struct nethdr *net = data; - struct nlmsghdr *nlh = data + NETHDR_SIZ; - unsigned int len; + struct nethdr_ack *nack = (struct nethdr_ack *) data; - net->flags = ntohs(net->flags); + return __do_prepare(m, data, NETHDR_ACK_SIZ); +} - if (net->flags & NET_F_NACK || net->flags & NET_F_ACK) - len = NETHDR_ACK_SIZ; - else - len = ntohl(nlh->nlmsg_len) + NETHDR_SIZ; +static int __prepare_data(struct mcast_sock *m, void *data) +{ + struct nethdr *net = (struct nethdr *) data; + struct netpld *pld = NETHDR_DATA(net); - return send_netmsg(m, data, len); + return __do_prepare(m, data, ntohs(pld->len) + NETPLD_SIZ + NETHDR_SIZ); } -int mcast_send_error(struct mcast_sock *m, void *data) +int prepare_send_netmsg(struct mcast_sock *m, void *data) { - struct nethdr *net = data; - unsigned int len = NETHDR_SIZ; + int ret = 0; + struct nethdr *net = (struct nethdr *) data; - if (net->flags & NET_F_NACK || net->flags & NET_F_ACK) { - struct nethdr_ack *nack = (struct nethdr_ack *) net; - nack->from = htonl(nack->from); - nack->to = htonl(nack->to); - len = NETHDR_ACK_SIZ; - } + if (IS_DATA(net)) + ret = __prepare_data(m, data); + else if (IS_CTL(net)) + ret = __prepare_ctl(m, data); - return send_netmsg(m, data, len); + return ret; } -#include "us-conntrack.h" -#include "sync.h" +static int tx_buflen = 0; +/* XXX: use buffer size of interface MTU */ +static char __tx_buf[1460], *tx_buf = __tx_buf; -static int __build_send(struct us_conntrack *u, int type, int query) +/* return 0 if it is not sent, otherwise return 1 */ +int mcast_buffered_send_netmsg(struct mcast_sock *m, void *data, int len) { - char __net[4096]; - struct nethdr *net = (struct nethdr *) __net; + int ret = 0; + struct nethdr *net = data; - if (!state_helper_verdict(type, u->ct)) - return 0; +retry: + if (tx_buflen + len < sizeof(__tx_buf)) { + memcpy(__tx_buf + tx_buflen, net, len); + tx_buflen += len; + } else { + __do_send(m, tx_buf, tx_buflen); + ret = 1; + tx_buflen = 0; + goto retry; + } - int ret = build_network_msg(query, - STATE(subsys_event), - u->ct, - __net, - sizeof(__net)); + return ret; +} - if (ret == -1) - return -1; +int mcast_buffered_pending_netmsg(struct mcast_sock *m) +{ + int ret; + + if (tx_buflen == 0) + return 0; - mcast_send_netmsg(STATE_SYNC(mcast_client), __net); - if (STATE_SYNC(sync)->send) - STATE_SYNC(sync)->send(type, net, u); + ret = __do_send(m, tx_buf, tx_buflen); + tx_buflen = 0; - return 0; + return ret; } -int mcast_build_send_update(struct us_conntrack *u) +int mcast_send_netmsg(struct mcast_sock *m, void *data) { - return __build_send(u, NFCT_T_UPDATE, NFCT_Q_UPDATE); + int ret; + int len = prepare_send_netmsg(m, data); + + ret = mcast_buffered_send_netmsg(m, data, len); + mcast_buffered_pending_netmsg(m); + + return ret; } -int mcast_build_send_destroy(struct us_conntrack *u) +void build_netmsg(struct nf_conntrack *ct, int query, struct nethdr *net) { - return __build_send(u, NFCT_T_DESTROY, NFCT_Q_DESTROY); + struct netpld *pld = NETHDR_DATA(net); + + build_netpld(ct, pld, query); } -int mcast_recv_netmsg(struct mcast_sock *m, void *data, int len) +int handle_netmsg(struct nethdr *net) { int ret; - struct nethdr *net = data; - struct nlmsghdr *nlh = data + NETHDR_SIZ; - struct nfgenmsg *nfhdr; - - ret = mcast_recv(m, net, len); - if (ret <= 0) - return ret; + struct netpld *pld = NETHDR_DATA(net); /* message too small: no room for the header */ - if (ret < NETHDR_SIZ) + if (ntohs(net->len) < NETHDR_ACK_SIZ) return -1; - if (ntohs(net->flags) & NET_F_HELLO) - STATE_SYNC(last_seq_recv) = ntohl(net->seq) - 1; + HDR_NETWORK2HOST(net); - if (ntohs(net->flags) & NET_F_NACK || ntohs(net->flags) & NET_F_ACK) { - struct nethdr_ack *nack = (struct nethdr_ack *) net; + if (IS_HELLO(net)) + STATE_SYNC(last_seq_recv) = net->seq - 1; - /* message too small: no room for the header */ - if (ret < NETHDR_ACK_SIZ) - return -1; - - /* host byte order conversion */ - net->flags = ntohs(net->flags); - net->seq = ntohl(net->seq); - - /* acknowledgement conversion */ - nack->from = ntohl(nack->from); - nack->to = ntohl(nack->to); - - return ret; - } - - if (ntohs(net->flags) & NET_F_RESYNC) { - /* host byte order conversion */ - net->flags = ntohs(net->flags); - net->seq = ntohl(net->seq); - - return ret; - } + if (IS_CTL(net)) + return 0; /* information received is too small */ - if (ret < NLMSG_SPACE(sizeof(struct nfgenmsg))) - return -1; - - /* information received and message length does not match */ - if (ret != ntohl(nlh->nlmsg_len) + NETHDR_SIZ) - return -1; - - /* this message does not come from ctnetlink */ - if (NFNL_SUBSYS_ID(ntohs(nlh->nlmsg_type)) != NFNL_SUBSYS_CTNETLINK) + if (net->len < sizeof(struct netpld)) return -1; - nfhdr = NLMSG_DATA(nlh); - - /* only AF_INET and AF_INET6 are supported */ - if (nfhdr->nfgen_family != AF_INET && - nfhdr->nfgen_family != AF_INET6) - return -1; - - /* only process message coming from nfnetlink v0 */ - if (nfhdr->version != NFNETLINK_V0) - return -1; - - /* host byte order conversion */ - net->flags = ntohs(net->flags); - net->seq = ntohl(net->seq); - - if (nlh_network2host(nlh) == -1) + /* size mismatch! */ + if (net->len < ntohs(pld->len) + NETHDR_SIZ) return -1; - return ret; + return 0; } int mcast_track_seq(u_int32_t seq, u_int32_t *exp_seq) @@ -238,30 +207,3 @@ out: return ret; } - -int build_network_msg(const int msg_type, - struct nfnl_subsys_handle *ssh, - struct nf_conntrack *ct, - void *buffer, - unsigned int size) -{ - memset(buffer, 0, size); - buffer += NETHDR_SIZ; - size -= NETHDR_SIZ; - return nfct_build_query(ssh, msg_type, ct, buffer, size); -} - -unsigned int parse_network_msg(struct nf_conntrack *ct, - const struct nlmsghdr *nlh) -{ - /* - * The parsing of netlink messages going through network is - * similar to the one that is done for messages coming from - * kernel, therefore do not replicate more code and use the - * function provided in the libraries. - * - * Yup, this is a hack 8) - */ - return nfct_parse_conntrack(NFCT_T_ALL, nlh, ct); -} - diff --git a/src/parse.c b/src/parse.c new file mode 100644 index 0000000..81b70c4 --- /dev/null +++ b/src/parse.c @@ -0,0 +1,76 @@ +/* + * (C) 2006-2007 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include "network.h" + +static int parse_u8(struct nf_conntrack *ct, int attr, void *data) +{ + u_int8_t *value = (u_int8_t *) data; + nfct_set_attr_u8(ct, attr, *value); +} + +static int parse_u16(struct nf_conntrack *ct, int attr, void *data) +{ + u_int16_t *value = (u_int16_t *) data; + nfct_set_attr_u16(ct, attr, ntohs(*value)); +} + +static int parse_u32(struct nf_conntrack *ct, int attr, void *data) +{ + u_int32_t *value = (u_int32_t *) data; + nfct_set_attr_u32(ct, attr, ntohl(*value)); +} + +typedef int (*parse)(struct nf_conntrack *ct, int attr, void *data); + +parse h[ATTR_MAX] = { + [ATTR_IPV4_SRC] = parse_u32, + [ATTR_IPV4_DST] = parse_u32, + [ATTR_L3PROTO] = parse_u8, + [ATTR_PORT_SRC] = parse_u16, + [ATTR_PORT_DST] = parse_u16, + [ATTR_L4PROTO] = parse_u8, + [ATTR_TCP_STATE] = parse_u8, + [ATTR_SNAT_IPV4] = parse_u32, + [ATTR_DNAT_IPV4] = parse_u32, + [ATTR_SNAT_PORT] = parse_u16, + [ATTR_DNAT_PORT] = parse_u16, + [ATTR_TIMEOUT] = parse_u32, + [ATTR_MARK] = parse_u32, + [ATTR_STATUS] = parse_u32, +}; + +void parse_netpld(struct nf_conntrack *ct, struct netpld *pld, int *query) +{ + int len; + struct netattr *attr; + + PLD_NETWORK2HOST(pld); + len = pld->len; + attr = PLD_DATA(pld); + + while (len > 0) { + ATTR_NETWORK2HOST(attr); + h[attr->nta_attr](ct, attr->nta_attr, NTA_DATA(attr)); + attr = NTA_NEXT(attr, len); + } + + *query = pld->query; +} diff --git a/src/proxy.c b/src/proxy.c deleted file mode 100644 index b9bb04e..0000000 --- a/src/proxy.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * (C) 2006 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include - -#if 0 -#define dprintf printf -#else -#define dprintf -#endif - -int nlh_payload_host2network(struct nfattr *nfa, int len) -{ - struct nfattr *__nfa; - - while (NFA_OK(nfa, len)) { - - dprintf("type=%d nfalen=%d len=%d [%s]\n", - nfa->nfa_type & 0x7fff, - nfa->nfa_len, len, - nfa->nfa_type & NFNL_NFA_NEST ? "NEST":""); - - if (nfa->nfa_type & NFNL_NFA_NEST) { - if (NFA_PAYLOAD(nfa) > len) - return -1; - - if (nlh_payload_host2network(NFA_DATA(nfa), - NFA_PAYLOAD(nfa)) == -1) - return -1; - } - - __nfa = NFA_NEXT(nfa, len); - - nfa->nfa_type = htons(nfa->nfa_type); - nfa->nfa_len = htons(nfa->nfa_len); - - nfa = __nfa; - } - return 0; -} - -int nlh_host2network(struct nlmsghdr *nlh) -{ - struct nfgenmsg *nfhdr = NLMSG_DATA(nlh); - struct nfattr *cda[CTA_MAX]; - unsigned int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg)); - unsigned int len = nlh->nlmsg_len - NLMSG_ALIGN(min_len); - - nlh->nlmsg_len = htonl(nlh->nlmsg_len); - nlh->nlmsg_type = htons(nlh->nlmsg_type); - nlh->nlmsg_flags = htons(nlh->nlmsg_flags); - nlh->nlmsg_seq = htonl(nlh->nlmsg_seq); - nlh->nlmsg_pid = htonl(nlh->nlmsg_pid); - - nfhdr->res_id = htons(nfhdr->res_id); - - return nlh_payload_host2network(NFM_NFA(NLMSG_DATA(nlh)), len); -} - -int nlh_payload_network2host(struct nfattr *nfa, int len) -{ - nfa->nfa_type = ntohs(nfa->nfa_type); - nfa->nfa_len = ntohs(nfa->nfa_len); - - while(NFA_OK(nfa, len)) { - - dprintf("type=%d nfalen=%d len=%d [%s]\n", - nfa->nfa_type & 0x7fff, - nfa->nfa_len, len, - nfa->nfa_type & NFNL_NFA_NEST ? "NEST":""); - - if (nfa->nfa_type & NFNL_NFA_NEST) { - if (NFA_PAYLOAD(nfa) > len) - return -1; - - if (nlh_payload_network2host(NFA_DATA(nfa), - NFA_PAYLOAD(nfa)) == -1) - return -1; - } - - nfa = NFA_NEXT(nfa,len); - - if (len < NFA_LENGTH(0)) - break; - - nfa->nfa_type = ntohs(nfa->nfa_type); - nfa->nfa_len = ntohs(nfa->nfa_len); - } - return 0; -} - -int nlh_network2host(struct nlmsghdr *nlh) -{ - struct nfgenmsg *nfhdr = NLMSG_DATA(nlh); - struct nfattr *cda[CTA_MAX]; - unsigned int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg)); - unsigned int len = ntohl(nlh->nlmsg_len) - NLMSG_ALIGN(min_len); - - nlh->nlmsg_len = ntohl(nlh->nlmsg_len); - nlh->nlmsg_type = ntohs(nlh->nlmsg_type); - nlh->nlmsg_flags = ntohs(nlh->nlmsg_flags); - nlh->nlmsg_seq = ntohl(nlh->nlmsg_seq); - nlh->nlmsg_pid = ntohl(nlh->nlmsg_pid); - - nfhdr->res_id = ntohs(nfhdr->res_id); - - return nlh_payload_network2host(NFM_NFA(NLMSG_DATA(nlh)), len); -} diff --git a/src/run.c b/src/run.c index 0173c9f..644f82e 100644 --- a/src/run.c +++ b/src/run.c @@ -24,20 +24,21 @@ #include "us-conntrack.h" #include #include +#include +#include "timer.h" void killer(int foo) { /* no signals while handling signals */ sigprocmask(SIG_BLOCK, &STATE(block), NULL); - nfnl_subsys_close(STATE(subsys_event)); - nfnl_subsys_close(STATE(subsys_dump)); - nfnl_close(STATE(event)); - nfnl_close(STATE(dump)); + nfct_close(STATE(event)); + nfct_close(STATE(dump)); ignore_pool_destroy(STATE(ignore_pool)); local_server_destroy(STATE(local)); STATE(mode)->kill(); + destroy_alarm_scheduler(); unlink(CONFIG(lockfile)); dlog(STATE(log), "------- shutdown received ----"); close_log(STATE(log)); @@ -69,12 +70,16 @@ void local_handler(int fd, void *data) switch(type) { case FLUSH_MASTER: - dlog(STATE(log), "[REQ] flushing master table"); - nl_flush_master_conntrack_table(); + dlog(STATE(log), "[DEPRECATED] `conntrackd -F' is deprecated. " + "Use conntrack -F instead."); + if (fork() == 0) { + execlp("conntrack", "conntrack", "-F", NULL); + exit(EXIT_SUCCESS); + } return; case RESYNC_MASTER: dlog(STATE(log), "[REQ] resync with master table"); - nl_dump_conntrack_table(STATE(dump), STATE(subsys_dump)); + nl_dump_conntrack_table(); return; } @@ -104,6 +109,11 @@ int init(int mode) return -1; } + if (init_alarm_scheduler() == -1) { + dlog(STATE(log), "[FAIL] can't initialize alarm scheduler"); + return -1; + } + /* local UNIX socket */ STATE(local) = local_server_create(&CONFIG(local)); if (!STATE(local)) { @@ -147,22 +157,20 @@ int init(int mode) return 0; } -#define POLL_NSECS 1 - -static void __run(void) +static void __run(long credit, int step) { int max, ret; fd_set readfds; struct timeval tv = { - .tv_sec = POLL_NSECS, - .tv_usec = 0 + .tv_sec = 0, + .tv_usec = credit, }; FD_ZERO(&readfds); FD_SET(STATE(local), &readfds); - FD_SET(nfnl_fd(STATE(event)), &readfds); + FD_SET(nfct_fd(STATE(event)), &readfds); - max = MAX(STATE(local), nfnl_fd(STATE(event))); + max = MAX(STATE(local), nfct_fd(STATE(event))); if (STATE(mode)->add_fds_to_set) max = MAX(max, STATE(mode)->add_fds_to_set(&readfds)); @@ -185,8 +193,8 @@ static void __run(void) do_local_server_step(STATE(local), NULL, local_handler); /* conntrack event has happened */ - if (FD_ISSET(nfnl_fd(STATE(event)), &readfds)) { - ret = nfnl_catch(STATE(event)); + if (FD_ISSET(nfct_fd(STATE(event)), &readfds)) { + while ((ret = nfct_catch(STATE(event))) != -1); if (ret == -1) { switch(errno) { case ENOBUFS: @@ -197,6 +205,7 @@ static void __run(void) * size and resync with master conntrack table. */ nl_resize_socket_buffer(STATE(event)); + /* XXX: schedule overrun call via alarm */ STATE(mode)->overrun(); break; case ENOENT: @@ -206,6 +215,8 @@ static void __run(void) * interested in. Just ignore it. */ break; + case EAGAIN: + break; default: dlog(STATE(log), "event catch says: %s", strerror(errno)); @@ -214,14 +225,35 @@ static void __run(void) } } - if (STATE(mode)->step) - STATE(mode)->step(&readfds); + if (STATE(mode)->run) + STATE(mode)->run(&readfds, step); sigprocmask(SIG_UNBLOCK, &STATE(block), NULL); } void run(void) { - while(1) - __run(); + int step = 0; + struct timer timer; + + timer_init(&timer); + + while(1) { + timer_start(&timer); + __run(GET_CREDITS(timer), step); + timer_stop(&timer); + + if (timer_adjust_credit(&timer)) { + timer_start(&timer); + sigprocmask(SIG_BLOCK, &STATE(block), NULL); + do_alarm_run(step); + sigprocmask(SIG_UNBLOCK, &STATE(block), NULL); + timer_stop(&timer); + + if (timer_adjust_credit(&timer)) + dlog(STATE(log), "alarm run takes too long!"); + + step = (step + 1) < STEPS_PER_SECONDS ? step + 1 : 0; + } + } } diff --git a/src/state_helper.c b/src/state_helper.c index 81b0d09..eba9d8f 100644 --- a/src/state_helper.c +++ b/src/state_helper.c @@ -25,7 +25,7 @@ int state_helper_verdict(int type, struct nf_conntrack *ct) { u_int8_t l4proto; - if (type == NFCT_T_DESTROY) + if (type == NFCT_Q_DESTROY) return ST_H_REPLICATE; l4proto = nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO); diff --git a/src/stats-mode.c b/src/stats-mode.c index 92794cd..65bab1b 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -86,7 +86,7 @@ static int local_handler_stats(int fd, int type, void *data) return ret; } -static void dump_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh) +static void dump_stats(struct nf_conntrack *ct) { if (cache_update_force(STATE_STATS(cache), ct)) debug_ct(ct, "resync entry"); @@ -137,7 +137,7 @@ static void overrun_stats() nfct_close(h); } -static void event_new_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh) +static void event_new_stats(struct nf_conntrack *ct) { if (cache_add(STATE_STATS(cache), ct)) { debug_ct(ct, "cache new"); @@ -150,7 +150,7 @@ static void event_new_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh) } } -static void event_update_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh) +static void event_update_stats(struct nf_conntrack *ct) { if (!cache_update_force(STATE_STATS(cache), ct)) { debug_ct(ct, "can't update"); @@ -159,7 +159,7 @@ static void event_update_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh) debug_ct(ct, "update"); } -static int event_destroy_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh) +static int event_destroy_stats(struct nf_conntrack *ct) { if (cache_del(STATE_STATS(cache), ct)) { debug_ct(ct, "cache destroy"); @@ -173,7 +173,7 @@ static int event_destroy_stats(struct nf_conntrack *ct, struct nlmsghdr *nlh) struct ct_mode stats_mode = { .init = init_stats, .add_fds_to_set = NULL, - .step = NULL, + .run = NULL, .local = local_handler_stats, .kill = kill_stats, .dump = dump_stats, diff --git a/src/sync-mode.c b/src/sync-mode.c index 38ab016..f30cb95 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -27,43 +27,27 @@ #include #include "sync.h" #include "network.h" +#include "buffer.h" +#include "debug.h" -/* handler for multicast messages received */ -static void mcast_handler() +static void do_mcast_handler_step(struct nethdr *net) { - int ret; - unsigned int type; - char __net[4096]; - struct nethdr *net = (struct nethdr *) __net; - struct nlmsghdr *nlh = (struct nlmsghdr *) (__net + NETHDR_SIZ); + unsigned int query; + struct netpld *pld = NETHDR_DATA(net); char __ct[nfct_maxsize()]; struct nf_conntrack *ct = (struct nf_conntrack *) __ct; struct us_conntrack *u = NULL; - ret = mcast_recv_netmsg(STATE_SYNC(mcast_server), net, sizeof(__net)); - if (ret <= 0) { - STATE(malformed)++; - return; - } - if (STATE_SYNC(sync)->recv(net)) return; memset(ct, 0, sizeof(__ct)); - if ((type = parse_network_msg(ct, nlh)) == NFCT_T_ERROR) { - STATE(malformed)++; - return; - } + /* XXX: check for malformed */ + parse_netpld(ct, pld, &query); - nfct_attr_unset(ct, ATTR_TIMEOUT); - nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES); - nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS); - nfct_attr_unset(ct, ATTR_REPL_COUNTER_BYTES); - nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); - - switch(type) { - case NFCT_T_NEW: + switch(query) { + case NFCT_Q_CREATE: retry: if ((u = cache_add(STATE_SYNC(external), ct))) { debug_ct(u->ct, "external new"); @@ -80,24 +64,57 @@ retry: debug_ct(ct, "can't add"); } break; - case NFCT_T_UPDATE: + case NFCT_Q_UPDATE: if ((u = cache_update_force(STATE_SYNC(external), ct))) { debug_ct(u->ct, "external update"); } else debug_ct(ct, "can't update"); break; - case NFCT_T_DESTROY: + case NFCT_Q_DESTROY: if (cache_del(STATE_SYNC(external), ct)) debug_ct(ct, "external destroy"); else debug_ct(ct, "can't destroy"); break; default: - dlog(STATE(log), "mcast received unknown msg type %d\n", type); + dlog(STATE(log), "mcast received unknown query %d\n", query); break; } } +/* handler for multicast messages received */ +static void mcast_handler() +{ + int numbytes, remain; + char __net[4096], *ptr = __net; + + numbytes = mcast_recv(STATE_SYNC(mcast_server), __net, sizeof(__net)); + if (numbytes <= 0) + return; + + remain = numbytes; + while (remain > 0) { + struct nethdr *net = (struct nethdr *) ptr; + + if (ntohs(net->len) > remain) { + dlog(STATE(log), "fragmented messages"); + break; + } + + debug("recv sq: %u fl:%u len:%u (rem:%d)\n", + ntohl(net->seq), ntohs(net->flags), + ntohs(net->len), remain); + + if (handle_netmsg(net) == -1) { + STATE(malformed)++; + return; + } + do_mcast_handler_step(net); + ptr += net->len; + remain -= net->len; + } +} + static int init_sync(void) { int ret; @@ -159,11 +176,6 @@ static int init_sync(void) /* initialization of multicast sequence generation */ STATE_SYNC(last_seq_sent) = time(NULL); - if (create_alarm_thread() == -1) { - dlog(STATE(log), "[FAIL] can't initialize alarm thread"); - return -1; - } - return 0; } @@ -174,11 +186,17 @@ static int add_fds_to_set_sync(fd_set *readfds) return STATE_SYNC(mcast_server->fd); } -static void step_sync(fd_set *readfds) +static void run_sync(fd_set *readfds, int step) { /* multicast packet has been received */ if (FD_ISSET(STATE_SYNC(mcast_server->fd), readfds)) mcast_handler(); + + if (STATE_SYNC(sync)->run) + STATE_SYNC(sync)->run(step); + + /* flush pending messages */ + mcast_buffered_pending_netmsg(STATE_SYNC(mcast_client)); } static void kill_sync() @@ -189,8 +207,6 @@ static void kill_sync() mcast_server_destroy(STATE_SYNC(mcast_server)); mcast_client_destroy(STATE_SYNC(mcast_client)); - destroy_alarm_thread(); - if (STATE_SYNC(sync)->kill) STATE_SYNC(sync)->kill(); } @@ -267,10 +283,6 @@ static int local_handler_sync(int fd, int type, void *data) STATE_SYNC(mcast_server)); dump_stats_sync(fd); break; - case SEND_BULK: - dlog(STATE(log), "[REQ] sending bulk update"); - cache_bulk(STATE_SYNC(internal)); - break; default: if (STATE_SYNC(sync)->local) ret = STATE_SYNC(sync)->local(fd, type, data); @@ -280,7 +292,7 @@ static int local_handler_sync(int fd, int type, void *data) return ret; } -static void dump_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) +static void dump_sync(struct nf_conntrack *ct) { /* This is required by kernels < 2.6.20 */ nfct_attr_unset(ct, ATTR_TIMEOUT); @@ -294,23 +306,21 @@ static void dump_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) debug_ct(ct, "resync"); } -static void mcast_send_sync(struct nlmsghdr *nlh, - struct us_conntrack *u, +static void mcast_send_sync(struct us_conntrack *u, struct nf_conntrack *ct, - int type) + int query) { - char __net[4096]; - struct nethdr *net = (struct nethdr *) __net; - - memset(__net, 0, sizeof(__net)); + int len; + struct nethdr *net; - if (!state_helper_verdict(type, ct)) + if (!state_helper_verdict(query, ct)) return; - memcpy(__net + NETHDR_SIZ, nlh, nlh->nlmsg_len); - mcast_send_netmsg(STATE_SYNC(mcast_client), net); + net = BUILD_NETMSG(ct, query); + len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); + mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); if (STATE_SYNC(sync)->send) - STATE_SYNC(sync)->send(type, net, u); + STATE_SYNC(sync)->send(net, u); } static int overrun_cb(enum nf_conntrack_msg_type type, @@ -332,8 +342,16 @@ static int overrun_cb(enum nf_conntrack_msg_type type, if (!cache_test(STATE_SYNC(internal), ct)) { if ((u = cache_update_force(STATE_SYNC(internal), ct))) { + int len; + debug_ct(u->ct, "overrun resync"); - mcast_build_send_update(u); + + struct nethdr *net = BUILD_NETMSG(u->ct, NFCT_Q_UPDATE); + len = prepare_send_netmsg(STATE_SYNC(mcast_client),net); + mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), + net, len); + if (STATE_SYNC(sync)->send) + STATE_SYNC(sync)->send(net, u); } } @@ -348,9 +366,17 @@ static int overrun_purge_step(void *data1, void *data2) ret = nfct_query(h, NFCT_Q_GET, u->ct); if (ret == -1 && errno == ENOENT) { + int len; + struct nethdr *net = BUILD_NETMSG(u->ct, NFCT_Q_DESTROY); + debug_ct(u->ct, "overrun purge resync"); - mcast_build_send_destroy(u); - __cache_del(STATE_SYNC(internal), u->ct); + + len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); + mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); + if (STATE_SYNC(sync)->send) + STATE_SYNC(sync)->send(net, u); + + cache_del(STATE_SYNC(internal), u->ct); } return 0; @@ -382,7 +408,7 @@ static void overrun_sync() nfct_close(h); } -static void event_new_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) +static void event_new_sync(struct nf_conntrack *ct) { struct us_conntrack *u; @@ -394,12 +420,12 @@ static void event_new_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) nfct_attr_unset(ct, ATTR_TIMEOUT); retry: if ((u = cache_add(STATE_SYNC(internal), ct))) { - mcast_send_sync(nlh, u, ct, NFCT_T_NEW); + mcast_send_sync(u, ct, NFCT_Q_CREATE); debug_ct(u->ct, "internal new"); } else { if (errno == EEXIST) { cache_del(STATE_SYNC(internal), ct); - mcast_send_sync(nlh, NULL, ct, NFCT_T_DESTROY); + mcast_send_sync(NULL, ct, NFCT_Q_DESTROY); goto retry; } @@ -409,7 +435,7 @@ retry: } } -static void event_update_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) +static void event_update_sync(struct nf_conntrack *ct) { struct us_conntrack *u; @@ -420,15 +446,15 @@ static void event_update_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) return; } debug_ct(u->ct, "internal update"); - mcast_send_sync(nlh, u, ct, NFCT_T_UPDATE); + mcast_send_sync(u, ct, NFCT_Q_UPDATE); } -static int event_destroy_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) +static int event_destroy_sync(struct nf_conntrack *ct) { nfct_attr_unset(ct, ATTR_TIMEOUT); if (cache_del(STATE_SYNC(internal), ct)) { - mcast_send_sync(nlh, NULL, ct, NFCT_T_DESTROY); + mcast_send_sync(NULL, ct, NFCT_Q_DESTROY); debug_ct(ct, "internal destroy"); } else debug_ct(ct, "can't destroy"); @@ -437,7 +463,7 @@ static int event_destroy_sync(struct nf_conntrack *ct, struct nlmsghdr *nlh) struct ct_mode sync_mode = { .init = init_sync, .add_fds_to_set = add_fds_to_set_sync, - .step = step_sync, + .run = run_sync, .local = local_handler_sync, .kill = kill_sync, .dump = dump_sync, diff --git a/src/sync-nack.c b/src/sync-nack.c index 20ad1f4..dbda0a7 100644 --- a/src/sync-nack.c +++ b/src/sync-nack.c @@ -24,6 +24,7 @@ #include "buffer.h" #include "debug.h" #include "network.h" +#include "alarm.h" #include #include @@ -33,28 +34,34 @@ #define dp #endif -static LIST_HEAD(queue); +static LIST_HEAD(rs_list); +static LIST_HEAD(tx_list); +static unsigned int tx_list_len; +static struct buffer *rs_queue; +static struct buffer *tx_queue; struct cache_nack { - struct list_head head; + struct list_head rs_list; + struct list_head tx_list; u_int32_t seq; }; static void cache_nack_add(struct us_conntrack *u, void *data) { struct cache_nack *cn = data; - INIT_LIST_HEAD(&cn->head); + INIT_LIST_HEAD(&cn->rs_list); + INIT_LIST_HEAD(&cn->tx_list); } static void cache_nack_del(struct us_conntrack *u, void *data) { struct cache_nack *cn = data; - if (cn->head.next == &cn->head && - cn->head.prev == &cn->head) + if (cn->rs_list.next == &cn->rs_list && + cn->rs_list.prev == &cn->rs_list) return; - list_del(&cn->head); + list_del(&cn->rs_list); } static struct cache_extra cache_nack_extra = { @@ -65,19 +72,31 @@ static struct cache_extra cache_nack_extra = { static int nack_init() { - STATE_SYNC(buffer) = buffer_create(CONFIG(resend_buffer_size)); - if (STATE_SYNC(buffer) == NULL) + tx_queue = buffer_create(CONFIG(resend_buffer_size)); + if (tx_queue == NULL) { + dlog(STATE(log), "[FAIL] cannot create tx buffer"); return -1; + } + + rs_queue = buffer_create(CONFIG(resend_buffer_size)); + if (rs_queue == NULL) { + dlog(STATE(log), "[FAIL] cannot create rs buffer"); + return -1; + } + + INIT_LIST_HEAD(&tx_list); + INIT_LIST_HEAD(&rs_list); return 0; } static void nack_kill() { - buffer_destroy(STATE_SYNC(buffer)); + buffer_destroy(rs_queue); + buffer_destroy(tx_queue); } -static void mcast_send_control(u_int32_t flags, u_int32_t from, u_int32_t to) +static void tx_queue_add_ctlmsg(u_int32_t flags, u_int32_t from, u_int32_t to) { struct nethdr_ack ack = { .flags = flags, @@ -85,8 +104,19 @@ static void mcast_send_control(u_int32_t flags, u_int32_t from, u_int32_t to) .to = to, }; - mcast_send_error(STATE_SYNC(mcast_client), &ack); - buffer_add(STATE_SYNC(buffer), &ack, NETHDR_ACK_SIZ); + buffer_add(tx_queue, &ack, NETHDR_ACK_SIZ); +} + +static int do_cache_to_tx(void *data1, void *data2) +{ + struct us_conntrack *u = data2; + struct cache_nack *cn = cache_get_extra(STATE_SYNC(internal), u); + + /* add to tx list */ + list_add(&cn->tx_list, &tx_list); + tx_list_len++; + + return 0; } static int nack_local(int fd, int type, void *data) @@ -94,85 +124,78 @@ static int nack_local(int fd, int type, void *data) int ret = 1; switch(type) { - case REQUEST_DUMP: - mcast_send_control(NET_F_RESYNC, 0, 0); - dlog(STATE(log), "[REQ] request resync"); - break; - default: - ret = 0; - break; + case REQUEST_DUMP: + dlog(STATE(log), "[REQ] request resync"); + tx_queue_add_ctlmsg(NET_F_RESYNC, 0, 0); + break; + case SEND_BULK: + dlog(STATE(log), "[REQ] sending bulk update"); + cache_iterate(STATE_SYNC(internal), NULL, do_cache_to_tx); + break; + default: + ret = 0; + break; } return ret; } -static int buffer_compare(void *data1, void *data2) +static int rs_queue_to_tx(void *data1, void *data2) { struct nethdr *net = data1; struct nethdr_ack *nack = data2; - struct nlmsghdr *nlh = data1 + NETHDR_SIZ; - - unsigned old_seq = ntohl(net->seq); - if (between(ntohl(net->seq), nack->from, nack->to)) { - if (mcast_resend_netmsg(STATE_SYNC(mcast_client), net)) - dp("resend destroy (old seq=%u) (seq=%u)\n", - old_seq, ntohl(net->seq)); + if (between(net->seq, nack->from, nack->to)) { + dp("rs_queue_to_tx sq: %u fl:%u len:%u\n", + net->seq, net->flags, net->len); + buffer_add(tx_queue, net, net->len); } return 0; } -static int buffer_remove(void *data1, void *data2) +static int rs_queue_empty(void *data1, void *data2) { struct nethdr *net = data1; struct nethdr_ack *h = data2; - if (between(ntohl(net->seq), h->from, h->to)) { - dp("remove from buffer (seq=%u)\n", ntohl(net->seq)); - __buffer_del(STATE_SYNC(buffer), data1); + if (between(net->seq, h->from, h->to)) { + dp("remove from buffer (seq=%u)\n", net->seq); + buffer_del(rs_queue, data1); } return 0; } -static void queue_resend(struct cache *c, unsigned int from, unsigned int to) +static void rs_list_to_tx(struct cache *c, unsigned int from, unsigned int to) { struct list_head *n; struct us_conntrack *u; - list_for_each(n, &queue) { + list_for_each(n, &rs_list) { struct cache_nack *cn = (struct cache_nack *) n; struct us_conntrack *u; u = cache_get_conntrack(STATE_SYNC(internal), cn); - if (between(cn->seq, from, to)) { - debug_ct(u->ct, "resend nack"); - dp("resending nack'ed (oldseq=%u) ", cn->seq); - - if (mcast_build_send_update(u) == -1) - continue; - - dp("(newseq=%u)\n", cn->seq); + dp("resending nack'ed (oldseq=%u)\n", cn->seq); + list_add(&cn->tx_list, &tx_list); + tx_list_len++; } } } -static void queue_empty(struct cache *c, unsigned int from, unsigned int to) +static void rs_list_empty(struct cache *c, unsigned int from, unsigned int to) { struct list_head *n, *tmp; - struct us_conntrack *u; - dp("ACK from %u to %u\n", from, to); - list_for_each_safe(n, tmp, &queue) { + list_for_each_safe(n, tmp, &rs_list) { struct cache_nack *cn = (struct cache_nack *) n; + struct us_conntrack *u; u = cache_get_conntrack(STATE_SYNC(internal), cn); if (between(cn->seq, from, to)) { - dp("remove %u\n", cn->seq); - debug_ct(u->ct, "ack received: empty queue"); dp("queue: deleting from queue (seq=%u)\n", cn->seq); - list_del(&cn->head); - INIT_LIST_HEAD(&cn->head); + list_del(&cn->rs_list); + INIT_LIST_HEAD(&cn->rs_list); } } } @@ -187,73 +210,149 @@ static int nack_recv(const struct nethdr *net) if (!mcast_track_seq(net->seq, &exp_seq)) { dp("OOS: sending nack (seq=%u)\n", exp_seq); - mcast_send_control(NET_F_NACK, exp_seq, net->seq - 1); + tx_queue_add_ctlmsg(NET_F_NACK, exp_seq, net->seq-1); window = CONFIG(window_size); } else { /* received a window, send an acknowledgement */ if (--window == 0) { dp("sending ack (seq=%u)\n", net->seq); - mcast_send_control(NET_F_ACK, - net->seq - CONFIG(window_size), - net->seq); + tx_queue_add_ctlmsg(NET_F_ACK, + net->seq - CONFIG(window_size), + net->seq); } } - if (net->flags & NET_F_NACK) { + if (IS_NACK(net)) { struct nethdr_ack *nack = (struct nethdr_ack *) net; dp("NACK: from seq=%u to seq=%u\n", nack->from, nack->to); - queue_resend(STATE_SYNC(internal), nack->from, nack->to); - buffer_iterate(STATE_SYNC(buffer), nack, buffer_compare); + rs_list_to_tx(STATE_SYNC(internal), nack->from, nack->to); + buffer_iterate(rs_queue, nack, rs_queue_to_tx); return 1; - } else if (net->flags & NET_F_RESYNC) { + } else if (IS_RESYNC(net)) { dp("RESYNC ALL\n"); - cache_bulk(STATE_SYNC(internal)); + cache_iterate(STATE_SYNC(internal), NULL, do_cache_to_tx); return 1; - } else if (net->flags & NET_F_ACK) { + } else if (IS_ACK(net)) { struct nethdr_ack *h = (struct nethdr_ack *) net; dp("ACK: from seq=%u to seq=%u\n", h->from, h->to); - queue_empty(STATE_SYNC(internal), h->from, h->to); - buffer_iterate(STATE_SYNC(buffer), h, buffer_remove); + rs_list_empty(STATE_SYNC(internal), h->from, h->to); + buffer_iterate(rs_queue, h, rs_queue_empty); + return 1; + } else if (IS_ALIVE(net)) return 1; - } return 0; } -static void nack_send(int type, - const struct nethdr *net, - struct us_conntrack *u) +static void nack_send(struct nethdr *net, struct us_conntrack *u) { - int size = NETHDR_SIZ; - struct nlmsghdr *nlh = (struct nlmsghdr *) ((void *) net + size); + struct netpld *pld = NETHDR_DATA(net); struct cache_nack *cn; - - size += ntohl(nlh->nlmsg_len); - switch(type) { - case NFCT_T_NEW: - case NFCT_T_UPDATE: + HDR_NETWORK2HOST(net); + + switch(ntohs(pld->query)) { + case NFCT_Q_CREATE: + case NFCT_Q_UPDATE: cn = (struct cache_nack *) cache_get_extra(STATE_SYNC(internal), u); - if (cn->head.next == &cn->head && - cn->head.prev == &cn->head) + if (cn->rs_list.next == &cn->rs_list && + cn->rs_list.prev == &cn->rs_list) goto insert; - list_del(&cn->head); - INIT_LIST_HEAD(&cn->head); + list_del(&cn->rs_list); + INIT_LIST_HEAD(&cn->rs_list); insert: - cn->seq = ntohl(net->seq); - list_add(&cn->head, &queue); + cn->seq = net->seq; + list_add(&cn->rs_list, &rs_list); break; - case NFCT_T_DESTROY: - buffer_add(STATE_SYNC(buffer), net, size); + case NFCT_Q_DESTROY: + buffer_add(rs_queue, net, net->len); break; } } +static int tx_queue_xmit(void *data1, void *data2) +{ + struct nethdr *net = data1; + int len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); + + dp("tx_queue sq: %u fl:%u len:%u\n", + ntohl(net->seq), ntohs(net->flags), ntohs(net->len)); + + mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); + HDR_NETWORK2HOST(net); + + if (IS_DATA(net) || IS_ACK(net) || IS_NACK(net)) { + dp("-> back_to_tx_queue sq: %u fl:%u len:%u\n", + net->seq, net->flags, net->len); + buffer_add(rs_queue, net, net->len); + } + buffer_del(tx_queue, net); + + return 0; +} + +static int tx_list_xmit(struct list_head *i, struct us_conntrack *u) +{ + int ret; + struct nethdr *net = BUILD_NETMSG(u->ct, NFCT_Q_UPDATE); + int len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); + + dp("tx_list sq: %u fl:%u len:%u\n", + ntohl(net->seq), ntohs(net->flags), + ntohs(net->len)); + + list_del(i); + INIT_LIST_HEAD(i); + tx_list_len--; + + ret = mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); + if (STATE_SYNC(sync)->send) + STATE_SYNC(sync)->send(net, u); + + return ret; +} + +static struct alarm_list alive_alarm; + +static void do_alive_alarm(struct alarm_list *a, void *data) +{ + del_alarm(a); + tx_queue_add_ctlmsg(NET_F_ALIVE, 0, 0); +} + +static void nack_run(int step) +{ + struct list_head *i, *tmp; + + /* send messages in the tx_queue */ + buffer_iterate(tx_queue, NULL, tx_queue_xmit); + + /* send conntracks in the tx_list */ + list_for_each_safe(i, tmp, &tx_list) { + struct cache_nack *cn; + struct us_conntrack *u; + + cn = container_of(i, struct cache_nack, tx_list); + u = cache_get_conntrack(STATE_SYNC(internal), cn); + tx_list_xmit(i, u); + } + + if (alive_alarm.expires > 0) + mod_alarm(&alive_alarm, 1); + else { + init_alarm(&alive_alarm); + /* XXX: alive message expiration configurable */ + set_alarm_expiration(&alive_alarm, 1); + set_alarm_function(&alive_alarm, do_alive_alarm); + add_alarm(&alive_alarm); + } +} + struct sync_mode nack = { .internal_cache_flags = LIFETIME, .external_cache_flags = LIFETIME, @@ -263,4 +362,5 @@ struct sync_mode nack = { .local = nack_local, .recv = nack_recv, .send = nack_send, + .run = nack_run, }; diff --git a/src/sync-notrack.c b/src/sync-notrack.c index 1d6eba8..8588ecf 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -24,12 +24,16 @@ static void refresher(struct alarm_list *a, void *data) { + int len; + struct nethdr *net; struct us_conntrack *u = data; debug_ct(u->ct, "persistence update"); a->expires = random() % CONFIG(refresh) + 1; - mcast_build_send_update(u); + net = BUILD_NETMSG(u->ct, NFCT_Q_UPDATE); + len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); + mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); } static void cache_notrack_add(struct us_conntrack *u, void *data) diff --git a/src/timer.c b/src/timer.c new file mode 100644 index 0000000..b85c286 --- /dev/null +++ b/src/timer.c @@ -0,0 +1,75 @@ +/* + * (C) 2006-2007 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include "conntrackd.h" +#include "timer.h" + +#define TIMESLICE_CREDIT (1000000 / STEPS_PER_SECONDS) /* 200 ms timeslice */ + +void timer_init(struct timer *timer) +{ + memset(timer, 0, sizeof(struct timer)); + timer->credits = TIMESLICE_CREDIT; +} + +void timer_start(struct timer *timer) +{ + gettimeofday(&timer->start, NULL); +} + +static int timeval_subtract(struct timeval *diff, + struct timeval *start, + struct timeval *stop) +{ + diff->tv_sec = stop->tv_sec - start->tv_sec; + diff->tv_usec = stop->tv_usec - start->tv_usec; + + if (diff->tv_usec < 0) { + diff->tv_usec += 1000000; + diff->tv_sec--; + } + + /* Return 1 if result is negative. */ + return diff->tv_sec < 0; +} + +void timer_stop(struct timer *timer) +{ + gettimeofday(&timer->stop, NULL); + timeval_subtract(&timer->diff, &timer->start, &timer->stop); +} + +int timer_adjust_credit(struct timer *timer) +{ + if (timer->diff.tv_sec != 0) { + timer->credits = TIMESLICE_CREDIT; + return 1; + } + + timer->credits -= timer->diff.tv_usec; + + if (timer->credits < 0) { + timer->credits += TIMESLICE_CREDIT; + if (timer->credits < 0) + timer->credits = TIMESLICE_CREDIT; + return 1; + } + return 0; +} -- cgit v1.2.3 From 18bbf19becaab7dc4137406928f96ad089192f69 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Wed, 18 Jul 2007 20:04:00 +0000 Subject: conntrackd: - use buffer of MTU size conntrack: - better protocol argument checkings - fix per-protocol filtering, eg. conntrack -[L|E] -p tcp now works - show per-protocol help, ie. conntrack -h -p tcp - add alias --src for --orig-src and alias --dst for --orig-dst --- ChangeLog | 7 ++ examples/sync/nack/node1/conntrackd.conf | 1 + examples/sync/nack/node2/conntrackd.conf | 1 + examples/sync/persistent/node1/conntrackd.conf | 1 + examples/sync/persistent/node2/conntrackd.conf | 1 + extensions/libct_proto_icmp.c | 45 ++++++++--- extensions/libct_proto_tcp.c | 63 ++++++++++----- extensions/libct_proto_udp.c | 50 +++++++++--- include/conntrack.h | 28 +++++-- include/mcast.h | 3 + include/network.h | 7 ++ src/conntrack.c | 108 +++++++++++-------------- src/mcast.c | 14 ++++ src/network.c | 32 +++++++- src/read_config_lex.l | 3 +- src/read_config_yy.y | 9 ++- src/sync-mode.c | 9 ++- 17 files changed, 266 insertions(+), 116 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index b65966b..23ab6e9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,6 +5,7 @@ version 0.9.5 (yet unreleased) o conntrack-tools requires libnetfilter_conntrack >= 0.0.81 o add len field to nethdr o implement buffered send/recv to batch messages +o use buffer of MTU size o stop using netlink format for network messages: use similar TLV-based format o reduce synchronization messages size up to 60% o introduce periodic alive messages for sync-nack protocol @@ -14,6 +15,12 @@ o remove major use of libnfnetlink functions: use libnetfilter_conntrack API o deprecate conntrackd -F, use conntrack -F instead o major rework of the network infrastructure: much simple, less messy += conntrack = +o better protocol argument checkings +o fix per-protocol filtering, eg. conntrack -L -p tcp +o show per-protocol help, ie. conntrack -h -p tcp +o add alias --src for --orig-src and alias --dst for --orig-dst + version 0.9.4 (2007/07/02) ------------------------------ diff --git a/examples/sync/nack/node1/conntrackd.conf b/examples/sync/nack/node1/conntrackd.conf index edec9cf..9a7d55f 100644 --- a/examples/sync/nack/node1/conntrackd.conf +++ b/examples/sync/nack/node1/conntrackd.conf @@ -32,6 +32,7 @@ Sync { Multicast { IPv4_address 225.0.0.50 IPv4_interface 192.168.100.100 # IP of dedicated link + Interface eth2 Group 3780 } diff --git a/examples/sync/nack/node2/conntrackd.conf b/examples/sync/nack/node2/conntrackd.conf index de5f4d2..cee16c8 100644 --- a/examples/sync/nack/node2/conntrackd.conf +++ b/examples/sync/nack/node2/conntrackd.conf @@ -31,6 +31,7 @@ Sync { Multicast { IPv4_address 225.0.0.50 IPv4_interface 192.168.100.200 # IP of dedicated link + Interface eth2 Group 3780 } diff --git a/examples/sync/persistent/node1/conntrackd.conf b/examples/sync/persistent/node1/conntrackd.conf index 60f264b..e80921b 100644 --- a/examples/sync/persistent/node1/conntrackd.conf +++ b/examples/sync/persistent/node1/conntrackd.conf @@ -37,6 +37,7 @@ Sync { Multicast { IPv4_address 225.0.0.50 IPv4_interface 192.168.100.100 # IP of dedicated link + Interface eth2 Group 3780 } diff --git a/examples/sync/persistent/node2/conntrackd.conf b/examples/sync/persistent/node2/conntrackd.conf index 6a1806b..ad4b040 100644 --- a/examples/sync/persistent/node2/conntrackd.conf +++ b/examples/sync/persistent/node2/conntrackd.conf @@ -37,6 +37,7 @@ Sync { Multicast { IPv4_address 225.0.0.50 IPv4_interface 192.168.100.200 # IP of dedicated link + Interface eth2 Group 3780 } diff --git a/extensions/libct_proto_icmp.c b/extensions/libct_proto_icmp.c index 765ced4..09fd8da 100644 --- a/extensions/libct_proto_icmp.c +++ b/extensions/libct_proto_icmp.c @@ -24,6 +24,33 @@ static struct option opts[] = { {0, 0, 0, 0} }; +#define ICMP_NUMBER_OF_OPT 4 + +static const char *icmp_optflags[ICMP_NUMBER_OF_OPT] = { +"icmp-type", "icmp-code", "icmp-id" +}; + +static char icmp_commands_v_options[NUMBER_OF_CMD][ICMP_NUMBER_OF_OPT] = +/* Well, it's better than "Re: Maradona vs Pele" */ +{ + /* 1 2 3 */ +/*CT_LIST*/ {2,2,2}, +/*CT_CREATE*/ {1,1,2}, +/*CT_UPDATE*/ {1,1,2}, +/*CT_DELETE*/ {1,1,2}, +/*CT_GET*/ {1,1,2}, +/*CT_FLUSH*/ {0,0,0}, +/*CT_EVENT*/ {2,2,2}, +/*CT_VERSION*/ {0,0,0}, +/*CT_HELP*/ {0,0,0}, +/*EXP_LIST*/ {0,0,0}, +/*EXP_CREATE*/ {0,0,0}, +/*EXP_DELETE*/ {0,0,0}, +/*EXP_GET*/ {0,0,0}, +/*EXP_FLUSH*/ {0,0,0}, +/*EXP_EVENT*/ {0,0,0}, +}; + static void help() { fprintf(stdout, " --icmp-type\t\t\ticmp type\n"); @@ -31,7 +58,7 @@ static void help() fprintf(stdout, " --icmp-id\t\t\ticmp id\n"); } -static int parse(char c, char *argv[], +static int parse(char c, struct nf_conntrack *ct, struct nf_conntrack *exptuple, struct nf_conntrack *mask, @@ -69,16 +96,14 @@ static int parse(char c, char *argv[], return 1; } -static int final_check(unsigned int flags, - unsigned int command, - struct nf_conntrack *ct) +static void final_check(unsigned int flags, + unsigned int cmd, + struct nf_conntrack *ct) { - if (!(flags & ICMP_TYPE)) - return 0; - else if (!(flags & ICMP_CODE)) - return 0; - - return 1; + generic_opt_check(flags, + ICMP_NUMBER_OF_OPT, + icmp_commands_v_options[cmd], + icmp_optflags); } static struct ctproto_handler icmp = { diff --git a/extensions/libct_proto_tcp.c b/extensions/libct_proto_tcp.c index 5a40cef..1f630b3 100644 --- a/extensions/libct_proto_tcp.c +++ b/extensions/libct_proto_tcp.c @@ -32,6 +32,34 @@ static struct option opts[] = { {0, 0, 0, 0} }; +#define TCP_NUMBER_OF_OPT 10 + +static const char *tcp_optflags[TCP_NUMBER_OF_OPT] = { +"sport", "dport", "reply-port-src", "reply-port-dst", "mask-port-src", +"mask-port-dst", "state", "tuple-port-src", "tuple-port-dst" +}; + +static char tcp_commands_v_options[NUMBER_OF_CMD][TCP_NUMBER_OF_OPT] = +/* Well, it's better than "Re: Sevilla vs Betis" */ +{ + /* 1 2 3 4 5 6 7 8 9 */ +/*CT_LIST*/ {2,2,2,2,0,0,2,0,0}, +/*CT_CREATE*/ {1,1,1,1,0,0,1,0,0}, +/*CT_UPDATE*/ {1,1,1,1,0,0,2,0,0}, +/*CT_DELETE*/ {1,1,1,1,0,0,0,0,0}, +/*CT_GET*/ {1,1,1,1,0,0,2,0,0}, +/*CT_FLUSH*/ {0,0,0,0,0,0,0,0,0}, +/*CT_EVENT*/ {2,2,2,2,0,0,2,0,0}, +/*CT_VERSION*/ {0,0,0,0,0,0,0,0,0}, +/*CT_HELP*/ {0,0,0,0,0,0,0,0,0}, +/*EXP_LIST*/ {0,0,0,0,0,0,0,0,0}, +/*EXP_CREATE*/ {1,1,1,1,1,1,0,1,1}, +/*EXP_DELETE*/ {1,1,1,1,0,0,0,0,0}, +/*EXP_GET*/ {1,1,1,1,0,0,0,0,0}, +/*EXP_FLUSH*/ {0,0,0,0,0,0,0,0,0}, +/*EXP_EVENT*/ {0,0,0,0,0,0,0,0,0}, +}; + static const char *states[] = { "NONE", "SYN_SENT", @@ -58,7 +86,7 @@ static void help() fprintf(stdout, " --state\t\t\tTCP state, fe. ESTABLISHED\n"); } -static int parse_options(char c, char *argv[], +static int parse_options(char c, struct nf_conntrack *ct, struct nf_conntrack *exptuple, struct nf_conntrack *mask, @@ -139,10 +167,9 @@ static int parse_options(char c, char *argv[], break; } } - if (i == 10) { - printf("doh?\n"); - return 0; - } + if (i == 10) + exit_error(PARAMETER_PROBLEM, + "Unknown TCP state %s\n", optarg); *flags |= TCP_STATE; break; case '8': @@ -169,12 +196,10 @@ static int parse_options(char c, char *argv[], return 1; } -static int final_check(unsigned int flags, - unsigned int command, - struct nf_conntrack *ct) +static void final_check(unsigned int flags, + unsigned int cmd, + struct nf_conntrack *ct) { - int ret = 0; - if ((flags & (TCP_ORIG_SPORT|TCP_ORIG_DPORT)) && !(flags & (TCP_REPL_SPORT|TCP_REPL_DPORT))) { nfct_set_attr_u16(ct, @@ -183,7 +208,8 @@ static int final_check(unsigned int flags, nfct_set_attr_u16(ct, ATTR_REPL_PORT_DST, nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC)); - ret = 1; + flags |= TCP_REPL_SPORT; + flags |= TCP_REPL_DPORT; } else if (!(flags & (TCP_ORIG_SPORT|TCP_ORIG_DPORT)) && (flags & (TCP_REPL_SPORT|TCP_REPL_DPORT))) { nfct_set_attr_u16(ct, @@ -192,17 +218,14 @@ static int final_check(unsigned int flags, nfct_set_attr_u16(ct, ATTR_ORIG_PORT_DST, nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC)); - ret = 1; + flags |= TCP_ORIG_SPORT; + flags |= TCP_ORIG_DPORT; } - if ((flags & (TCP_ORIG_SPORT|TCP_ORIG_DPORT)) - && ((flags & (TCP_REPL_SPORT|TCP_REPL_DPORT)))) - ret = 1; - - /* --state is missing and we are trying to create a conntrack */ - if (ret && (command & CT_CREATE) && (!(flags & TCP_STATE))) - ret = 0; - return ret; + generic_opt_check(flags, + TCP_NUMBER_OF_OPT, + tcp_commands_v_options[cmd], + tcp_optflags); } static struct ctproto_handler tcp = { diff --git a/extensions/libct_proto_udp.c b/extensions/libct_proto_udp.c index cb131d6..2216b71 100644 --- a/extensions/libct_proto_udp.c +++ b/extensions/libct_proto_udp.c @@ -31,6 +31,13 @@ static struct option opts[] = { {0, 0, 0, 0} }; +#define UDP_NUMBER_OF_OPT 9 + +static const char *udp_optflags[UDP_NUMBER_OF_OPT] = { +"sport", "dport", "reply-port-src", "reply-port-dst", "mask-port-src", +"mask-port-dst", "tuple-port-src", "tuple-port-dst" +}; + static void help() { fprintf(stdout, " --orig-port-src\t\toriginal source port\n"); @@ -43,7 +50,28 @@ static void help() fprintf(stdout, " --tuple-port-src\t\texpectation tuple dst port\n"); } -static int parse_options(char c, char *argv[], +static char udp_commands_v_options[NUMBER_OF_CMD][UDP_NUMBER_OF_OPT] = +/* Well, it's better than "Re: Galeano vs Vargas Llosa" */ +{ + /* 1 2 3 4 5 6 7 8 */ +/*CT_LIST*/ {2,2,2,2,0,0,0,0}, +/*CT_CREATE*/ {1,1,1,1,0,0,0,0}, +/*CT_UPDATE*/ {1,1,1,1,0,0,0,0}, +/*CT_DELETE*/ {1,1,1,1,0,0,0,0}, +/*CT_GET*/ {1,1,1,1,0,0,0,0}, +/*CT_FLUSH*/ {0,0,0,0,0,0,0,0}, +/*CT_EVENT*/ {2,2,2,2,0,0,0,0}, +/*CT_VERSION*/ {0,0,0,0,0,0,0,0}, +/*CT_HELP*/ {0,0,0,0,0,0,0,0}, +/*EXP_LIST*/ {0,0,0,0,0,0,0,0}, +/*EXP_CREATE*/ {1,1,1,1,1,1,1,1}, +/*EXP_DELETE*/ {1,1,1,1,0,0,0,0}, +/*EXP_GET*/ {1,1,1,1,0,0,0,0}, +/*EXP_FLUSH*/ {0,0,0,0,0,0,0,0}, +/*EXP_EVENT*/ {0,0,0,0,0,0,0,0}, +}; + +static int parse_options(char c, struct nf_conntrack *ct, struct nf_conntrack *exptuple, struct nf_conntrack *mask, @@ -134,9 +162,9 @@ static int parse_options(char c, char *argv[], return 1; } -static int final_check(unsigned int flags, - unsigned int command, - struct nf_conntrack *ct) +static void final_check(unsigned int flags, + unsigned int cmd, + struct nf_conntrack *ct) { int ret = 0; @@ -148,7 +176,8 @@ static int final_check(unsigned int flags, nfct_set_attr_u16(ct, ATTR_REPL_PORT_DST, nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC)); - ret = 1; + flags |= UDP_REPL_SPORT; + flags |= UDP_REPL_DPORT; } else if (!(flags & (UDP_ORIG_SPORT|UDP_ORIG_DPORT)) && (flags & (UDP_REPL_SPORT|UDP_REPL_DPORT))) { nfct_set_attr_u16(ct, @@ -157,13 +186,14 @@ static int final_check(unsigned int flags, nfct_set_attr_u16(ct, ATTR_ORIG_PORT_DST, nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC)); - ret = 1; + flags |= UDP_ORIG_SPORT; + flags |= UDP_ORIG_DPORT; } - if ((flags & (UDP_ORIG_SPORT|UDP_ORIG_DPORT)) - && ((flags & (UDP_REPL_SPORT|UDP_REPL_DPORT)))) - ret = 1; - return ret; + generic_opt_check(flags, + UDP_NUMBER_OF_OPT, + udp_commands_v_options[cmd], + udp_optflags); } static struct ctproto_handler udp = { diff --git a/include/conntrack.h b/include/conntrack.h index f344d72..5edc0e9 100644 --- a/include/conntrack.h +++ b/include/conntrack.h @@ -151,15 +151,15 @@ struct ctproto_handler { enum ctattr_protoinfo protoinfo_attr; - int (*parse_opts)(char c, char *argv[], - struct nf_conntrack *ct, - struct nf_conntrack *exptuple, - struct nf_conntrack *mask, - unsigned int *flags); + int (*parse_opts)(char c, + struct nf_conntrack *ct, + struct nf_conntrack *exptuple, + struct nf_conntrack *mask, + unsigned int *flags); - int (*final_check)(unsigned int flags, - unsigned int command, - struct nf_conntrack *ct); + void (*final_check)(unsigned int flags, + unsigned int command, + struct nf_conntrack *ct); void (*help)(); @@ -168,6 +168,18 @@ struct ctproto_handler { unsigned int option_offset; }; +enum exittype { + OTHER_PROBLEM = 1, + PARAMETER_PROBLEM, + VERSION_PROBLEM +}; + +void generic_opt_check(int options, + int nops, + char *optset, + const char *optflg[]); +void exit_error(enum exittype status, char *msg, ...); + extern void register_proto(struct ctproto_handler *h); extern void register_tcp(void); diff --git a/include/mcast.h b/include/mcast.h index 66676dc..d4fd335 100644 --- a/include/mcast.h +++ b/include/mcast.h @@ -2,6 +2,7 @@ #define _MCAST_H_ #include +#include struct mcast_conf { int ipproto; @@ -16,6 +17,8 @@ struct mcast_conf { struct in_addr interface_addr; struct in6_addr interface_addr6; } ifa; + int mtu; + char iface[IFNAMSIZ]; }; struct mcast_stats { diff --git a/include/network.h b/include/network.h index bc9431d..f8fdd0d 100644 --- a/include/network.h +++ b/include/network.h @@ -55,6 +55,13 @@ int prepare_send_netmsg(struct mcast_sock *m, void *data); int mcast_send_netmsg(struct mcast_sock *m, void *data); int mcast_recv_netmsg(struct mcast_sock *m, void *data, int len); +struct mcast_conf; + +int mcast_buffered_init(struct mcast_conf *conf); +void mcast_buffered_destroy(); +int mcast_buffered_send_netmsg(struct mcast_sock *m, void *data, int len); +int mcast_buffered_pending_netmsg(struct mcast_sock *m); + #define IS_DATA(x) ((x->flags & ~NET_F_HELLO) == 0) #define IS_ACK(x) (x->flags & NET_F_ACK) #define IS_NACK(x) (x->flags & NET_F_NACK) diff --git a/src/conntrack.c b/src/conntrack.c index eece45b..165809b 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -64,8 +64,10 @@ static const char cmdflags[NUMBER_OF_CMD] static const char cmd_need_param[NUMBER_OF_CMD] = { 2, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, 0, 2, 2 }; -static const char optflags[NUMBER_OF_OPT] -= {'s','d','r','q','p','t','u','z','e','[',']','{','}','a','m','i','f','n','g','x'}; +static const char *optflags[NUMBER_OF_OPT] = { +"src","dst","reply-src","reply-dst","protonum","timeout","status","zero", +"event-mask","tuple-src","tuple-dst","mask-src","mask-dst","nat-range","mark", +"id","family","src-nat","dst-nat","output" }; static struct option original_opts[] = { {"dump", 2, 0, 'L'}, @@ -78,7 +80,9 @@ static struct option original_opts[] = { {"version", 0, 0, 'V'}, {"help", 0, 0, 'h'}, {"orig-src", 1, 0, 's'}, + {"src", 1, 0, 's'}, {"orig-dst", 1, 0, 'd'}, + {"dst", 1, 0, 'd'}, {"reply-src", 1, 0, 'r'}, {"reply-dst", 1, 0, 'q'}, {"protonum", 1, 0, 'p'}, @@ -127,7 +131,7 @@ static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = /*CT_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, /*CT_EVENT*/ {2,2,2,2,2,0,0,0,2,0,0,0,0,0,2,0,0,2,2,2}, /*VERSION*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*HELP*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*HELP*/ {0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, /*EXP_LIST*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,0,0,0}, /*EXP_CREATE*/{1,1,2,2,1,1,2,0,0,1,1,1,1,0,0,0,0,0,0,0}, /*EXP_DELETE*/{1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, @@ -172,12 +176,6 @@ static struct ctproto_handler *findproto(char *name) return handler; } -enum exittype { - OTHER_PROBLEM = 1, - PARAMETER_PROBLEM, - VERSION_PROBLEM -}; - void extension_help(struct ctproto_handler *h) { fprintf(stdout, "\n"); @@ -193,8 +191,7 @@ exit_tryhelp(int status) exit(status); } -static void -exit_error(enum exittype status, char *msg, ...) +void exit_error(enum exittype status, char *msg, ...) { va_list args; @@ -218,51 +215,43 @@ exit_error(enum exittype status, char *msg, ...) static void generic_cmd_check(int command, int options) { - int i; - - for (i = 0; i < NUMBER_OF_CMD; i++) { - if (!(command & (1< illegal, 1 => legal, 0 => undecided. */ + for (i = 0; i < NUMBER_OF_CMD; i++) + if (command & (1<parse_opts - &&!h->parse_opts(c - h->option_offset, argv, obj, + &&!h->parse_opts(c - h->option_offset, obj, exptuple, mask, &l4flags)) exit_error(PARAMETER_PROBLEM, "parse error\n"); @@ -996,16 +985,15 @@ int main(int argc, char *argv[]) if (family == AF_UNSPEC) family = AF_INET; - generic_cmd_check(command, options); - generic_opt_check(command, options); + cmd = bit2cmd(command); + generic_cmd_check(cmd, options); + generic_opt_check(options, + NUMBER_OF_OPT, + commands_v_options[cmd], + optflags); - if (!(command & CT_HELP) - && h && h->final_check - && !h->final_check(l4flags, command, obj)) { - usage(argv[0]); - extension_help(h); - exit_error(PARAMETER_PROBLEM, "Missing protocol arguments!\n"); - } + if (!(command & CT_HELP) && h && h->final_check) + h->final_check(l4flags, cmd, obj); switch(command) { diff --git a/src/mcast.c b/src/mcast.c index 6193a59..cdaed5f 100644 --- a/src/mcast.c +++ b/src/mcast.c @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include "mcast.h" #include "debug.h" @@ -71,6 +73,18 @@ struct mcast_sock *mcast_server_create(struct mcast_conf *conf) return NULL; } + if(conf->iface[0]) { + struct ifreq ifr; + + strncpy(ifr.ifr_name, conf->iface, sizeof(ifr.ifr_name)); + + if (ioctl(m->fd, SIOCGIFMTU, &ifr) == -1) { + debug("ioctl"); + return NULL; + } + conf->mtu = ifr.ifr_mtu; + } + if (setsockopt(m->fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) { debug("mcast_sock_server_create:setsockopt1"); diff --git a/src/network.c b/src/network.c index d162839..a7843dc 100644 --- a/src/network.c +++ b/src/network.c @@ -90,9 +90,33 @@ int prepare_send_netmsg(struct mcast_sock *m, void *data) return ret; } +static int tx_buflenmax; static int tx_buflen = 0; -/* XXX: use buffer size of interface MTU */ -static char __tx_buf[1460], *tx_buf = __tx_buf; +static char *tx_buf; + +#define HEADERSIZ 28 /* IP header (20 bytes) + UDP header 8 (bytes) */ + +int mcast_buffered_init(struct mcast_conf *conf) +{ + int mtu = conf->mtu - HEADERSIZ; + + /* default to Ethernet MTU 1500 bytes */ + if (mtu == 0) + mtu = 1500 - HEADERSIZ; + + tx_buf = malloc(mtu); + if (tx_buf == NULL) + return -1; + + tx_buflenmax = mtu; + + return 0; +} + +void mcast_buffered_destroy(void) +{ + free(tx_buf); +} /* return 0 if it is not sent, otherwise return 1 */ int mcast_buffered_send_netmsg(struct mcast_sock *m, void *data, int len) @@ -101,8 +125,8 @@ int mcast_buffered_send_netmsg(struct mcast_sock *m, void *data, int len) struct nethdr *net = data; retry: - if (tx_buflen + len < sizeof(__tx_buf)) { - memcpy(__tx_buf + tx_buflen, net, len); + if (tx_buflen + len < tx_buflenmax) { + memcpy(tx_buf + tx_buflen, net, len); tx_buflen += len; } else { __do_send(m, tx_buf, tx_buflen); diff --git a/src/read_config_lex.l b/src/read_config_lex.l index dee90c9..87e98d1 100644 --- a/src/read_config_lex.l +++ b/src/read_config_lex.l @@ -42,7 +42,7 @@ ip6_part {hex_255}":"? ip6_form1 {ip6_part}{0,16}"::"{ip6_part}{0,16} ip6_form2 ({hex_255}":"){16}{hex_255} ip6 {ip6_form1}|{ip6_form2} -string [a-zA-Z]* +string [a-zA-Z0-9]* persistent [P|p][E|e][R|r][S|s][I|i][S|s][T|t][E|e][N|n][T|T] nack [N|n][A|a][C|c][K|k] @@ -52,6 +52,7 @@ nack [N|n][A|a][C|c][K|k] "IPv6_address" { return T_IPV6_ADDR; } "IPv4_interface" { return T_IPV4_IFACE; } "IPv6_interface" { return T_IPV6_IFACE; } +"Interface" { return T_IFACE; } "Port" { return T_PORT; } "Multicast" { return T_MULTICAST; } "HashSize" { return T_HASHSIZE; } diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 57250b4..de592d2 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -1,6 +1,6 @@ %{ /* - * (C) 2006 by Pablo Neira Ayuso + * (C) 2006-2007 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 @@ -45,7 +45,7 @@ struct ct_conf conf; %token T_GENERAL T_SYNC T_STATS T_RELAX_TRANSITIONS T_BUFFER_SIZE T_DELAY %token T_SYNC_MODE T_LISTEN_TO T_FAMILY T_RESEND_BUFFER_SIZE %token T_PERSISTENT T_NACK T_CHECKSUM T_WINDOWSIZE T_ON T_OFF -%token T_REPLICATE T_FOR +%token T_REPLICATE T_FOR T_IFACE %token T_ESTABLISHED T_SYN_SENT T_SYN_RECV T_FIN_WAIT %token T_CLOSE_WAIT T_LAST_ACK T_TIME_WAIT T_CLOSE T_LISTEN @@ -227,6 +227,11 @@ multicast_option : T_IPV6_IFACE T_IP conf.mcast.ipproto = AF_INET6; }; +multicast_option : T_IFACE T_STRING +{ + strncpy(conf.mcast.iface, $2, IFNAMSIZ); +}; + multicast_option : T_BACKLOG T_NUMBER { fprintf(stderr, "Notice: Backlog option inside Multicast clause is " diff --git a/src/sync-mode.c b/src/sync-mode.c index f30cb95..917a3b2 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -86,7 +86,7 @@ retry: static void mcast_handler() { int numbytes, remain; - char __net[4096], *ptr = __net; + char __net[65536], *ptr = __net; /* XXX: maximum MTU for IPv4 */ numbytes = mcast_recv(STATE_SYNC(mcast_server), __net, sizeof(__net)); if (numbytes <= 0) @@ -173,6 +173,11 @@ static int init_sync(void) return -1; } + if (mcast_buffered_init(&CONFIG(mcast)) == -1) { + dlog(STATE(log), "[FAIL] can't init tx buffer!"); + return -1; + } + /* initialization of multicast sequence generation */ STATE_SYNC(last_seq_sent) = time(NULL); @@ -207,6 +212,8 @@ static void kill_sync() mcast_server_destroy(STATE_SYNC(mcast_server)); mcast_client_destroy(STATE_SYNC(mcast_client)); + mcast_buffered_destroy(); + if (STATE_SYNC(sync)->kill) STATE_SYNC(sync)->kill(); } -- cgit v1.2.3 From 9479a701b5185f5f5ad4ddf14ac37b847aa979dd Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Thu, 19 Jul 2007 15:13:22 +0000 Subject: minor fix in the last commit: check conf->mtu instead of mtu that is < 0 --- src/network.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/network.c b/src/network.c index a7843dc..9bd3469 100644 --- a/src/network.c +++ b/src/network.c @@ -101,7 +101,7 @@ int mcast_buffered_init(struct mcast_conf *conf) int mtu = conf->mtu - HEADERSIZ; /* default to Ethernet MTU 1500 bytes */ - if (mtu == 0) + if (conf->mtu == 0) mtu = 1500 - HEADERSIZ; tx_buf = malloc(mtu); -- cgit v1.2.3 From 0b8d66289f7e96c449bb88e7ec20a5860fba18ee Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Thu, 19 Jul 2007 17:13:40 +0000 Subject: - simplify cache_flush function: use cache_del() --- ChangeLog | 1 + src/cache_iterators.c | 13 +------------ 2 files changed, 2 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 4008415..82d5947 100644 --- a/ChangeLog +++ b/ChangeLog @@ -14,6 +14,7 @@ o simplify debugging functions: use nfct_snprintf instead o remove major use of libnfnetlink functions: use libnetfilter_conntrack API o deprecate conntrackd -F, use conntrack -F instead o major rework of the network infrastructure: much simple, less messy +o simplify cache_flush function: use cache_del() = conntrack = o better protocol argument checkings diff --git a/src/cache_iterators.c b/src/cache_iterators.c index 1d1b2e8..36f7364 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -148,18 +148,8 @@ static int do_flush(void *data1, void *data2) { struct cache *c = data1; struct us_conntrack *u = data2; - void *data = u->data; - int i; - - for (i = 0; i < c->num_features; i++) { - c->features[i]->destroy(u, data); - data += c->features[i]->size; - } - - if (c->extra && c->extra->destroy) - c->extra->destroy(u, ((void *) u) + c->extra_offset); - free(u->ct); + cache_del(c, u->ct); return 0; } @@ -167,6 +157,5 @@ static int do_flush(void *data1, void *data2) void cache_flush(struct cache *c) { hashtable_iterate(c->h, c, do_flush); - hashtable_flush(c->h); c->flush++; } -- cgit v1.2.3 From 281a74fc8d2a474f35b07e6b9a82ba8e4be3f627 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Thu, 19 Jul 2007 18:35:41 +0000 Subject: fix NAT in changes committed in r6904 --- src/build.c | 49 ++++++++++++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/build.c b/src/build.c index b77dbc2..981548e 100644 --- a/src/build.c +++ b/src/build.c @@ -58,20 +58,21 @@ static void __build_u32(const struct nf_conntrack *ct, addattr(pld, attr, &data, sizeof(u_int32_t)); } +static void __nat_build_u32(u_int32_t data, struct netpld *pld, int attr) +{ + data = htonl(data); + addattr(pld, attr, &data, sizeof(u_int32_t)); +} + +static void __nat_build_u16(u_int16_t data, struct netpld *pld, int attr) +{ + data = htons(data); + addattr(pld, attr, &data, sizeof(u_int16_t)); +} + /* XXX: IPv6 and ICMP not supported */ void build_netpld(struct nf_conntrack *ct, struct netpld *pld, int query) { - /* undo NAT */ - if (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) - nfct_setobjopt(ct, NFCT_SOPT_UNDO_SNAT); - if (nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) - nfct_setobjopt(ct, NFCT_SOPT_UNDO_DNAT); - if (nfct_getobjopt(ct, NFCT_GOPT_IS_SPAT)) - nfct_setobjopt(ct, NFCT_SOPT_UNDO_SPAT); - if (nfct_getobjopt(ct, NFCT_GOPT_IS_DPAT)) - nfct_setobjopt(ct, NFCT_SOPT_UNDO_DPAT); - - /* build message */ if (nfct_attr_is_set(ct, ATTR_IPV4_SRC)) __build_u32(ct, pld, ATTR_IPV4_SRC); if (nfct_attr_is_set(ct, ATTR_IPV4_DST)) @@ -92,14 +93,6 @@ void build_netpld(struct nf_conntrack *ct, struct netpld *pld, int query) __build_u8(ct, pld, ATTR_TCP_STATE); } } - if (nfct_attr_is_set(ct, ATTR_SNAT_IPV4)) - __build_u32(ct, pld, ATTR_SNAT_IPV4); - if (nfct_attr_is_set(ct, ATTR_DNAT_IPV4)) - __build_u32(ct, pld, ATTR_DNAT_IPV4); - if (nfct_attr_is_set(ct, ATTR_SNAT_PORT)) - __build_u16(ct, pld, ATTR_SNAT_PORT); - if (nfct_attr_is_set(ct, ATTR_DNAT_PORT)) - __build_u16(ct, pld, ATTR_DNAT_PORT); if (nfct_attr_is_set(ct, ATTR_TIMEOUT)) __build_u32(ct, pld, ATTR_TIMEOUT); if (nfct_attr_is_set(ct, ATTR_MARK)) @@ -107,6 +100,24 @@ void build_netpld(struct nf_conntrack *ct, struct netpld *pld, int query) if (nfct_attr_is_set(ct, ATTR_STATUS)) __build_u32(ct, pld, ATTR_STATUS); + /* NAT */ + if (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) { + u_int32_t data = nfct_get_attr_u32(ct, ATTR_REPL_IPV4_DST); + __nat_build_u32(data, pld, ATTR_SNAT_IPV4); + } + if (nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) { + u_int32_t data = nfct_get_attr_u32(ct, ATTR_REPL_IPV4_SRC); + __nat_build_u32(data, pld, ATTR_DNAT_IPV4); + } + if (nfct_getobjopt(ct, NFCT_GOPT_IS_SPAT)) { + u_int16_t data = nfct_get_attr_u16(ct, ATTR_REPL_PORT_DST); + __nat_build_u16(data, pld, ATTR_SNAT_PORT); + } + if (nfct_getobjopt(ct, NFCT_GOPT_IS_DPAT)) { + u_int16_t data = nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC); + __nat_build_u16(data, pld, ATTR_DNAT_PORT); + } + pld->query = query; PLD_HOST2NETWORK(pld); -- cgit v1.2.3 From 8c634be62780c8467e6a61419d40cdc8b7a0c865 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Mon, 6 Aug 2007 09:43:06 +0000 Subject: conntrack-tools compilation problem (K.Kovacs) --- ChangeLog | 5 +++++ Makefile.am | 2 +- configure.in | 4 ++++ src/Makefile.am | 3 ++- 4 files changed, 12 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index bb376bd..588cab0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +version 0.9.6 (yet unreleased) +------------------------------ + +o fix compilation problem due to missing headers (Krisztian Kovacs) + version 0.9.5 (2007/07/29) ------------------------------ diff --git a/Makefile.am b/Makefile.am index 17282b2..239eedf 100644 --- a/Makefile.am +++ b/Makefile.am @@ -9,7 +9,7 @@ EXTRA_DIST = $(man_MANS) Make_global.am ChangeLog TODO examples SUBDIRS = extensions src DIST_SUBDIRS = include src extensions -LINKOPTS = -lnfnetlink -lnetfilter_conntrack -lpthread +LIBS = @LIBNETFILTER_CONNTRACK_LIBS@ AM_CFLAGS = -g $(OBJECTS): libtool diff --git a/configure.in b/configure.in index 7e1cd20..6582b1b 100644 --- a/configure.in +++ b/configure.in @@ -104,4 +104,8 @@ dnl debug/src/Makefile dnl extensions/Makefile dnl src/Makefile]) +CFLAGS="$CFLAGS $LIBNETFILTER_CONNTRACK_CFLAGS" + +AC_SUBST(LIBNETFILTER_CONNTRACK_LIBS) + AC_OUTPUT(Makefile src/Makefile include/Makefile extensions/Makefile) diff --git a/src/Makefile.am b/src/Makefile.am index d71e23c..83511fa 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -8,6 +8,7 @@ sbin_PROGRAMS = conntrack conntrackd conntrack_SOURCES = conntrack.c conntrack_LDADD = ../extensions/libct_proto_tcp.la ../extensions/libct_proto_udp.la ../extensions/libct_proto_icmp.la +conntrack_LDFLAGS = $(all_libraries) @LIBNETFILTER_CONNTRACK_LIBS@ conntrackd_SOURCES = alarm.c main.c run.c hash.c buffer.c \ local.c log.c mcast.c netlink.c \ @@ -22,6 +23,6 @@ conntrackd_SOURCES = alarm.c main.c run.c hash.c buffer.c \ build.c parse.c \ read_config_yy.y read_config_lex.l -conntrackd_LDFLAGS = $(all_libraries) -lnfnetlink -lnetfilter_conntrack +conntrackd_LDFLAGS = $(all_libraries) @LIBNETFILTER_CONNTRACK_LIBS@ EXTRA_DIST = read_config_yy.h -- cgit v1.2.3 From f23d9e790a27d29462c2fb6185253349375cef12 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Wed, 12 Sep 2007 12:48:34 +0000 Subject: Remove window tracking disabling limitation (requires Linux kernel >= 2.6.22) --- ChangeLog | 3 +++ src/cache_iterators.c | 13 +++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 447d171..6d1aa06 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,9 @@ version 0.9.6 (yet unreleased) o fix compilation problem due to missing headers (Krisztian Kovacs) o include kernel options and Fedora comments in the INSTALL file += conntrackd = +o Remove window tracking disabling limitation (requires Linux kernel >= 2.6.22) + version 0.9.5 (2007/07/29) ------------------------------ diff --git a/src/cache_iterators.c b/src/cache_iterators.c index 36f7364..287f92f 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -78,6 +78,7 @@ void cache_dump(struct cache *c, int fd, int type) static int do_commit(void *data1, void *data2) { int ret; + u_int8_t flags; struct cache *c = data1; struct us_conntrack *u = data2; struct nf_conntrack *ct = u->ct; @@ -97,10 +98,14 @@ static int do_commit(void *data1, void *data2) */ nfct_set_attr_u32(ct, ATTR_TIMEOUT, CONFIG(commit_timeout)); - if (ret == -1) { - dlog(STATE(log), "failed to build: %s", strerror(errno)); - return 0; - } + /* + * TCP flags to overpass window tracking for recovered connections + */ + flags = IP_CT_TCP_FLAG_BE_LIBERAL | IP_CT_TCP_FLAG_SACK_PERM; + nfct_set_attr_u8(ct, ATTR_TCP_FLAGS_ORIG, flags); + nfct_set_attr_u8(ct, ATTR_TCP_MASK_ORIG, flags); + nfct_set_attr_u8(ct, ATTR_TCP_FLAGS_REPL, flags); + nfct_set_attr_u8(ct, ATTR_TCP_MASK_REPL, flags); ret = nfct_query(STATE(dump), NFCT_Q_CREATE_UPDATE, ct); if (ret == -1) { -- cgit v1.2.3 From 66cd168df39bfcf581bb36250a080a66331ee5cd Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Wed, 12 Sep 2007 15:23:14 +0000 Subject: add syslog support and bump version --- ChangeLog | 1 + configure.in | 2 +- examples/stats/conntrackd.conf | 11 +++- examples/sync/nack/node1/conntrackd.conf | 11 +++- examples/sync/nack/node2/conntrackd.conf | 11 +++- examples/sync/persistent/node1/conntrackd.conf | 11 +++- examples/sync/persistent/node2/conntrackd.conf | 11 +++- include/conntrackd.h | 4 ++ include/log.h | 2 +- src/cache_iterators.c | 10 ++-- src/log.c | 76 +++++++++++++++++++------- src/main.c | 12 ++-- src/netlink.c | 12 ++-- src/read_config_lex.l | 3 +- src/read_config_yy.y | 57 ++++++++++++++++++- src/run.c | 28 +++++----- src/stats-mode.c | 17 +++--- src/sync-mode.c | 33 +++++------ src/sync-nack.c | 8 +-- 19 files changed, 228 insertions(+), 92 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 6d1aa06..c085175 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,6 +6,7 @@ o include kernel options and Fedora comments in the INSTALL file = conntrackd = o Remove window tracking disabling limitation (requires Linux kernel >= 2.6.22) +o syslog support (based on patch from Simon Lodal) version 0.9.5 (2007/07/29) ------------------------------ diff --git a/configure.in b/configure.in index 536d2d8..9400e37 100644 --- a/configure.in +++ b/configure.in @@ -1,4 +1,4 @@ -AC_INIT(conntrack-tools, 0.9.5, pablo@netfilter.org) +AC_INIT(conntrack-tools, 0.9.6, pablo@netfilter.org) AC_CANONICAL_SYSTEM diff --git a/examples/stats/conntrackd.conf b/examples/stats/conntrackd.conf index e514ac0..07deaa8 100644 --- a/examples/stats/conntrackd.conf +++ b/examples/stats/conntrackd.conf @@ -14,9 +14,16 @@ General { HashLimit 65535 # - # Logfile + # Logfile: on, off, or a filename + # Default: on (/var/log/conntrackd.log) # - LogFile /var/log/conntrackd.log + #LogFile off + + # + # Syslog: on, off or a facility name (daemon (default) or local0..7) + # Default: off + # + #Syslog on # # Lockfile diff --git a/examples/sync/nack/node1/conntrackd.conf b/examples/sync/nack/node1/conntrackd.conf index 9a7d55f..ef9eb4a 100644 --- a/examples/sync/nack/node1/conntrackd.conf +++ b/examples/sync/nack/node1/conntrackd.conf @@ -65,9 +65,16 @@ General { HashLimit 65535 # - # Logfile + # Logfile: on, off, or a filename + # Default: on (/var/log/conntrackd.log) # - LogFile /var/log/conntrackd.log + #LogFile off + + # + # Syslog: on, off or a facility name (daemon (default) or local0..7) + # Default: off + # + #Syslog on # # Lockfile diff --git a/examples/sync/nack/node2/conntrackd.conf b/examples/sync/nack/node2/conntrackd.conf index cee16c8..c4d8a21 100644 --- a/examples/sync/nack/node2/conntrackd.conf +++ b/examples/sync/nack/node2/conntrackd.conf @@ -64,9 +64,16 @@ General { HashLimit 65535 # - # Logfile + # Logfile: on, off, or a filename + # Default: on (/var/log/conntrackd.log) # - LogFile /var/log/conntrackd.log + #LogFile off + + # + # Syslog: on, off or a facility name (daemon (default) or local0..7) + # Default: off + # + #Syslog on # # Lockfile diff --git a/examples/sync/persistent/node1/conntrackd.conf b/examples/sync/persistent/node1/conntrackd.conf index e80921b..d240fbb 100644 --- a/examples/sync/persistent/node1/conntrackd.conf +++ b/examples/sync/persistent/node1/conntrackd.conf @@ -70,9 +70,16 @@ General { HashLimit 65535 # - # Logfile + # Logfile: on, off, or a filename + # Default: on (/var/log/conntrackd.log) # - LogFile /var/log/conntrackd.log + #LogFile off + + # + # Syslog: on, off or a facility name (daemon (default) or local0..7) + # Default: off + # + #Syslog on # # Lockfile diff --git a/examples/sync/persistent/node2/conntrackd.conf b/examples/sync/persistent/node2/conntrackd.conf index ad4b040..d5a276e 100644 --- a/examples/sync/persistent/node2/conntrackd.conf +++ b/examples/sync/persistent/node2/conntrackd.conf @@ -70,9 +70,16 @@ General { HashLimit 65535 # - # Logfile + # Logfile: on, off, or a filename + # Default: on (/var/log/conntrackd.log) # - LogFile /var/log/conntrackd.log + #LogFile off + + # + # Syslog: on, off or a facility name (daemon (default) or local0..7) + # Default: off + # + #Syslog on # # Lockfile diff --git a/include/conntrackd.h b/include/conntrackd.h index e89fc79..fc15ebe 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -12,6 +12,7 @@ #include "state_helper.h" #include "linux_list.h" #include +#include /* UNIX facilities */ #define FLUSH_MASTER 0 /* flush kernel conntrack table */ @@ -29,6 +30,8 @@ #define DEFAULT_CONFIGFILE "/etc/conntrackd/conntrackd.conf" #define DEFAULT_LOCKFILE "/var/lock/conntrackd.lock" +#define DEFAULT_LOGFILE "/var/log/conntrackd.log" +#define DEFAULT_SYSLOG_FACILITY LOG_DAEMON enum { SYNC_MODE_PERSISTENT_BIT = 0, @@ -65,6 +68,7 @@ union inet_address { struct ct_conf { char logfile[FILENAME_MAXLEN]; + int syslog_facility; char lockfile[FILENAME_MAXLEN]; int hashsize; /* hashtable size */ struct mcast_conf mcast; /* multicast settings */ diff --git a/include/log.h b/include/log.h index 9ecff30..f6f450c 100644 --- a/include/log.h +++ b/include/log.h @@ -4,7 +4,7 @@ #include FILE *init_log(char *filename); -void dlog(FILE *fd, char *format, ...); +void dlog(FILE *fd, int priority, char *format, ...); void close_log(FILE *fd); #endif diff --git a/src/cache_iterators.c b/src/cache_iterators.c index 287f92f..24506e4 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -139,14 +139,14 @@ void cache_commit(struct cache *c) commit_exist = c->commit_exist - commit_exist; /* log results */ - dlog(STATE(log), "Committed %u new entries", commit_ok); + dlog(STATE(log), LOG_INFO, "Committed %u new entries", commit_ok); if (commit_exist) - dlog(STATE(log), "%u entries ignored, " - "already exist", commit_exist); + dlog(STATE(log), LOG_INFO, "%u entries ignored, " + "already exist", commit_exist); if (commit_fail) - dlog(STATE(log), "%u entries can't be " - "committed", commit_fail); + dlog(STATE(log), LOG_INFO, "%u entries can't be " + "committed", commit_fail); } static int do_flush(void *data1, void *data2) diff --git a/src/log.c b/src/log.c index 88cadea..5fea1c3 100644 --- a/src/log.c +++ b/src/log.c @@ -22,36 +22,74 @@ #include #include #include +#include "conntrackd.h" FILE *init_log(char *filename) { - FILE *fd; + FILE *fd = NULL; - fd = fopen(filename, "a+"); - if (fd == NULL) { - fprintf(stderr, "can't open log file `%s'\n", filename); - return NULL; + if (filename[0]) { + fd = fopen(filename, "a+"); + if (fd == NULL) { + fprintf(stderr, "can't open log file `%s'\n", filename); + return NULL; + } } + if (CONFIG(syslog_facility) != -1) + openlog(PACKAGE, LOG_PID, CONFIG(syslog_facility)); + return fd; } -void dlog(FILE *fd, char *format, ...) -{ - time_t t = time(NULL); - char *buf = ctime(&t); - va_list args; - - buf[strlen(buf)-1]='\0'; - va_start(args, format); - fprintf(fd, "[%s] (pid=%d) ", buf, getpid()); - vfprintf(fd, format, args); - va_end(args); - fprintf(fd, "\n"); - fflush(fd); +void dlog(FILE *fd, int priority, char *format, ...) + { + time_t t; + char *buf; + char *prio; + va_list args; + + if (fd) { + t = time(NULL); + buf = ctime(&t); + buf[strlen(buf)-1]='\0'; + switch (priority) { + case LOG_INFO: + prio = "info"; + break; + case LOG_NOTICE: + prio = "notice"; + break; + case LOG_WARNING: + prio = "warning"; + break; + case LOG_ERR: + prio = "ERROR"; + break; + default: + prio = "?"; + break; + } + va_start(args, format); + fprintf(fd, "[%s] (pid=%d) [%s] ", buf, getpid(), prio); + vfprintf(fd, format, args); + va_end(args); + fprintf(fd, "\n"); + fflush(fd); + } + + if (CONFIG(syslog_facility) != -1) { + va_start(args, format); + vsyslog(priority, format, args); + va_end(args); + } } void close_log(FILE *fd) { - fclose(fd); + if (fd != NULL) + fclose(fd); + + if (CONFIG(syslog_facility) != -1) + closelog(); } diff --git a/src/main.c b/src/main.c index 007b76e..712b572 100644 --- a/src/main.c +++ b/src/main.c @@ -244,10 +244,10 @@ int main(int argc, char *argv[]) } /* - * Setting up logfile + * Setting up logging */ STATE(log) = init_log(CONFIG(logfile)); - if (!STATE(log)) { + if (config_set && !STATE(log)) { fprintf(stdout, "can't open logfile `%s\n'", CONFIG(logfile)); exit(EXIT_FAILURE); } @@ -276,15 +276,15 @@ int main(int argc, char *argv[]) pid_t pid; if ((pid = fork()) == -1) { - dlog(STATE(log), "fork() failed: " - "%s", strerror(errno)); + dlog(STATE(log), LOG_ERR, "fork() failed: " + "%s", strerror(errno)); exit(EXIT_FAILURE); } else if (pid) exit(EXIT_SUCCESS); - dlog(STATE(log), "--- starting in daemon mode ---"); + dlog(STATE(log), LOG_INFO, "--- starting in daemon mode ---"); } else - dlog(STATE(log), "--- starting in console mode ---"); + dlog(STATE(log), LOG_INFO, "--- starting in console mode ---"); /* * initialization process diff --git a/src/netlink.c b/src/netlink.c index be5f82e..693646f 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -75,7 +75,7 @@ static int event_handler(enum nf_conntrack_msg_type type, update_traffic_stats(ct); break; default: - dlog(STATE(log), "received unknown msg from ctnetlink\n"); + dlog(STATE(log), LOG_WARNING, "unknown msg from ctnetlink\n"); break; } @@ -136,7 +136,7 @@ static int dump_handler(enum nf_conntrack_msg_type type, STATE(mode)->dump(ct); break; default: - dlog(STATE(log), "received unknown msg from ctnetlink"); + dlog(STATE(log), LOG_WARNING, "unknown msg from ctnetlink"); break; } return NFCT_CB_CONTINUE; @@ -169,7 +169,8 @@ void nl_resize_socket_buffer(struct nfct_handle *h) return; if (s > CONFIG(netlink_buffer_size_max_grown)) { - dlog(STATE(log), "WARNING: maximum netlink socket buffer " + dlog(STATE(log), LOG_WARNING, + "maximum netlink socket buffer " "size has been reached. We are likely to " "be losing events, this may lead to " "unsynchronized replicas. Please, consider " @@ -184,8 +185,9 @@ void nl_resize_socket_buffer(struct nfct_handle *h) CONFIG(netlink_buffer_size) = nfnl_rcvbufsiz(nfct_nfnlh(h), s); /* notify the sysadmin */ - dlog(STATE(log), "netlink socket buffer size has been set to %u bytes", - CONFIG(netlink_buffer_size)); + dlog(STATE(log), LOG_INFO, "netlink socket buffer size " + "has been set to %u bytes", + CONFIG(netlink_buffer_size)); } int nl_dump_conntrack_table(void) diff --git a/src/read_config_lex.l b/src/read_config_lex.l index 87e98d1..48c0409 100644 --- a/src/read_config_lex.l +++ b/src/read_config_lex.l @@ -42,7 +42,7 @@ ip6_part {hex_255}":"? ip6_form1 {ip6_part}{0,16}"::"{ip6_part}{0,16} ip6_form2 ({hex_255}":"){16}{hex_255} ip6 {ip6_form1}|{ip6_form2} -string [a-zA-Z0-9]* +string [a-zA-Z][a-zA-Z0-9]* persistent [P|p][E|e][R|r][S|s][I|i][S|s][T|t][E|e][N|n][T|T] nack [N|n][A|a][C|c][K|k] @@ -73,6 +73,7 @@ nack [N|n][A|a][C|c][K|k] "Backlog" { return T_BACKLOG; } "Group" { return T_GROUP; } "LogFile" { return T_LOG; } +"Syslog" { return T_SYSLOG; } "LockFile" { return T_LOCK; } "General" { return T_GENERAL; } "Sync" { return T_SYNC; } diff --git a/src/read_config_yy.y b/src/read_config_yy.y index de592d2..8bc83fe 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -25,6 +25,7 @@ #include #include "conntrackd.h" #include "ignore.h" +#include extern char *yytext; extern int yylineno; @@ -48,6 +49,7 @@ struct ct_conf conf; %token T_REPLICATE T_FOR T_IFACE %token T_ESTABLISHED T_SYN_SENT T_SYN_RECV T_FIN_WAIT %token T_CLOSE_WAIT T_LAST_ACK T_TIME_WAIT T_CLOSE T_LISTEN +%token T_SYSLOG %token T_IP T_PATH_VAL @@ -72,11 +74,56 @@ line : ignore_protocol | stats ; -log : T_LOG T_PATH_VAL +logfile_bool : T_LOG T_ON +{ + strncpy(conf.logfile, DEFAULT_LOGFILE, FILENAME_MAXLEN); +}; + +logfile_bool : T_LOG T_OFF +{ +}; + +logfile_path : T_LOG T_PATH_VAL { strncpy(conf.logfile, $2, FILENAME_MAXLEN); }; +syslog_bool : T_SYSLOG T_ON +{ + conf.syslog_facility = DEFAULT_SYSLOG_FACILITY; +}; + +syslog_bool : T_SYSLOG T_OFF +{ + conf.syslog_facility = -1; +} + +syslog_facility : T_SYSLOG T_STRING +{ + if (!strcmp($2, "daemon")) + conf.syslog_facility = LOG_DAEMON; + else if (!strcmp($2, "local0")) + conf.syslog_facility = LOG_LOCAL0; + else if (!strcmp($2, "local1")) + conf.syslog_facility = LOG_LOCAL1; + else if (!strcmp($2, "local2")) + conf.syslog_facility = LOG_LOCAL2; + else if (!strcmp($2, "local3")) + conf.syslog_facility = LOG_LOCAL3; + else if (!strcmp($2, "local4")) + conf.syslog_facility = LOG_LOCAL4; + else if (!strcmp($2, "local5")) + conf.syslog_facility = LOG_LOCAL5; + else if (!strcmp($2, "local6")) + conf.syslog_facility = LOG_LOCAL6; + else if (!strcmp($2, "local7")) + conf.syslog_facility = LOG_LOCAL7; + else { + fprintf(stderr, "'%s' is not a known syslog facility, ignoring.\n", $2); + return; + } +}; + lock : T_LOCK T_PATH_VAL { strncpy(conf.lockfile, $2, FILENAME_MAXLEN); @@ -461,7 +508,10 @@ general_list: general_line: hashsize | hashlimit - | log + | logfile_bool + | logfile_path + | syslog_facility + | syslog_bool | lock | unix_line | netlink_buffer_size @@ -516,6 +566,9 @@ init_config(char *filename) if (!fp) return -1; + /* Zero may be a valid facility */ + CONFIG(syslog_facility) = -1; + yyrestart(fp); yyparse(); fclose(fp); diff --git a/src/run.c b/src/run.c index 644f82e..9ce9923 100644 --- a/src/run.c +++ b/src/run.c @@ -40,7 +40,7 @@ void killer(int foo) STATE(mode)->kill(); destroy_alarm_scheduler(); unlink(CONFIG(lockfile)); - dlog(STATE(log), "------- shutdown received ----"); + dlog(STATE(log), LOG_INFO, "------- shutdown received ----"); close_log(STATE(log)); sigprocmask(SIG_UNBLOCK, &STATE(block), NULL); @@ -60,31 +60,31 @@ void local_handler(int fd, void *data) ret = read(fd, &type, sizeof(type)); if (ret == -1) { - dlog(STATE(log), "can't read from unix socket"); + dlog(STATE(log), LOG_INFO, "can't read from unix socket"); return; } if (ret == 0) { - dlog(STATE(log), "local request: nothing to process?"); + dlog(STATE(log), LOG_INFO, "local request: nothing received?"); return; } switch(type) { case FLUSH_MASTER: - dlog(STATE(log), "[DEPRECATED] `conntrackd -F' is deprecated. " - "Use conntrack -F instead."); + dlog(STATE(log), LOG_NOTICE, "`conntrackd -F' is deprecated. " + "Use conntrack -F instead."); if (fork() == 0) { execlp("conntrack", "conntrack", "-F", NULL); exit(EXIT_SUCCESS); } return; case RESYNC_MASTER: - dlog(STATE(log), "[REQ] resync with master table"); + dlog(STATE(log), LOG_NOTICE, "resync with master table"); nl_dump_conntrack_table(); return; } if (!STATE(mode)->local(fd, type, data)) - dlog(STATE(log), "[FAIL] unknown local request %d", type); + dlog(STATE(log), LOG_ERR, "unknown local request %d", type); } int init(int mode) @@ -105,30 +105,30 @@ int init(int mode) /* Initialization */ if (STATE(mode)->init() == -1) { - dlog(STATE(log), "[FAIL] initialization failed"); + dlog(STATE(log), LOG_ERR, "initialization failed"); return -1; } if (init_alarm_scheduler() == -1) { - dlog(STATE(log), "[FAIL] can't initialize alarm scheduler"); + dlog(STATE(log), LOG_ERR, "can't initialize alarm scheduler"); return -1; } /* local UNIX socket */ STATE(local) = local_server_create(&CONFIG(local)); if (!STATE(local)) { - dlog(STATE(log), "[FAIL] can't open unix socket!"); + dlog(STATE(log), LOG_ERR, "can't open unix socket!"); return -1; } if (nl_init_event_handler() == -1) { - dlog(STATE(log), "[FAIL] can't open netlink handler! " - "no ctnetlink kernel support?"); + dlog(STATE(log), LOG_ERR, "can't open netlink handler! " + "no ctnetlink kernel support?"); return -1; } if (nl_init_dump_handler() == -1) { - dlog(STATE(log), "[FAIL] can't open netlink handler! " + dlog(STATE(log), LOG_ERR, "can't open netlink handler! " "no ctnetlink kernel support?"); return -1; } @@ -152,7 +152,7 @@ int init(int mode) if (signal(SIGCHLD, child) == SIG_ERR) return -1; - dlog(STATE(log), "[OK] initialization completed"); + dlog(STATE(log), LOG_INFO, "initialization completed"); return 0; } diff --git a/src/stats-mode.c b/src/stats-mode.c index 65bab1b..1d68e02 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -32,7 +32,7 @@ static int init_stats(void) state.stats = malloc(sizeof(struct ct_stats_state)); if (!state.stats) { - dlog(STATE(log), "[FAIL] can't allocate memory for stats sync"); + dlog(STATE(log), LOG_ERR, "can't allocate memory for stats"); return -1; } memset(state.stats, 0, sizeof(struct ct_stats_state)); @@ -42,8 +42,8 @@ static int init_stats(void) CONFIG(family), NULL); if (!STATE_STATS(cache)) { - dlog(STATE(log), "[FAIL] can't allocate memory for the " - "external cache"); + dlog(STATE(log), LOG_ERR, "can't allocate memory for the " + "external cache"); return -1; } @@ -68,7 +68,7 @@ static int local_handler_stats(int fd, int type, void *data) cache_dump(STATE_STATS(cache), fd, NFCT_O_XML); break; case FLUSH_CACHE: - dlog(STATE(log), "[REQ] flushing caches"); + dlog(STATE(log), LOG_NOTICE, "flushing caches"); cache_flush(STATE_STATS(cache)); break; case KILL: @@ -122,7 +122,7 @@ static void overrun_stats() h = nfct_open(CONNTRACK, 0); if (!h) { - dlog(STATE(log), "can't open overrun handler"); + dlog(STATE(log), LOG_ERR, "can't open overrun handler"); return; } @@ -132,7 +132,8 @@ static void overrun_stats() ret = nfct_query(h, NFCT_Q_DUMP, &family); if (ret == -1) - dlog(STATE(log), "overrun query error %s", strerror(errno)); + dlog(STATE(log), LOG_ERR, + "overrun query error %s", strerror(errno)); nfct_close(h); } @@ -143,8 +144,8 @@ static void event_new_stats(struct nf_conntrack *ct) debug_ct(ct, "cache new"); } else { if (errno != EEXIST) { - dlog(STATE(log), "can't add to cache cache: " - "%s\n", strerror(errno)); + dlog(STATE(log), LOG_ERR, + "can't add to cache cache: %s\n", strerror(errno)); debug_ct(ct, "can't add"); } } diff --git a/src/sync-mode.c b/src/sync-mode.c index 917a3b2..e48b121 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -77,7 +77,7 @@ retry: debug_ct(ct, "can't destroy"); break; default: - dlog(STATE(log), "mcast received unknown query %d\n", query); + dlog(STATE(log), LOG_ERR, "mcast unknown query %d\n", query); break; } } @@ -97,7 +97,7 @@ static void mcast_handler() struct nethdr *net = (struct nethdr *) ptr; if (ntohs(net->len) > remain) { - dlog(STATE(log), "fragmented messages"); + dlog(STATE(log), LOG_ERR, "fragmented messages"); break; } @@ -121,7 +121,7 @@ static int init_sync(void) state.sync = malloc(sizeof(struct ct_sync_state)); if (!state.sync) { - dlog(STATE(log), "[FAIL] can't allocate memory for state sync"); + dlog(STATE(log), LOG_ERR, "can't allocate memory for sync"); return -1; } memset(state.sync, 0, sizeof(struct ct_sync_state)); @@ -142,8 +142,8 @@ static int init_sync(void) STATE_SYNC(sync)->internal_cache_extra); if (!STATE_SYNC(internal)) { - dlog(STATE(log), "[FAIL] can't allocate memory for " - "the internal cache"); + dlog(STATE(log), LOG_ERR, "can't allocate memory for " + "the internal cache"); return -1; } @@ -154,27 +154,27 @@ static int init_sync(void) NULL); if (!STATE_SYNC(external)) { - dlog(STATE(log), "[FAIL] can't allocate memory for the " - "external cache"); + dlog(STATE(log), LOG_ERR, "can't allocate memory for the " + "external cache"); return -1; } /* multicast server to receive events from the wire */ STATE_SYNC(mcast_server) = mcast_server_create(&CONFIG(mcast)); if (STATE_SYNC(mcast_server) == NULL) { - dlog(STATE(log), "[FAIL] can't open multicast server!"); + dlog(STATE(log), LOG_ERR, "can't open multicast server!"); return -1; } /* multicast client to send events on the wire */ STATE_SYNC(mcast_client) = mcast_client_create(&CONFIG(mcast)); if (STATE_SYNC(mcast_client) == NULL) { - dlog(STATE(log), "[FAIL] can't open client multicast socket!"); + dlog(STATE(log), LOG_ERR, "can't open client multicast socket"); return -1; } if (mcast_buffered_init(&CONFIG(mcast)) == -1) { - dlog(STATE(log), "[FAIL] can't init tx buffer!"); + dlog(STATE(log), LOG_ERR, "can't init tx buffer!"); return -1; } @@ -269,13 +269,13 @@ static int local_handler_sync(int fd, int type, void *data) case COMMIT: ret = fork(); if (ret == 0) { - dlog(STATE(log), "[REQ] committing external cache"); + dlog(STATE(log), LOG_INFO, "committing external cache"); cache_commit(STATE_SYNC(external)); exit(EXIT_SUCCESS); } break; case FLUSH_CACHE: - dlog(STATE(log), "[REQ] flushing caches"); + dlog(STATE(log), LOG_INFO, "flushing caches"); cache_flush(STATE_SYNC(internal)); cache_flush(STATE_SYNC(external)); break; @@ -398,7 +398,7 @@ static void overrun_sync() h = nfct_open(CONNTRACK, 0); if (!h) { - dlog(STATE(log), "can't open overrun handler"); + dlog(STATE(log), LOG_ERR, "can't open overrun handler"); return; } @@ -406,7 +406,8 @@ static void overrun_sync() ret = nfct_query(h, NFCT_Q_DUMP, &family); if (ret == -1) - dlog(STATE(log), "overrun query error %s", strerror(errno)); + dlog(STATE(log), LOG_ERR, + "overrun query error %s", strerror(errno)); nfct_callback_unregister(h); @@ -436,8 +437,8 @@ retry: goto retry; } - dlog(STATE(log), "can't add to internal cache: " - "%s\n", strerror(errno)); + dlog(STATE(log), LOG_ERR, "can't add to internal cache: " + "%s\n", strerror(errno)); debug_ct(ct, "can't add"); } } diff --git a/src/sync-nack.c b/src/sync-nack.c index dbda0a7..fa61be4 100644 --- a/src/sync-nack.c +++ b/src/sync-nack.c @@ -74,13 +74,13 @@ static int nack_init() { tx_queue = buffer_create(CONFIG(resend_buffer_size)); if (tx_queue == NULL) { - dlog(STATE(log), "[FAIL] cannot create tx buffer"); + dlog(STATE(log), LOG_ERR, "cannot create tx buffer"); return -1; } rs_queue = buffer_create(CONFIG(resend_buffer_size)); if (rs_queue == NULL) { - dlog(STATE(log), "[FAIL] cannot create rs buffer"); + dlog(STATE(log), LOG_ERR, "cannot create rs buffer"); return -1; } @@ -125,11 +125,11 @@ static int nack_local(int fd, int type, void *data) switch(type) { case REQUEST_DUMP: - dlog(STATE(log), "[REQ] request resync"); + dlog(STATE(log), LOG_NOTICE, "request resync"); tx_queue_add_ctlmsg(NET_F_RESYNC, 0, 0); break; case SEND_BULK: - dlog(STATE(log), "[REQ] sending bulk update"); + dlog(STATE(log), LOG_NOTICE, "sending bulk update"); cache_iterate(STATE_SYNC(internal), NULL, do_cache_to_tx); break; default: -- cgit v1.2.3 From 3c5e35974c65f4470e6543c2cc772c0f1824dc44 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Sun, 25 Nov 2007 18:08:02 +0000 Subject: Add CacheWriteThrough clause: external cache write through policy. This feature is particularly useful for active-active setup without connection persistency, ie. you cannot know which firewall would filter a packet that belongs to a connection. --- ChangeLog | 1 + examples/sync/nack/node1/conntrackd.conf | 8 ++++ examples/sync/nack/node2/conntrackd.conf | 8 ++++ examples/sync/persistent/node1/conntrackd.conf | 8 ++++ examples/sync/persistent/node2/conntrackd.conf | 8 ++++ include/cache.h | 4 ++ include/conntrackd.h | 1 + src/Makefile.am | 2 +- src/cache.c | 17 +++++---- src/cache_iterators.c | 21 +--------- src/cache_wt.c | 53 ++++++++++++++++++++++++++ src/netlink.c | 31 +++++++++++++++ src/read_config_lex.l | 1 + src/read_config_yy.y | 13 ++++++- src/sync-mode.c | 22 ++++++++--- 15 files changed, 163 insertions(+), 35 deletions(-) create mode 100644 src/cache_wt.c (limited to 'src') diff --git a/ChangeLog b/ChangeLog index c085175..46242c5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -7,6 +7,7 @@ o include kernel options and Fedora comments in the INSTALL file = conntrackd = o Remove window tracking disabling limitation (requires Linux kernel >= 2.6.22) o syslog support (based on patch from Simon Lodal) +o add CacheWriteThrough clause: external cache write through policy version 0.9.5 (2007/07/29) ------------------------------ diff --git a/examples/sync/nack/node1/conntrackd.conf b/examples/sync/nack/node1/conntrackd.conf index ef9eb4a..4fc8f22 100644 --- a/examples/sync/nack/node1/conntrackd.conf +++ b/examples/sync/nack/node1/conntrackd.conf @@ -47,6 +47,14 @@ Sync { # FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN. # # Replicate ESTABLISHED TIME_WAIT for TCP + + # If you have a multiprimary setup (active-active) without connection + # persistency, ie. you can't know which firewall handles a packet + # that is part of a connection, then you need direct commit of + # conntrack entries to the kernel conntrack table. OSPF setups must + # set on this option. Default is Off. + # + # CacheWriteThrough On } # diff --git a/examples/sync/nack/node2/conntrackd.conf b/examples/sync/nack/node2/conntrackd.conf index c4d8a21..43ebd77 100644 --- a/examples/sync/nack/node2/conntrackd.conf +++ b/examples/sync/nack/node2/conntrackd.conf @@ -46,6 +46,14 @@ Sync { # FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN. # # Replicate ESTABLISHED TIME_WAIT for TCP + + # If you have a multiprimary setup (active-active) without connection + # persistency, ie. you can't know which firewall handles a packet + # that is part of a connection, then you need direct commit of + # conntrack entries to the kernel conntrack table. OSPF setups must + # set on this option. Default is Off. + # + # CacheWriteThrough On } # diff --git a/examples/sync/persistent/node1/conntrackd.conf b/examples/sync/persistent/node1/conntrackd.conf index d240fbb..a55608b 100644 --- a/examples/sync/persistent/node1/conntrackd.conf +++ b/examples/sync/persistent/node1/conntrackd.conf @@ -52,6 +52,14 @@ Sync { # FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN. # # Replicate ESTABLISHED TIME_WAIT for TCP + + # If you have a multiprimary setup (active-active) without connection + # persistency, ie. you can't know which firewall handles a packet + # that is part of a connection, then you need direct commit of + # conntrack entries to the kernel conntrack table. OSPF setups must + # set on this option. Default is Off. + # + # CacheWriteThrough On } # diff --git a/examples/sync/persistent/node2/conntrackd.conf b/examples/sync/persistent/node2/conntrackd.conf index d5a276e..32416d0 100644 --- a/examples/sync/persistent/node2/conntrackd.conf +++ b/examples/sync/persistent/node2/conntrackd.conf @@ -52,6 +52,14 @@ Sync { # FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN. # # Replicate ESTABLISHED TIME_WAIT for TCP + + # If you have a multiprimary setup (active-active) without connection + # persistency, ie. you can't know which firewall handles a packet + # that is part of a connection, then you need direct commit of + # conntrack entries to the kernel conntrack table. OSPF setups must + # set on this option. Default is Off. + # + # CacheWriteThrough On } # diff --git a/include/cache.h b/include/cache.h index e755dbe..f5e9576 100644 --- a/include/cache.h +++ b/include/cache.h @@ -14,6 +14,9 @@ enum { LIFETIME_FEATURE = 2, LIFETIME = (1 << LIFETIME_FEATURE), + WRITE_THROUGH_FEATURE = 3, + WRITE_THROUGH = (1 << WRITE_THROUGH_FEATURE), + __CACHE_MAX_FEATURE }; #define CACHE_MAX_FEATURE __CACHE_MAX_FEATURE @@ -31,6 +34,7 @@ struct cache_feature { extern struct cache_feature lifetime_feature; extern struct cache_feature timer_feature; +extern struct cache_feature writethrough_feature; #define CACHE_MAX_NAMELEN 32 diff --git a/include/conntrackd.h b/include/conntrackd.h index fc15ebe..2722f00 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -86,6 +86,7 @@ struct ct_conf { int family; /* protocol family */ unsigned int resend_buffer_size;/* NACK protocol */ unsigned int window_size; + int cache_write_through; }; #define STATE(x) st.x diff --git a/src/Makefile.am b/src/Makefile.am index 83511fa..8f5c620 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -14,7 +14,7 @@ conntrackd_SOURCES = alarm.c main.c run.c hash.c buffer.c \ local.c log.c mcast.c netlink.c \ ignore_pool.c \ cache.c cache_iterators.c \ - cache_lifetime.c cache_timer.c \ + cache_lifetime.c cache_timer.c cache_wt.c \ sync-mode.c sync-notrack.c sync-nack.c \ traffic_stats.c stats-mode.c \ network.c \ diff --git a/src/cache.c b/src/cache.c index 1e20d95..80cde01 100644 --- a/src/cache.c +++ b/src/cache.c @@ -110,6 +110,7 @@ static int compare6(const void *data1, const void *data2) struct cache_feature *cache_feature[CACHE_MAX_FEATURE] = { [TIMER_FEATURE] = &timer_feature, [LIFETIME_FEATURE] = &lifetime_feature, + [WRITE_THROUGH_FEATURE] = &writethrough_feature, }; struct cache *cache_create(char *name, @@ -263,14 +264,6 @@ static struct us_conntrack *__update(struct cache *c, struct nf_conntrack *ct) int i; void *data = u->data; - for (i = 0; i < c->num_features; i++) { - c->features[i]->update(u, data); - data += c->features[i]->size; - } - - if (c->extra && c->extra->update) - c->extra->update(u, ((void *) u) + c->extra_offset); - if (nfct_attr_is_set(ct, ATTR_STATUS)) nfct_set_attr_u32(u->ct, ATTR_STATUS, nfct_get_attr_u32(ct, ATTR_STATUS)); @@ -281,6 +274,14 @@ static struct us_conntrack *__update(struct cache *c, struct nf_conntrack *ct) nfct_set_attr_u32(u->ct, ATTR_TIMEOUT, nfct_get_attr_u32(ct, ATTR_TIMEOUT)); + for (i = 0; i < c->num_features; i++) { + c->features[i]->update(u, data); + data += c->features[i]->size; + } + + if (c->extra && c->extra->update) + c->extra->update(u, ((void *) u) + c->extra_offset); + return u; } return NULL; diff --git a/src/cache_iterators.c b/src/cache_iterators.c index 24506e4..c29100c 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -78,36 +78,17 @@ void cache_dump(struct cache *c, int fd, int type) static int do_commit(void *data1, void *data2) { int ret; - u_int8_t flags; struct cache *c = data1; struct us_conntrack *u = data2; struct nf_conntrack *ct = u->ct; - /* XXX: related connections */ - if (nfct_attr_is_set(ct, ATTR_STATUS)) { - u_int32_t status = nfct_get_attr_u32(ct, ATTR_STATUS); - status &= ~IPS_EXPECTED; - nfct_set_attr_u32(ct, ATTR_STATUS, status); - } - - nfct_setobjopt(ct, NFCT_SOPT_SETUP_REPLY); - /* * Set a reduced timeout for candidate-to-be-committed * conntracks that live in the external cache */ nfct_set_attr_u32(ct, ATTR_TIMEOUT, CONFIG(commit_timeout)); - /* - * TCP flags to overpass window tracking for recovered connections - */ - flags = IP_CT_TCP_FLAG_BE_LIBERAL | IP_CT_TCP_FLAG_SACK_PERM; - nfct_set_attr_u8(ct, ATTR_TCP_FLAGS_ORIG, flags); - nfct_set_attr_u8(ct, ATTR_TCP_MASK_ORIG, flags); - nfct_set_attr_u8(ct, ATTR_TCP_FLAGS_REPL, flags); - nfct_set_attr_u8(ct, ATTR_TCP_MASK_REPL, flags); - - ret = nfct_query(STATE(dump), NFCT_Q_CREATE_UPDATE, ct); + ret = nl_create_conntrack(ct); if (ret == -1) { switch(errno) { case EEXIST: diff --git a/src/cache_wt.c b/src/cache_wt.c new file mode 100644 index 0000000..2a9d8e7 --- /dev/null +++ b/src/cache_wt.c @@ -0,0 +1,53 @@ +/* + * (C) 2007 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include "conntrackd.h" +#include "us-conntrack.h" +#include "cache.h" + +static void add_update(struct us_conntrack *u) +{ + char __ct[nfct_maxsize()]; + struct nf_conntrack *ct = (struct nf_conntrack *) __ct; + + memcpy(ct, u->ct, nfct_maxsize()); + + nl_create_conntrack(ct); +} + +static void writethrough_add(struct us_conntrack *u, void *data) +{ + add_update(u); +} + +static void writethrough_update(struct us_conntrack *u, void *data) +{ + add_update(u); +} + +static void writethrough_destroy(struct us_conntrack *u, void *data) +{ + nl_destroy_conntrack(u->ct); +} + +struct cache_feature writethrough_feature = { + .add = writethrough_add, + .update = writethrough_update, + .destroy = writethrough_destroy, +}; diff --git a/src/netlink.c b/src/netlink.c index 693646f..d453fe1 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -194,3 +194,34 @@ int nl_dump_conntrack_table(void) { return nfct_query(STATE(dump), NFCT_Q_DUMP, &CONFIG(family)); } + +/* This function modifies the conntrack passed as argument! */ +int nl_create_conntrack(struct nf_conntrack *ct) +{ + u_int8_t flags; + + /* XXX: related connections */ + if (nfct_attr_is_set(ct, ATTR_STATUS)) { + u_int32_t status = nfct_get_attr_u32(ct, ATTR_STATUS); + status &= ~IPS_EXPECTED; + nfct_set_attr_u32(ct, ATTR_STATUS, status); + } + + nfct_setobjopt(ct, NFCT_SOPT_SETUP_REPLY); + + /* + * TCP flags to overpass window tracking for recovered connections + */ + flags = IP_CT_TCP_FLAG_BE_LIBERAL | IP_CT_TCP_FLAG_SACK_PERM; + nfct_set_attr_u8(ct, ATTR_TCP_FLAGS_ORIG, flags); + nfct_set_attr_u8(ct, ATTR_TCP_MASK_ORIG, flags); + nfct_set_attr_u8(ct, ATTR_TCP_FLAGS_REPL, flags); + nfct_set_attr_u8(ct, ATTR_TCP_MASK_REPL, flags); + + return nfct_query(STATE(dump), NFCT_Q_CREATE_UPDATE, ct); +} + +int nl_destroy_conntrack(struct nf_conntrack *ct) +{ + return nfct_query(STATE(dump), NFCT_Q_DESTROY, ct); +} diff --git a/src/read_config_lex.l b/src/read_config_lex.l index 48c0409..844cae1 100644 --- a/src/read_config_lex.l +++ b/src/read_config_lex.l @@ -90,6 +90,7 @@ nack [N|n][A|a][C|c][K|k] "ACKWindowSize" { return T_WINDOWSIZE; } "Replicate" { return T_REPLICATE; } "for" { return T_FOR; } +"CacheWriteThrough" { return T_WRITE_THROUGH; } "SYN_SENT" { return T_SYN_SENT; } "SYN_RECV" { return T_SYN_RECV; } "ESTABLISHED" { return T_ESTABLISHED; } diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 8bc83fe..e5ce195 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -49,7 +49,7 @@ struct ct_conf conf; %token T_REPLICATE T_FOR T_IFACE %token T_ESTABLISHED T_SYN_SENT T_SYN_RECV T_FIN_WAIT %token T_CLOSE_WAIT T_LAST_ACK T_TIME_WAIT T_CLOSE T_LISTEN -%token T_SYSLOG +%token T_SYSLOG T_WRITE_THROUGH %token T_IP T_PATH_VAL @@ -366,6 +366,7 @@ sync_line: refreshtime | sync_mode_nack | listen_to | state_replication + | cache_writethrough ; sync_mode_persistent: T_SYNC_MODE T_PERSISTENT '{' sync_mode_persistent_list '}' @@ -500,6 +501,16 @@ tcp_state: T_LISTEN state_helper_register(&tcp_state_helper, TCP_CONNTRACK_LISTEN); }; +cache_writethrough: T_WRITE_THROUGH T_ON +{ + conf.cache_write_through = 1; +}; + +cache_writethrough: T_WRITE_THROUGH T_OFF +{ + conf.cache_write_through = 0; +}; + general: T_GENERAL '{' general_list '}'; general_list: diff --git a/src/sync-mode.c b/src/sync-mode.c index e48b121..8a19ac5 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -147,6 +147,10 @@ static int init_sync(void) return -1; } + /* straight forward commit of conntrack to kernel space */ + if (CONFIG(cache_write_through)) + STATE_SYNC(sync)->external_cache_flags |= WRITE_THROUGH; + STATE_SYNC(external) = cache_create("external", STATE_SYNC(sync)->external_cache_flags, @@ -301,8 +305,10 @@ static int local_handler_sync(int fd, int type, void *data) static void dump_sync(struct nf_conntrack *ct) { + if (!CONFIG(cache_write_through)) + nfct_attr_unset(ct, ATTR_TIMEOUT); + /* This is required by kernels < 2.6.20 */ - nfct_attr_unset(ct, ATTR_TIMEOUT); nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES); nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS); nfct_attr_unset(ct, ATTR_REPL_COUNTER_BYTES); @@ -339,8 +345,10 @@ static int overrun_cb(enum nf_conntrack_msg_type type, if (ignore_conntrack(ct)) return NFCT_CB_CONTINUE; + if (!CONFIG(cache_write_through)) + nfct_attr_unset(ct, ATTR_TIMEOUT); + /* This is required by kernels < 2.6.20 */ - nfct_attr_unset(ct, ATTR_TIMEOUT); nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES); nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS); nfct_attr_unset(ct, ATTR_REPL_COUNTER_BYTES); @@ -420,12 +428,14 @@ static void event_new_sync(struct nf_conntrack *ct) { struct us_conntrack *u; + if (!CONFIG(cache_write_through)) + nfct_attr_unset(ct, ATTR_TIMEOUT); + /* required by linux kernel <= 2.6.20 */ nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES); nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS); nfct_attr_unset(ct, ATTR_REPL_COUNTER_BYTES); nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); - nfct_attr_unset(ct, ATTR_TIMEOUT); retry: if ((u = cache_add(STATE_SYNC(internal), ct))) { mcast_send_sync(u, ct, NFCT_Q_CREATE); @@ -447,7 +457,8 @@ static void event_update_sync(struct nf_conntrack *ct) { struct us_conntrack *u; - nfct_attr_unset(ct, ATTR_TIMEOUT); + if (!CONFIG(cache_write_through)) + nfct_attr_unset(ct, ATTR_TIMEOUT); if ((u = cache_update_force(STATE_SYNC(internal), ct)) == NULL) { debug_ct(ct, "can't update"); @@ -459,7 +470,8 @@ static void event_update_sync(struct nf_conntrack *ct) static int event_destroy_sync(struct nf_conntrack *ct) { - nfct_attr_unset(ct, ATTR_TIMEOUT); + if (!CONFIG(cache_write_through)) + nfct_attr_unset(ct, ATTR_TIMEOUT); if (cache_del(STATE_SYNC(internal), ct)) { mcast_send_sync(NULL, ct, NFCT_Q_DESTROY); -- cgit v1.2.3 From a2eb348ebb6bb3172aa46dd132befe2a24c2d302 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Fri, 21 Dec 2007 13:20:04 +0000 Subject: = conntrack = o fix missing `-g' and `-n' options in getopt_long control string o add support for secmark (requires Linux kernel >= 2.6.25) o add mark and secmark information to the manpage o cleanup error message = conntrackd = o add support for secmark (requires Linux kernel >= 2.6.25) o add conntrackd (8) manpage --- ChangeLog | 8 ++++++ Makefile.am | 2 +- TODO | 42 ++++++++++++++------------- configure.in | 2 +- conntrack.8 | 5 ++++ conntrackd.8 | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++ include/conntrack.h | 5 +++- src/build.c | 2 ++ src/conntrack.c | 55 +++++++++++++++++++++--------------- src/parse.c | 1 + 10 files changed, 158 insertions(+), 45 deletions(-) create mode 100644 conntrackd.8 (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 46242c5..9d8e753 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,10 +4,18 @@ version 0.9.6 (yet unreleased) o fix compilation problem due to missing headers (Krisztian Kovacs) o include kernel options and Fedora comments in the INSTALL file += conntrack = +o fix missing `-g' and `-n' options in getopt_long control string +o add support for secmark (requires Linux kernel >= 2.6.25) +o add mark and secmark information to the manpage +o cleanup error message + = conntrackd = o Remove window tracking disabling limitation (requires Linux kernel >= 2.6.22) o syslog support (based on patch from Simon Lodal) o add CacheWriteThrough clause: external cache write through policy +o add support for secmark (requires Linux kernel >= 2.6.25) +o add conntrackd (8) manpage version 0.9.5 (2007/07/29) ------------------------------ diff --git a/Makefile.am b/Makefile.am index 239eedf..3abf2cc 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4,7 +4,7 @@ include Make_global.am # have all needed files, that a GNU package needs AUTOMAKE_OPTIONS = foreign dist-bzip2 1.6 -man_MANS = conntrack.8 +man_MANS = conntrack.8 conntrackd.8 EXTRA_DIST = $(man_MANS) Make_global.am ChangeLog TODO examples SUBDIRS = extensions src diff --git a/TODO b/TODO index 482b677..7f5b949 100644 --- a/TODO +++ b/TODO @@ -2,28 +2,32 @@ There are several tasks that are pending to be done, I have classified them by dificulty levels: = Relatively easy = - * add syslog support (based on Simon Lodal's patch) - * improve shell scripts for keepalived/heartbeat: *really* important - * use NACK based protocol, feedback: call pablo :-) - * manpage for conntrackd(8) - * use the floating priority feature in keepalived to avoid premature - take over. + [ ] improve shell scripts for keepalived/heartbeat: *really* important + [ ] NACK as default protocol + [ ] rename persistent to alarm + [X] manpage for conntrackd(8) + [ ] add scripts to use the floating priority feature in keepalived to avoid + premature take over. + [ ] ignorepool with unlimited size and ignore networks + [ ] selective conntracks removal + [ ] debian/rpm packages + [ ] improve website + [ ] Dumazet improvement hashtable (multiply vs. divide) + [X] add secmark support = Requires some work = - * study better keepalived transitions - * test/fix ipv6 support - * have a look at open issues - * implement support for TCP window tracking (patches are on the table) at - the moment you have to disable it: + [ ] study better keepalived transitions + [ ] test/fix ipv6 support + [ ] add support setup related conntracks + [ ] NAT sequence adjustment support - echo 1 > /proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_be_liberal - -= Requires kernel patches = - * setup master conntrack to match IPCT_RELATED - -= Open issues = - * unsupported iptables matches: += Open issues that won't be ever resolved = + * unsupported stateful iptables matches: * connbytes: probably the persistent may support it * recent: requires further study * quota: private data counters - * connection tracking NAT helpers: sequence adjustment issues (?) + += conntrack = + * add support for -D --dport 1000 + * improve error messages + * add support for SCTP (requires kernel >= 2.6.25) diff --git a/configure.in b/configure.in index 9400e37..bcd43f2 100644 --- a/configure.in +++ b/configure.in @@ -18,7 +18,7 @@ esac dnl Dependencies LIBNFNETLINK_REQUIRED=0.0.25 -LIBNETFILTER_CONNTRACK_REQUIRED=0.0.82 +LIBNETFILTER_CONNTRACK_REQUIRED=0.0.87 PKG_CHECK_MODULES(LIBNFNETLINK, libnfnetlink >= $LIBNFNETLINK_REQUIRED,, AC_MSG_ERROR(Cannot find libnfnetlink >= $LIBNFNETLINK_REQUIRED)) diff --git a/conntrack.8 b/conntrack.8 index d095d6c..0924888 100644 --- a/conntrack.8 +++ b/conntrack.8 @@ -106,6 +106,11 @@ This option is only required in conjunction with "-L, --dump". If this option is .TP .BI "-t, --timeout " "TIMEOUT" Specify the timeout. +.BI "-m, --mark " "MARK" +Specify the conntrack mark. +.TP +.BI "-c, --secmark " "SECMARK" +Specify the conntrack selinux security mark. .TP .BI "-u, --status " "[ASSURED|SEEN_REPLY|UNSET][,...]" Specify the conntrack status. diff --git a/conntrackd.8 b/conntrackd.8 new file mode 100644 index 0000000..8e2f2cc --- /dev/null +++ b/conntrackd.8 @@ -0,0 +1,81 @@ +.TH CONNTRACKD 8 "Dec 21, 2007" "" "" + +.\" Man page written by Pablo Neira Ayuso (Dec 2007) + +.SH NAME +conntrackd \- netfilter connection tracking userspace daemon +.SH SYNOPSIS +.BR "conntrackd [options]" +.SH DESCRIPTION +.B conntrackd +provides a userspace daemon for the netfilter connection tracking system. This daemon synchronizes connection tracking states among several replica firewalls. Thus, +.B conntrackd +can be used to implement highly available stateful firewalls. The daemon fully supports Primary-Backup and Multiprimary setups for both symmetric and asymmetric paths. It can also be used as statistics collector. +.SH OPTIONS +The options recognized by +.B conntrackd +can be divided into several different groups. +.SS MODES +These options specify the particular operation mode in which conntrackd runs. Only one of them can be specified at any given time. +.TP +.BI "-d " +Run conntrackd in daemon mode. This option can be combined with "-S" +.TP +.BI "-S " +Run conntrackd in statistics mode. Default mode is synchronization mode, so if you want to use +.B conntrackd +in statistics mode, you have to pass this option +.SS CLIENT COMMANDS +.B conntrackd +can be used in client mode to request several information and operations to a running daemon +.TP +.BI "-i " +Dump the internal cache, i.e. show local states +.TP +.BI "-e " +Dump the external cache, i.e. show foreign states +.TP +.BI "-x " +Display output in XML format. This option is only valid in combination +with "-i" and "-e" parameters. +.TP +.BI "-f " +Flush the internal and the external cache +.TP +.BI "-k " +Kill the daemon +.TP +.BI "-s " +Dump statistics +.TP +.BI "-R " +Force a resync against the kernel connection tracking table +.SH DIAGNOSTICS +The exit code is 0 for correct function. Errors cause an exit code of 1. +.SH EXAMPLES +.TP +.B conntrackd \-d +Runs conntrackd in daemon and synchronization mode +.TP +.B conntrackd \-i +Dumps the states held in the internal cache, i.e. those handled by this firewall +.TP +.B conntrackd \-e +Dumps the states held in the external cache, i.e. those handled by other replica firewalls +.TP +.B conntrackd \-c +Commits the internal cache into the kernel connection tracking system. This is used to inject the state so that the connections can be recovered during the failover. +.SH DEPENDENCIES +This daemon requires a Linux kernel version >= 2.6.18. TCP window tracking support requires >= 2.6.22, otherwise you have to disable it. Helpers are fully supported since >= 2.6.25, however, if you use any previous version, depending on the protocol helper and your setup (e.g. if you setup performs NAT sequence adjustments or not), your help connection may be successfully recovered. +.TP +There are several unsupported stateful iptables matches such as recent, connbytes and the quota matches which gather internal information to operate. Since that information does not belong to the domain of the connection tracking system, connections affected by those matches may not be fully recovered during the takeover. +.SH SEE ALSO +.BR conntrack (8), iptables (8) +.br +.BR "http://people.netfilter.org/pablo/conntrack-tools/" +.SH AUTHORS +Pablo Neira Ayuso wrote and maintains the conntrackd tool +.TP +Please send bug reports to . Subscription is required. +.PP +Man page written by Pablo Neira Ayuso . diff --git a/include/conntrack.h b/include/conntrack.h index 5edc0e9..1b2581e 100644 --- a/include/conntrack.h +++ b/include/conntrack.h @@ -127,7 +127,10 @@ enum options { CT_OPT_OUTPUT_BIT = 19, CT_OPT_OUTPUT = (1 << CT_OPT_OUTPUT_BIT), - CT_OPT_MAX = CT_OPT_OUTPUT_BIT + CT_OPT_SECMARK_BIT = 20, + CT_OPT_SECMARK = (1 << CT_OPT_SECMARK_BIT), + + CT_OPT_MAX = CT_OPT_SECMARK_BIT }; #define NUMBER_OF_OPT CT_OPT_MAX+1 diff --git a/src/build.c b/src/build.c index 981548e..109b26e 100644 --- a/src/build.c +++ b/src/build.c @@ -97,6 +97,8 @@ void build_netpld(struct nf_conntrack *ct, struct netpld *pld, int query) __build_u32(ct, pld, ATTR_TIMEOUT); if (nfct_attr_is_set(ct, ATTR_MARK)) __build_u32(ct, pld, ATTR_MARK); + if (nfct_attr_is_set(ct, ATTR_SECMARK)) + __build_u32(ct, pld, ATTR_SECMARK); if (nfct_attr_is_set(ct, ATTR_STATUS)) __build_u32(ct, pld, ATTR_STATUS); diff --git a/src/conntrack.c b/src/conntrack.c index 165809b..65dc4a7 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -67,7 +67,7 @@ static const char cmd_need_param[NUMBER_OF_CMD] static const char *optflags[NUMBER_OF_OPT] = { "src","dst","reply-src","reply-dst","protonum","timeout","status","zero", "event-mask","tuple-src","tuple-dst","mask-src","mask-dst","nat-range","mark", -"id","family","src-nat","dst-nat","output" }; +"id","family","src-nat","dst-nat","output","secmark"}; static struct option original_opts[] = { {"dump", 2, 0, 'L'}, @@ -96,6 +96,7 @@ static struct option original_opts[] = { {"mask-dst", 1, 0, '}'}, {"nat-range", 1, 0, 'a'}, /* deprecated */ {"mark", 1, 0, 'm'}, + {"secmark", 1, 0, 'c'}, {"id", 2, 0, 'i'}, /* deprecated */ {"family", 1, 0, 'f'}, {"src-nat", 2, 0, 'n'}, @@ -122,22 +123,22 @@ static unsigned int global_option_offset = 0; static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = /* Well, it's better than "Re: Linux vs FreeBSD" */ { - /* s d r q p t u z e [ ] { } a m i f n g o */ -/*CT_LIST*/ {2,2,2,2,2,0,0,2,0,0,0,0,0,0,2,2,2,2,2,2}, -/*CT_CREATE*/ {2,2,2,2,1,1,1,0,0,0,0,0,0,2,2,0,0,2,2,0}, -/*CT_UPDATE*/ {2,2,2,2,1,2,2,0,0,0,0,0,0,0,2,2,0,0,0,0}, -/*CT_DELETE*/ {2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0}, -/*CT_GET*/ {2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,2,0,0,0,2}, -/*CT_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*CT_EVENT*/ {2,2,2,2,2,0,0,0,2,0,0,0,0,0,2,0,0,2,2,2}, -/*VERSION*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*HELP*/ {0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*EXP_LIST*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,0,0,0}, -/*EXP_CREATE*/{1,1,2,2,1,1,2,0,0,1,1,1,1,0,0,0,0,0,0,0}, -/*EXP_DELETE*/{1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*EXP_GET*/ {1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*EXP_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*EXP_EVENT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + /* s d r q p t u z e [ ] { } a m i f n g o c */ +/*CT_LIST*/ {2,2,2,2,2,0,0,2,0,0,0,0,0,0,2,2,2,2,2,2,2}, +/*CT_CREATE*/ {2,2,2,2,1,1,1,0,0,0,0,0,0,2,2,0,0,2,2,0,2}, +/*CT_UPDATE*/ {2,2,2,2,1,2,2,0,0,0,0,0,0,0,2,2,0,0,0,0,2}, +/*CT_DELETE*/ {2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0}, +/*CT_GET*/ {2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,2,0,0,0,2,0}, +/*CT_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*CT_EVENT*/ {2,2,2,2,2,0,0,0,2,0,0,0,0,0,2,0,0,2,2,2,2}, +/*VERSION*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*HELP*/ {0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*EXP_LIST*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,0,0,0,0}, +/*EXP_CREATE*/{1,1,2,2,1,1,2,0,0,1,1,1,1,0,0,0,0,0,0,0,0}, +/*EXP_DELETE*/{1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*EXP_GET*/ {1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*EXP_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*EXP_EVENT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, }; static LIST_HEAD(proto_list); @@ -145,7 +146,8 @@ static LIST_HEAD(proto_list); static unsigned int options; static unsigned int command; -#define CT_COMPARISON (CT_OPT_PROTO | CT_OPT_ORIG | CT_OPT_REPL | CT_OPT_MARK) +#define CT_COMPARISON (CT_OPT_PROTO | CT_OPT_ORIG | CT_OPT_REPL | CT_OPT_MARK |\ + CT_OPT_SECMARK) void register_proto(struct ctproto_handler *h) { @@ -206,7 +208,6 @@ void exit_error(enum exittype status, char *msg, ...) fprintf(stderr,"%s v%s: ", PROGNAME, VERSION); vfprintf(stderr, msg, args); va_end(args); - fprintf(stderr, "\n"); if (status == PARAMETER_PROBLEM) exit_tryhelp(status); exit(status); @@ -522,6 +523,7 @@ static const char usage_conntrack_parameters[] = " -n, --src-nat ip\t\t\tsource NAT ip\n" " -g, --dst-nat ip\t\t\tdestination NAT ip\n" " -m, --mark mark\t\t\tSet mark\n" + " -c, --secmark secmark\t\t\tSet selinux secmark\n" " -e, --event-mask eventmask\t\tEvent mask, eg. NEW,DESTROY\n" " -z, --zero \t\t\t\tZero counters while listing\n" " -o, --output type[,...]\t\tOutput format, eg. xml\n"; @@ -556,7 +558,7 @@ void usage(char *prog) { fprintf(stdout, "\n%s", usage_tables); fprintf(stdout, "\n%s", usage_conntrack_parameters); fprintf(stdout, "\n%s", usage_expectation_parameters); - fprintf(stdout, "\n%s", usage_parameters); + fprintf(stdout, "\n%s\n", usage_parameters); } static unsigned int output_mask; @@ -677,9 +679,10 @@ int main(int argc, char *argv[]) register_udp(); register_icmp(); - while ((c = getopt_long(argc, argv, - "L::I::U::D::G::E::F::hVs:d:r:q:p:t:u:e:a:z[:]:{:}:m:i::f:o:", - opts, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "L::I::U::D::G::E::F::hVs:d:r:q:" + "p:t:u:e:a:z[:]:{:}:m:i::f:o:n::" + "g::c:", + opts, NULL)) != -1) { switch(c) { case 'L': type = check_type(argc, argv); @@ -948,6 +951,12 @@ int main(int argc, char *argv[]) continue; nfct_set_attr_u32(obj, ATTR_MARK, atol(optarg)); break; + case 'c': + options |= CT_OPT_SECMARK; + if (!optarg) + continue; + nfct_set_attr_u32(obj, ATTR_SECMARK, atol(optarg)); + break; case 'i': printf("warning: ignoring --id. deprecated option.\n"); break; diff --git a/src/parse.c b/src/parse.c index 81b70c4..8816e7a 100644 --- a/src/parse.c +++ b/src/parse.c @@ -55,6 +55,7 @@ parse h[ATTR_MAX] = { [ATTR_TIMEOUT] = parse_u32, [ATTR_MARK] = parse_u32, [ATTR_STATUS] = parse_u32, + [ATTR_SECMARK] = parse_u32, }; void parse_netpld(struct nf_conntrack *ct, struct netpld *pld, int *query) -- cgit v1.2.3 From 6d37133f5c98dadf6eb17f7f6854290f572dd4ad Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Fri, 21 Dec 2007 13:50:59 +0000 Subject: raise ignorepoll limit from 1024 to INT_MAX --- ChangeLog | 1 + src/ignore_pool.c | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 9d8e753..74f0bc5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -16,6 +16,7 @@ o syslog support (based on patch from Simon Lodal) o add CacheWriteThrough clause: external cache write through policy o add support for secmark (requires Linux kernel >= 2.6.25) o add conntrackd (8) manpage +o raise ignorepool maximum limit from 1024 to INT_MAX version 0.9.5 (2007/07/29) ------------------------------ diff --git a/src/ignore_pool.c b/src/ignore_pool.c index d6f0e93..619c2fa 100644 --- a/src/ignore_pool.c +++ b/src/ignore_pool.c @@ -22,8 +22,9 @@ #include "ignore.h" #include -#define IGNORE_POOL_SIZE 32 -#define IGNORE_POOL_LIMIT 1024 +/* XXX: These should be configurable */ +#define IGNORE_POOL_SIZE 128 +#define IGNORE_POOL_LIMIT INT_MAX static u_int32_t hash(const void *data, struct hashtable *table) { -- cgit v1.2.3 From 5bac4f06e8ebc81ed16ec93a0db8682e6a359608 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Fri, 21 Dec 2007 18:04:49 +0000 Subject: o Use more appropriate names for the existing synchronization modes: o rename `persistent' mode to `alarm' o rename `nack' mode to `ftfw' o Now default synchronization mode is ftfw instead of alarm --- ChangeLog | 4 + examples/sync/alarm/README | 1 + examples/sync/alarm/node1/conntrackd.conf | 140 ++++++++++ examples/sync/alarm/node1/keepalived.conf | 39 +++ examples/sync/alarm/node2/conntrackd.conf | 140 ++++++++++ examples/sync/alarm/node2/keepalived.conf | 39 +++ examples/sync/alarm/script_backup.sh | 3 + examples/sync/alarm/script_master.sh | 4 + examples/sync/ftfw/README | 1 + examples/sync/ftfw/node1/conntrackd.conf | 135 +++++++++ examples/sync/ftfw/node1/keepalived.conf | 39 +++ examples/sync/ftfw/node2/conntrackd.conf | 134 +++++++++ examples/sync/ftfw/node2/keepalived.conf | 39 +++ examples/sync/ftfw/script_backup.sh | 3 + examples/sync/ftfw/script_master.sh | 5 + examples/sync/nack/README | 1 - examples/sync/nack/node1/conntrackd.conf | 135 --------- examples/sync/nack/node1/keepalived.conf | 39 --- examples/sync/nack/node2/conntrackd.conf | 134 --------- examples/sync/nack/node2/keepalived.conf | 39 --- examples/sync/nack/script_backup.sh | 3 - examples/sync/nack/script_master.sh | 5 - examples/sync/persistent/README | 1 - examples/sync/persistent/node1/conntrackd.conf | 140 ---------- examples/sync/persistent/node1/keepalived.conf | 39 --- examples/sync/persistent/node2/conntrackd.conf | 140 ---------- examples/sync/persistent/node2/keepalived.conf | 39 --- examples/sync/persistent/script_backup.sh | 3 - examples/sync/persistent/script_master.sh | 4 - include/conntrackd.h | 10 +- include/sync.h | 4 +- src/Makefile.am | 2 +- src/main.c | 2 +- src/read_config_lex.l | 14 +- src/read_config_yy.y | 10 +- src/sync-alarm.c | 104 +++++++ src/sync-ftfw.c | 366 +++++++++++++++++++++++++ src/sync-mode.c | 8 +- src/sync-nack.c | 366 ------------------------- src/sync-notrack.c | 104 ------- 40 files changed, 1226 insertions(+), 1212 deletions(-) create mode 100644 examples/sync/alarm/README create mode 100644 examples/sync/alarm/node1/conntrackd.conf create mode 100644 examples/sync/alarm/node1/keepalived.conf create mode 100644 examples/sync/alarm/node2/conntrackd.conf create mode 100644 examples/sync/alarm/node2/keepalived.conf create mode 100755 examples/sync/alarm/script_backup.sh create mode 100755 examples/sync/alarm/script_master.sh create mode 100644 examples/sync/ftfw/README create mode 100644 examples/sync/ftfw/node1/conntrackd.conf create mode 100644 examples/sync/ftfw/node1/keepalived.conf create mode 100644 examples/sync/ftfw/node2/conntrackd.conf create mode 100644 examples/sync/ftfw/node2/keepalived.conf create mode 100755 examples/sync/ftfw/script_backup.sh create mode 100755 examples/sync/ftfw/script_master.sh delete mode 100644 examples/sync/nack/README delete mode 100644 examples/sync/nack/node1/conntrackd.conf delete mode 100644 examples/sync/nack/node1/keepalived.conf delete mode 100644 examples/sync/nack/node2/conntrackd.conf delete mode 100644 examples/sync/nack/node2/keepalived.conf delete mode 100755 examples/sync/nack/script_backup.sh delete mode 100755 examples/sync/nack/script_master.sh delete mode 100644 examples/sync/persistent/README delete mode 100644 examples/sync/persistent/node1/conntrackd.conf delete mode 100644 examples/sync/persistent/node1/keepalived.conf delete mode 100644 examples/sync/persistent/node2/conntrackd.conf delete mode 100644 examples/sync/persistent/node2/keepalived.conf delete mode 100755 examples/sync/persistent/script_backup.sh delete mode 100755 examples/sync/persistent/script_master.sh create mode 100644 src/sync-alarm.c create mode 100644 src/sync-ftfw.c delete mode 100644 src/sync-nack.c delete mode 100644 src/sync-notrack.c (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 74f0bc5..272b078 100644 --- a/ChangeLog +++ b/ChangeLog @@ -17,6 +17,10 @@ o add CacheWriteThrough clause: external cache write through policy o add support for secmark (requires Linux kernel >= 2.6.25) o add conntrackd (8) manpage o raise ignorepool maximum limit from 1024 to INT_MAX +o Use more appropriate names for the existing synchronization modes: + o rename `persistent' mode to `alarm' + o rename `nack' mode to `ftfw' +o Now default synchronization mode is ftfw instead of alarm version 0.9.5 (2007/07/29) ------------------------------ diff --git a/examples/sync/alarm/README b/examples/sync/alarm/README new file mode 100644 index 0000000..dfd8474 --- /dev/null +++ b/examples/sync/alarm/README @@ -0,0 +1 @@ +This directory contains the files for the ALARM based protocol diff --git a/examples/sync/alarm/node1/conntrackd.conf b/examples/sync/alarm/node1/conntrackd.conf new file mode 100644 index 0000000..3004d07 --- /dev/null +++ b/examples/sync/alarm/node1/conntrackd.conf @@ -0,0 +1,140 @@ +# +# Synchronizer settings +# +Sync { + Mode ALARM { + # + # If a conntrack entry is not modified in <= 15 seconds, then + # a message is broadcasted. This mechanism is used to + # resynchronize nodes that just joined the multicast group + # + RefreshTime 15 + + # + # If we don't receive a notification about the state of + # an entry in the external cache after N seconds, then + # remove it. + # + CacheTimeout 180 + + # + # Entries committed to the connection tracking table + # starts with a limited timeout of N seconds until the + # takeover process is completed. + # + CommitTimeout 180 + } + + # + # Multicast IP and interface where messages are + # broadcasted (dedicated link). IMPORTANT: Make sure + # that iptables accepts traffic for destination + # 225.0.0.50, eg: + # + # iptables -I INPUT -d 225.0.0.50 -j ACCEPT + # iptables -I OUTPUT -d 225.0.0.50 -j ACCEPT + # + Multicast { + IPv4_address 225.0.0.50 + IPv4_interface 192.168.100.100 # IP of dedicated link + Interface eth2 + Group 3780 + } + + # Enable/Disable message checksumming + Checksum on + + # Uncomment this if you want to replicate just certain TCP states. + # This option introduces a tradeoff in the replication: it reduces + # CPU consumption and lost messages rate at the cost of having + # backup replicas that don't contain the current state that the active + # replica holds. TCP states are: SYN_SENT, SYN_RECV, ESTABLISHED, + # FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN. + # + # Replicate ESTABLISHED TIME_WAIT for TCP + + # If you have a multiprimary setup (active-active) without connection + # persistency, ie. you can't know which firewall handles a packet + # that is part of a connection, then you need direct commit of + # conntrack entries to the kernel conntrack table. OSPF setups must + # set on this option. Default is Off. + # + # CacheWriteThrough On +} + +# +# General settings +# +General { + # + # Number of buckets in the caches: hash table + # + HashSize 8192 + + # + # Maximum number of conntracks: + # it must be >= $ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max + # + HashLimit 65535 + + # + # Logfile: on, off, or a filename + # Default: on (/var/log/conntrackd.log) + # + #LogFile off + + # + # Syslog: on, off or a facility name (daemon (default) or local0..7) + # Default: off + # + #Syslog on + + # + # Lockfile + # + LockFile /var/lock/conntrack.lock + + # + # Unix socket configuration + # + UNIX { + Path /tmp/sync.sock + Backlog 20 + } + + # + # Netlink socket buffer size + # + SocketBufferSize 262142 + + # + # Increase the socket buffer up to maximum if required + # + SocketBufferSizeMaxGrown 655355 +} + +# +# Ignore traffic for a certain set of IP's: Usually +# all the IP assigned to the firewall since local +# traffic must be ignored, just forwarded connections +# are worth to replicate +# +IgnoreTrafficFor { + IPv4_address 127.0.0.1 # loopback + IPv4_address 192.168.0.1 + IPv4_address 192.168.1.1 + IPv4_address 192.168.100.100 # dedicated link ip + IPv4_address 192.168.0.100 # virtual IP 1 + IPv4_address 192.168.1.100 # virtual IP 2 +} + +# +# Do not replicate certain protocol traffic +# +IgnoreProtocol { + UDP + ICMP + IGMP + VRRP + # numeric numbers also valid +} diff --git a/examples/sync/alarm/node1/keepalived.conf b/examples/sync/alarm/node1/keepalived.conf new file mode 100644 index 0000000..f937467 --- /dev/null +++ b/examples/sync/alarm/node1/keepalived.conf @@ -0,0 +1,39 @@ +vrrp_sync_group G1 { # must be before vrrp_instance declaration + group { + VI_1 + VI_2 + } + notify_master /etc/conntrackd/script_master.sh + notify_backup /etc/conntrackd/script_backup.sh +# notify_fault /etc/conntrackd/script_fault.sh +} + +vrrp_instance VI_1 { + interface eth1 + state SLAVE + virtual_router_id 61 + priority 80 + advert_int 3 + authentication { + auth_type PASS + auth_pass papas_con_tomate + } + virtual_ipaddress { + 192.168.0.100 # default CIDR mask is /32 + } +} + +vrrp_instance VI_2 { + interface eth0 + state SLAVE + virtual_router_id 62 + priority 80 + advert_int 3 + authentication { + auth_type PASS + auth_pass papas_con_tomate + } + virtual_ipaddress { + 192.168.1.100 + } +} diff --git a/examples/sync/alarm/node2/conntrackd.conf b/examples/sync/alarm/node2/conntrackd.conf new file mode 100644 index 0000000..fb12130 --- /dev/null +++ b/examples/sync/alarm/node2/conntrackd.conf @@ -0,0 +1,140 @@ +# +# Synchronizer settings +# +Sync { + Mode ALARM { + # + # If a conntrack entry is not modified in <= 15 seconds, then + # a message is broadcasted. This mechanism is used to + # resynchronize nodes that just joined the multicast group + # + RefreshTime 15 + + # + # If we don't receive a notification about the state of + # an entry in the external cache after N seconds, then + # remove it. + # + CacheTimeout 180 + + # + # Entries committed to the connection tracking table + # starts with a limited timeout of N seconds until the + # takeover process is completed. + # + CommitTimeout 180 + } + + # + # Multicast IP and interface where messages are + # broadcasted (dedicated link). IMPORTANT: Make sure + # that iptables accepts traffic for destination + # 225.0.0.50, eg: + # + # iptables -I INPUT -d 225.0.0.50 -j ACCEPT + # iptables -I OUTPUT -d 225.0.0.50 -j ACCEPT + # + Multicast { + IPv4_address 225.0.0.50 + IPv4_interface 192.168.100.200 # IP of dedicated link + Interface eth2 + Group 3780 + } + + # Enable/Disable message checksumming + Checksum on + + # Uncomment this if you want to replicate just certain TCP states. + # This option introduces a tradeoff in the replication: it reduces + # CPU consumption and lost messages rate at the cost of having + # backup replicas that don't contain the current state that the active + # replica holds. TCP states are: SYN_SENT, SYN_RECV, ESTABLISHED, + # FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN. + # + # Replicate ESTABLISHED TIME_WAIT for TCP + + # If you have a multiprimary setup (active-active) without connection + # persistency, ie. you can't know which firewall handles a packet + # that is part of a connection, then you need direct commit of + # conntrack entries to the kernel conntrack table. OSPF setups must + # set on this option. Default is Off. + # + # CacheWriteThrough On +} + +# +# General settings +# +General { + # + # Number of buckets in the caches: hash table + # + HashSize 8192 + + # + # Maximum number of conntracks: + # it must be >= $ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max + # + HashLimit 65535 + + # + # Logfile: on, off, or a filename + # Default: on (/var/log/conntrackd.log) + # + #LogFile off + + # + # Syslog: on, off or a facility name (daemon (default) or local0..7) + # Default: off + # + #Syslog on + + # + # Lockfile + # + LockFile /var/lock/conntrack.lock + + # + # Unix socket configuration + # + UNIX { + Path /tmp/sync.sock + Backlog 20 + } + + # + # Netlink socket buffer size + # + SocketBufferSize 262142 + + # + # Increase the socket buffer up to maximum if required + # + SocketBufferSizeMaxGrown 655355 +} + +# +# Ignore traffic for a certain set of IP's: Usually +# all the IP assigned to the firewall since local +# traffic must be ignored, just forwarded connections +# are worth to replicate +# +IgnoreTrafficFor { + IPv4_address 127.0.0.1 # loopback + IPv4_address 192.168.0.2 + IPv4_address 192.168.1.2 + IPv4_address 192.168.100.200 # dedicated link ip + IPv4_address 192.168.0.200 # virtual IP 1 + IPv4_address 192.168.1.200 # virtual IP 2 +} + +# +# Do not replicate certain protocol traffic +# +IgnoreProtocol { + UDP + ICMP + IGMP + VRRP + # numeric numbers also valid +} diff --git a/examples/sync/alarm/node2/keepalived.conf b/examples/sync/alarm/node2/keepalived.conf new file mode 100644 index 0000000..f937467 --- /dev/null +++ b/examples/sync/alarm/node2/keepalived.conf @@ -0,0 +1,39 @@ +vrrp_sync_group G1 { # must be before vrrp_instance declaration + group { + VI_1 + VI_2 + } + notify_master /etc/conntrackd/script_master.sh + notify_backup /etc/conntrackd/script_backup.sh +# notify_fault /etc/conntrackd/script_fault.sh +} + +vrrp_instance VI_1 { + interface eth1 + state SLAVE + virtual_router_id 61 + priority 80 + advert_int 3 + authentication { + auth_type PASS + auth_pass papas_con_tomate + } + virtual_ipaddress { + 192.168.0.100 # default CIDR mask is /32 + } +} + +vrrp_instance VI_2 { + interface eth0 + state SLAVE + virtual_router_id 62 + priority 80 + advert_int 3 + authentication { + auth_type PASS + auth_pass papas_con_tomate + } + virtual_ipaddress { + 192.168.1.100 + } +} diff --git a/examples/sync/alarm/script_backup.sh b/examples/sync/alarm/script_backup.sh new file mode 100755 index 0000000..8ea2ad8 --- /dev/null +++ b/examples/sync/alarm/script_backup.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +/usr/sbin/conntrackd -B diff --git a/examples/sync/alarm/script_master.sh b/examples/sync/alarm/script_master.sh new file mode 100755 index 0000000..70c26c9 --- /dev/null +++ b/examples/sync/alarm/script_master.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +/usr/sbin/conntrackd -c +/usr/sbin/conntrackd -R diff --git a/examples/sync/ftfw/README b/examples/sync/ftfw/README new file mode 100644 index 0000000..a09db10 --- /dev/null +++ b/examples/sync/ftfw/README @@ -0,0 +1 @@ +This directory contains the files for the FT-FW based protocol diff --git a/examples/sync/ftfw/node1/conntrackd.conf b/examples/sync/ftfw/node1/conntrackd.conf new file mode 100644 index 0000000..fadeb9d --- /dev/null +++ b/examples/sync/ftfw/node1/conntrackd.conf @@ -0,0 +1,135 @@ +# +# Synchronizer settings +# +Sync { + Mode FTFW { + # + # Size of the buffer that hold destroy messages for + # possible resends (in bytes) + # + ResendBufferSize 262144 + + # + # Entries committed to the connection tracking table + # starts with a limited timeout of N seconds until the + # takeover process is completed. + # + CommitTimeout 180 + + # Set Acknowledgement window size + ACKWindowSize 20 + } + + # + # Multicast IP and interface where messages are + # broadcasted (dedicated link). IMPORTANT: Make sure + # that iptables accepts traffic for destination + # 225.0.0.50, eg: + # + # iptables -I INPUT -d 225.0.0.50 -j ACCEPT + # iptables -I OUTPUT -d 225.0.0.50 -j ACCEPT + # + Multicast { + IPv4_address 225.0.0.50 + IPv4_interface 192.168.100.100 # IP of dedicated link + Interface eth2 + Group 3780 + } + + # Enable/Disable message checksumming + Checksum on + + # Uncomment this if you want to replicate just certain TCP states. + # This option introduces a tradeoff in the replication: it reduces + # CPU consumption and lost messages rate at the cost of having + # backup replicas that don't contain the current state that the active + # replica holds. TCP states are: SYN_SENT, SYN_RECV, ESTABLISHED, + # FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN. + # + # Replicate ESTABLISHED TIME_WAIT for TCP + + # If you have a multiprimary setup (active-active) without connection + # persistency, ie. you can't know which firewall handles a packet + # that is part of a connection, then you need direct commit of + # conntrack entries to the kernel conntrack table. OSPF setups must + # set on this option. Default is Off. + # + # CacheWriteThrough On +} + +# +# General settings +# +General { + # + # Number of buckets in the caches: hash table + # + HashSize 8192 + + # + # Maximum number of conntracks: + # it must be >= $ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max + # + HashLimit 65535 + + # + # Logfile: on, off, or a filename + # Default: on (/var/log/conntrackd.log) + # + #LogFile off + + # + # Syslog: on, off or a facility name (daemon (default) or local0..7) + # Default: off + # + #Syslog on + + # + # Lockfile + # + LockFile /var/lock/conntrack.lock + + # + # Unix socket configuration + # + UNIX { + Path /tmp/sync.sock + Backlog 20 + } + + # + # Netlink socket buffer size + # + SocketBufferSize 262142 + + # + # Increase the socket buffer up to maximum if required + # + SocketBufferSizeMaxGrown 655355 +} + +# +# Ignore traffic for a certain set of IP's: Usually +# all the IP assigned to the firewall since local +# traffic must be ignored, just forwarded connections +# are worth to replicate +# +IgnoreTrafficFor { + IPv4_address 127.0.0.1 # loopback + IPv4_address 192.168.0.1 + IPv4_address 192.168.1.1 + IPv4_address 192.168.100.100 # dedicated link ip + IPv4_address 192.168.0.100 # virtual IP 1 + IPv4_address 192.168.1.100 # virtual IP 2 +} + +# +# Do not replicate certain protocol traffic +# +IgnoreProtocol { + UDP + ICMP + IGMP + VRRP + # numeric numbers also valid +} diff --git a/examples/sync/ftfw/node1/keepalived.conf b/examples/sync/ftfw/node1/keepalived.conf new file mode 100644 index 0000000..f937467 --- /dev/null +++ b/examples/sync/ftfw/node1/keepalived.conf @@ -0,0 +1,39 @@ +vrrp_sync_group G1 { # must be before vrrp_instance declaration + group { + VI_1 + VI_2 + } + notify_master /etc/conntrackd/script_master.sh + notify_backup /etc/conntrackd/script_backup.sh +# notify_fault /etc/conntrackd/script_fault.sh +} + +vrrp_instance VI_1 { + interface eth1 + state SLAVE + virtual_router_id 61 + priority 80 + advert_int 3 + authentication { + auth_type PASS + auth_pass papas_con_tomate + } + virtual_ipaddress { + 192.168.0.100 # default CIDR mask is /32 + } +} + +vrrp_instance VI_2 { + interface eth0 + state SLAVE + virtual_router_id 62 + priority 80 + advert_int 3 + authentication { + auth_type PASS + auth_pass papas_con_tomate + } + virtual_ipaddress { + 192.168.1.100 + } +} diff --git a/examples/sync/ftfw/node2/conntrackd.conf b/examples/sync/ftfw/node2/conntrackd.conf new file mode 100644 index 0000000..59ffc4f --- /dev/null +++ b/examples/sync/ftfw/node2/conntrackd.conf @@ -0,0 +1,134 @@ +# +# Synchronizer settings +# +Sync { + Mode FTFW { + # + # Size of the buffer that hold destroy messages for + # possible resends (in bytes) + # + ResendBufferSize 262144 + + # Entries committed to the connection tracking table + # starts with a limited timeout of N seconds until the + # takeover process is completed. + # + CommitTimeout 180 + + # Set Acknowledgement window size + ACKWindowSize 20 + } + + # + # Multicast IP and interface where messages are + # broadcasted (dedicated link). IMPORTANT: Make sure + # that iptables accepts traffic for destination + # 225.0.0.50, eg: + # + # iptables -I INPUT -d 225.0.0.50 -j ACCEPT + # iptables -I OUTPUT -d 225.0.0.50 -j ACCEPT + # + Multicast { + IPv4_address 225.0.0.50 + IPv4_interface 192.168.100.200 # IP of dedicated link + Interface eth2 + Group 3780 + } + + # Enable/Disable message checksumming + Checksum on + + # Uncomment this if you want to replicate just certain TCP states. + # This option introduces a tradeoff in the replication: it reduces + # CPU consumption and lost messages rate at the cost of having + # backup replicas that don't contain the current state that the active + # replica holds. TCP states are: SYN_SENT, SYN_RECV, ESTABLISHED, + # FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN. + # + # Replicate ESTABLISHED TIME_WAIT for TCP + + # If you have a multiprimary setup (active-active) without connection + # persistency, ie. you can't know which firewall handles a packet + # that is part of a connection, then you need direct commit of + # conntrack entries to the kernel conntrack table. OSPF setups must + # set on this option. Default is Off. + # + # CacheWriteThrough On +} + +# +# General settings +# +General { + # + # Number of buckets in the caches: hash table + # + HashSize 8192 + + # + # Maximum number of conntracks: + # it must be >= $ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max + # + HashLimit 65535 + + # + # Logfile: on, off, or a filename + # Default: on (/var/log/conntrackd.log) + # + #LogFile off + + # + # Syslog: on, off or a facility name (daemon (default) or local0..7) + # Default: off + # + #Syslog on + + # + # Lockfile + # + LockFile /var/lock/conntrack.lock + + # + # Unix socket configuration + # + UNIX { + Path /tmp/sync.sock + Backlog 20 + } + + # + # Netlink socket buffer size + # + SocketBufferSize 262142 + + # + # Increase the socket buffer up to maximum if required + # + SocketBufferSizeMaxGrown 655355 +} + +# +# Ignore traffic for a certain set of IP's: Usually +# all the IP assigned to the firewall since local +# traffic must be ignored, just forwarded connections +# are worth to replicate +# +IgnoreTrafficFor { + IPv4_address 127.0.0.1 # loopback + IPv4_address 192.168.0.2 + IPv4_address 192.168.1.2 + IPv4_address 192.168.100.200 # dedicated link ip + IPv4_address 192.168.0.200 # virtual IP 1 + IPv4_address 192.168.1.200 # virtual IP 2 +} + +# +# Do not replicate certain protocol traffic +# +IgnoreProtocol { + UDP + ICMP + IGMP + VRRP + # numeric numbers also valid +} diff --git a/examples/sync/ftfw/node2/keepalived.conf b/examples/sync/ftfw/node2/keepalived.conf new file mode 100644 index 0000000..f937467 --- /dev/null +++ b/examples/sync/ftfw/node2/keepalived.conf @@ -0,0 +1,39 @@ +vrrp_sync_group G1 { # must be before vrrp_instance declaration + group { + VI_1 + VI_2 + } + notify_master /etc/conntrackd/script_master.sh + notify_backup /etc/conntrackd/script_backup.sh +# notify_fault /etc/conntrackd/script_fault.sh +} + +vrrp_instance VI_1 { + interface eth1 + state SLAVE + virtual_router_id 61 + priority 80 + advert_int 3 + authentication { + auth_type PASS + auth_pass papas_con_tomate + } + virtual_ipaddress { + 192.168.0.100 # default CIDR mask is /32 + } +} + +vrrp_instance VI_2 { + interface eth0 + state SLAVE + virtual_router_id 62 + priority 80 + advert_int 3 + authentication { + auth_type PASS + auth_pass papas_con_tomate + } + virtual_ipaddress { + 192.168.1.100 + } +} diff --git a/examples/sync/ftfw/script_backup.sh b/examples/sync/ftfw/script_backup.sh new file mode 100755 index 0000000..813e375 --- /dev/null +++ b/examples/sync/ftfw/script_backup.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +/usr/sbin/conntrackd -n # request a resync from other nodes via multicast diff --git a/examples/sync/ftfw/script_master.sh b/examples/sync/ftfw/script_master.sh new file mode 100755 index 0000000..ff1dbc0 --- /dev/null +++ b/examples/sync/ftfw/script_master.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +/usr/sbin/conntrackd -c # commit the cache +/usr/sbin/conntrackd -f # flush the caches +/usr/sbin/conntrackd -R # resync with kernel conntrack table diff --git a/examples/sync/nack/README b/examples/sync/nack/README deleted file mode 100644 index 66987f7..0000000 --- a/examples/sync/nack/README +++ /dev/null @@ -1 +0,0 @@ -This directory contains the files for the NACK based protocol diff --git a/examples/sync/nack/node1/conntrackd.conf b/examples/sync/nack/node1/conntrackd.conf deleted file mode 100644 index 4fc8f22..0000000 --- a/examples/sync/nack/node1/conntrackd.conf +++ /dev/null @@ -1,135 +0,0 @@ -# -# Synchronizer settings -# -Sync { - Mode NACK { - # - # Size of the buffer that hold destroy messages for - # possible resends (in bytes) - # - ResendBufferSize 262144 - - # - # Entries committed to the connection tracking table - # starts with a limited timeout of N seconds until the - # takeover process is completed. - # - CommitTimeout 180 - - # Set Acknowledgement window size - ACKWindowSize 20 - } - - # - # Multicast IP and interface where messages are - # broadcasted (dedicated link). IMPORTANT: Make sure - # that iptables accepts traffic for destination - # 225.0.0.50, eg: - # - # iptables -I INPUT -d 225.0.0.50 -j ACCEPT - # iptables -I OUTPUT -d 225.0.0.50 -j ACCEPT - # - Multicast { - IPv4_address 225.0.0.50 - IPv4_interface 192.168.100.100 # IP of dedicated link - Interface eth2 - Group 3780 - } - - # Enable/Disable message checksumming - Checksum on - - # Uncomment this if you want to replicate just certain TCP states. - # This option introduces a tradeoff in the replication: it reduces - # CPU consumption and lost messages rate at the cost of having - # backup replicas that don't contain the current state that the active - # replica holds. TCP states are: SYN_SENT, SYN_RECV, ESTABLISHED, - # FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN. - # - # Replicate ESTABLISHED TIME_WAIT for TCP - - # If you have a multiprimary setup (active-active) without connection - # persistency, ie. you can't know which firewall handles a packet - # that is part of a connection, then you need direct commit of - # conntrack entries to the kernel conntrack table. OSPF setups must - # set on this option. Default is Off. - # - # CacheWriteThrough On -} - -# -# General settings -# -General { - # - # Number of buckets in the caches: hash table - # - HashSize 8192 - - # - # Maximum number of conntracks: - # it must be >= $ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max - # - HashLimit 65535 - - # - # Logfile: on, off, or a filename - # Default: on (/var/log/conntrackd.log) - # - #LogFile off - - # - # Syslog: on, off or a facility name (daemon (default) or local0..7) - # Default: off - # - #Syslog on - - # - # Lockfile - # - LockFile /var/lock/conntrack.lock - - # - # Unix socket configuration - # - UNIX { - Path /tmp/sync.sock - Backlog 20 - } - - # - # Netlink socket buffer size - # - SocketBufferSize 262142 - - # - # Increase the socket buffer up to maximum if required - # - SocketBufferSizeMaxGrown 655355 -} - -# -# Ignore traffic for a certain set of IP's: Usually -# all the IP assigned to the firewall since local -# traffic must be ignored, just forwarded connections -# are worth to replicate -# -IgnoreTrafficFor { - IPv4_address 127.0.0.1 # loopback - IPv4_address 192.168.0.1 - IPv4_address 192.168.1.1 - IPv4_address 192.168.100.100 # dedicated link ip - IPv4_address 192.168.0.100 # virtual IP 1 - IPv4_address 192.168.1.100 # virtual IP 2 -} - -# -# Do not replicate certain protocol traffic -# -IgnoreProtocol { - UDP - ICMP - IGMP - VRRP - # numeric numbers also valid -} diff --git a/examples/sync/nack/node1/keepalived.conf b/examples/sync/nack/node1/keepalived.conf deleted file mode 100644 index f937467..0000000 --- a/examples/sync/nack/node1/keepalived.conf +++ /dev/null @@ -1,39 +0,0 @@ -vrrp_sync_group G1 { # must be before vrrp_instance declaration - group { - VI_1 - VI_2 - } - notify_master /etc/conntrackd/script_master.sh - notify_backup /etc/conntrackd/script_backup.sh -# notify_fault /etc/conntrackd/script_fault.sh -} - -vrrp_instance VI_1 { - interface eth1 - state SLAVE - virtual_router_id 61 - priority 80 - advert_int 3 - authentication { - auth_type PASS - auth_pass papas_con_tomate - } - virtual_ipaddress { - 192.168.0.100 # default CIDR mask is /32 - } -} - -vrrp_instance VI_2 { - interface eth0 - state SLAVE - virtual_router_id 62 - priority 80 - advert_int 3 - authentication { - auth_type PASS - auth_pass papas_con_tomate - } - virtual_ipaddress { - 192.168.1.100 - } -} diff --git a/examples/sync/nack/node2/conntrackd.conf b/examples/sync/nack/node2/conntrackd.conf deleted file mode 100644 index 43ebd77..0000000 --- a/examples/sync/nack/node2/conntrackd.conf +++ /dev/null @@ -1,134 +0,0 @@ -# -# Synchronizer settings -# -Sync { - Mode NACK { - # - # Size of the buffer that hold destroy messages for - # possible resends (in bytes) - # - ResendBufferSize 262144 - - # Entries committed to the connection tracking table - # starts with a limited timeout of N seconds until the - # takeover process is completed. - # - CommitTimeout 180 - - # Set Acknowledgement window size - ACKWindowSize 20 - } - - # - # Multicast IP and interface where messages are - # broadcasted (dedicated link). IMPORTANT: Make sure - # that iptables accepts traffic for destination - # 225.0.0.50, eg: - # - # iptables -I INPUT -d 225.0.0.50 -j ACCEPT - # iptables -I OUTPUT -d 225.0.0.50 -j ACCEPT - # - Multicast { - IPv4_address 225.0.0.50 - IPv4_interface 192.168.100.200 # IP of dedicated link - Interface eth2 - Group 3780 - } - - # Enable/Disable message checksumming - Checksum on - - # Uncomment this if you want to replicate just certain TCP states. - # This option introduces a tradeoff in the replication: it reduces - # CPU consumption and lost messages rate at the cost of having - # backup replicas that don't contain the current state that the active - # replica holds. TCP states are: SYN_SENT, SYN_RECV, ESTABLISHED, - # FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN. - # - # Replicate ESTABLISHED TIME_WAIT for TCP - - # If you have a multiprimary setup (active-active) without connection - # persistency, ie. you can't know which firewall handles a packet - # that is part of a connection, then you need direct commit of - # conntrack entries to the kernel conntrack table. OSPF setups must - # set on this option. Default is Off. - # - # CacheWriteThrough On -} - -# -# General settings -# -General { - # - # Number of buckets in the caches: hash table - # - HashSize 8192 - - # - # Maximum number of conntracks: - # it must be >= $ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max - # - HashLimit 65535 - - # - # Logfile: on, off, or a filename - # Default: on (/var/log/conntrackd.log) - # - #LogFile off - - # - # Syslog: on, off or a facility name (daemon (default) or local0..7) - # Default: off - # - #Syslog on - - # - # Lockfile - # - LockFile /var/lock/conntrack.lock - - # - # Unix socket configuration - # - UNIX { - Path /tmp/sync.sock - Backlog 20 - } - - # - # Netlink socket buffer size - # - SocketBufferSize 262142 - - # - # Increase the socket buffer up to maximum if required - # - SocketBufferSizeMaxGrown 655355 -} - -# -# Ignore traffic for a certain set of IP's: Usually -# all the IP assigned to the firewall since local -# traffic must be ignored, just forwarded connections -# are worth to replicate -# -IgnoreTrafficFor { - IPv4_address 127.0.0.1 # loopback - IPv4_address 192.168.0.2 - IPv4_address 192.168.1.2 - IPv4_address 192.168.100.200 # dedicated link ip - IPv4_address 192.168.0.200 # virtual IP 1 - IPv4_address 192.168.1.200 # virtual IP 2 -} - -# -# Do not replicate certain protocol traffic -# -IgnoreProtocol { - UDP - ICMP - IGMP - VRRP - # numeric numbers also valid -} diff --git a/examples/sync/nack/node2/keepalived.conf b/examples/sync/nack/node2/keepalived.conf deleted file mode 100644 index f937467..0000000 --- a/examples/sync/nack/node2/keepalived.conf +++ /dev/null @@ -1,39 +0,0 @@ -vrrp_sync_group G1 { # must be before vrrp_instance declaration - group { - VI_1 - VI_2 - } - notify_master /etc/conntrackd/script_master.sh - notify_backup /etc/conntrackd/script_backup.sh -# notify_fault /etc/conntrackd/script_fault.sh -} - -vrrp_instance VI_1 { - interface eth1 - state SLAVE - virtual_router_id 61 - priority 80 - advert_int 3 - authentication { - auth_type PASS - auth_pass papas_con_tomate - } - virtual_ipaddress { - 192.168.0.100 # default CIDR mask is /32 - } -} - -vrrp_instance VI_2 { - interface eth0 - state SLAVE - virtual_router_id 62 - priority 80 - advert_int 3 - authentication { - auth_type PASS - auth_pass papas_con_tomate - } - virtual_ipaddress { - 192.168.1.100 - } -} diff --git a/examples/sync/nack/script_backup.sh b/examples/sync/nack/script_backup.sh deleted file mode 100755 index 813e375..0000000 --- a/examples/sync/nack/script_backup.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -/usr/sbin/conntrackd -n # request a resync from other nodes via multicast diff --git a/examples/sync/nack/script_master.sh b/examples/sync/nack/script_master.sh deleted file mode 100755 index ff1dbc0..0000000 --- a/examples/sync/nack/script_master.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh - -/usr/sbin/conntrackd -c # commit the cache -/usr/sbin/conntrackd -f # flush the caches -/usr/sbin/conntrackd -R # resync with kernel conntrack table diff --git a/examples/sync/persistent/README b/examples/sync/persistent/README deleted file mode 100644 index 36b5989..0000000 --- a/examples/sync/persistent/README +++ /dev/null @@ -1 +0,0 @@ -This directory contains the files for the PERSISTENT based protocol diff --git a/examples/sync/persistent/node1/conntrackd.conf b/examples/sync/persistent/node1/conntrackd.conf deleted file mode 100644 index a55608b..0000000 --- a/examples/sync/persistent/node1/conntrackd.conf +++ /dev/null @@ -1,140 +0,0 @@ -# -# Synchronizer settings -# -Sync { - Mode PERSISTENT { - # - # If a conntrack entry is not modified in <= 15 seconds, then - # a message is broadcasted. This mechanism is used to - # resynchronize nodes that just joined the multicast group - # - RefreshTime 15 - - # - # If we don't receive a notification about the state of - # an entry in the external cache after N seconds, then - # remove it. - # - CacheTimeout 180 - - # - # Entries committed to the connection tracking table - # starts with a limited timeout of N seconds until the - # takeover process is completed. - # - CommitTimeout 180 - } - - # - # Multicast IP and interface where messages are - # broadcasted (dedicated link). IMPORTANT: Make sure - # that iptables accepts traffic for destination - # 225.0.0.50, eg: - # - # iptables -I INPUT -d 225.0.0.50 -j ACCEPT - # iptables -I OUTPUT -d 225.0.0.50 -j ACCEPT - # - Multicast { - IPv4_address 225.0.0.50 - IPv4_interface 192.168.100.100 # IP of dedicated link - Interface eth2 - Group 3780 - } - - # Enable/Disable message checksumming - Checksum on - - # Uncomment this if you want to replicate just certain TCP states. - # This option introduces a tradeoff in the replication: it reduces - # CPU consumption and lost messages rate at the cost of having - # backup replicas that don't contain the current state that the active - # replica holds. TCP states are: SYN_SENT, SYN_RECV, ESTABLISHED, - # FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN. - # - # Replicate ESTABLISHED TIME_WAIT for TCP - - # If you have a multiprimary setup (active-active) without connection - # persistency, ie. you can't know which firewall handles a packet - # that is part of a connection, then you need direct commit of - # conntrack entries to the kernel conntrack table. OSPF setups must - # set on this option. Default is Off. - # - # CacheWriteThrough On -} - -# -# General settings -# -General { - # - # Number of buckets in the caches: hash table - # - HashSize 8192 - - # - # Maximum number of conntracks: - # it must be >= $ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max - # - HashLimit 65535 - - # - # Logfile: on, off, or a filename - # Default: on (/var/log/conntrackd.log) - # - #LogFile off - - # - # Syslog: on, off or a facility name (daemon (default) or local0..7) - # Default: off - # - #Syslog on - - # - # Lockfile - # - LockFile /var/lock/conntrack.lock - - # - # Unix socket configuration - # - UNIX { - Path /tmp/sync.sock - Backlog 20 - } - - # - # Netlink socket buffer size - # - SocketBufferSize 262142 - - # - # Increase the socket buffer up to maximum if required - # - SocketBufferSizeMaxGrown 655355 -} - -# -# Ignore traffic for a certain set of IP's: Usually -# all the IP assigned to the firewall since local -# traffic must be ignored, just forwarded connections -# are worth to replicate -# -IgnoreTrafficFor { - IPv4_address 127.0.0.1 # loopback - IPv4_address 192.168.0.1 - IPv4_address 192.168.1.1 - IPv4_address 192.168.100.100 # dedicated link ip - IPv4_address 192.168.0.100 # virtual IP 1 - IPv4_address 192.168.1.100 # virtual IP 2 -} - -# -# Do not replicate certain protocol traffic -# -IgnoreProtocol { - UDP - ICMP - IGMP - VRRP - # numeric numbers also valid -} diff --git a/examples/sync/persistent/node1/keepalived.conf b/examples/sync/persistent/node1/keepalived.conf deleted file mode 100644 index f937467..0000000 --- a/examples/sync/persistent/node1/keepalived.conf +++ /dev/null @@ -1,39 +0,0 @@ -vrrp_sync_group G1 { # must be before vrrp_instance declaration - group { - VI_1 - VI_2 - } - notify_master /etc/conntrackd/script_master.sh - notify_backup /etc/conntrackd/script_backup.sh -# notify_fault /etc/conntrackd/script_fault.sh -} - -vrrp_instance VI_1 { - interface eth1 - state SLAVE - virtual_router_id 61 - priority 80 - advert_int 3 - authentication { - auth_type PASS - auth_pass papas_con_tomate - } - virtual_ipaddress { - 192.168.0.100 # default CIDR mask is /32 - } -} - -vrrp_instance VI_2 { - interface eth0 - state SLAVE - virtual_router_id 62 - priority 80 - advert_int 3 - authentication { - auth_type PASS - auth_pass papas_con_tomate - } - virtual_ipaddress { - 192.168.1.100 - } -} diff --git a/examples/sync/persistent/node2/conntrackd.conf b/examples/sync/persistent/node2/conntrackd.conf deleted file mode 100644 index 32416d0..0000000 --- a/examples/sync/persistent/node2/conntrackd.conf +++ /dev/null @@ -1,140 +0,0 @@ -# -# Synchronizer settings -# -Sync { - Mode PERSISTENT { - # - # If a conntrack entry is not modified in <= 15 seconds, then - # a message is broadcasted. This mechanism is used to - # resynchronize nodes that just joined the multicast group - # - RefreshTime 15 - - # - # If we don't receive a notification about the state of - # an entry in the external cache after N seconds, then - # remove it. - # - CacheTimeout 180 - - # - # Entries committed to the connection tracking table - # starts with a limited timeout of N seconds until the - # takeover process is completed. - # - CommitTimeout 180 - } - - # - # Multicast IP and interface where messages are - # broadcasted (dedicated link). IMPORTANT: Make sure - # that iptables accepts traffic for destination - # 225.0.0.50, eg: - # - # iptables -I INPUT -d 225.0.0.50 -j ACCEPT - # iptables -I OUTPUT -d 225.0.0.50 -j ACCEPT - # - Multicast { - IPv4_address 225.0.0.50 - IPv4_interface 192.168.100.200 # IP of dedicated link - Interface eth2 - Group 3780 - } - - # Enable/Disable message checksumming - Checksum on - - # Uncomment this if you want to replicate just certain TCP states. - # This option introduces a tradeoff in the replication: it reduces - # CPU consumption and lost messages rate at the cost of having - # backup replicas that don't contain the current state that the active - # replica holds. TCP states are: SYN_SENT, SYN_RECV, ESTABLISHED, - # FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN. - # - # Replicate ESTABLISHED TIME_WAIT for TCP - - # If you have a multiprimary setup (active-active) without connection - # persistency, ie. you can't know which firewall handles a packet - # that is part of a connection, then you need direct commit of - # conntrack entries to the kernel conntrack table. OSPF setups must - # set on this option. Default is Off. - # - # CacheWriteThrough On -} - -# -# General settings -# -General { - # - # Number of buckets in the caches: hash table - # - HashSize 8192 - - # - # Maximum number of conntracks: - # it must be >= $ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max - # - HashLimit 65535 - - # - # Logfile: on, off, or a filename - # Default: on (/var/log/conntrackd.log) - # - #LogFile off - - # - # Syslog: on, off or a facility name (daemon (default) or local0..7) - # Default: off - # - #Syslog on - - # - # Lockfile - # - LockFile /var/lock/conntrack.lock - - # - # Unix socket configuration - # - UNIX { - Path /tmp/sync.sock - Backlog 20 - } - - # - # Netlink socket buffer size - # - SocketBufferSize 262142 - - # - # Increase the socket buffer up to maximum if required - # - SocketBufferSizeMaxGrown 655355 -} - -# -# Ignore traffic for a certain set of IP's: Usually -# all the IP assigned to the firewall since local -# traffic must be ignored, just forwarded connections -# are worth to replicate -# -IgnoreTrafficFor { - IPv4_address 127.0.0.1 # loopback - IPv4_address 192.168.0.2 - IPv4_address 192.168.1.2 - IPv4_address 192.168.100.200 # dedicated link ip - IPv4_address 192.168.0.200 # virtual IP 1 - IPv4_address 192.168.1.200 # virtual IP 2 -} - -# -# Do not replicate certain protocol traffic -# -IgnoreProtocol { - UDP - ICMP - IGMP - VRRP - # numeric numbers also valid -} diff --git a/examples/sync/persistent/node2/keepalived.conf b/examples/sync/persistent/node2/keepalived.conf deleted file mode 100644 index f937467..0000000 --- a/examples/sync/persistent/node2/keepalived.conf +++ /dev/null @@ -1,39 +0,0 @@ -vrrp_sync_group G1 { # must be before vrrp_instance declaration - group { - VI_1 - VI_2 - } - notify_master /etc/conntrackd/script_master.sh - notify_backup /etc/conntrackd/script_backup.sh -# notify_fault /etc/conntrackd/script_fault.sh -} - -vrrp_instance VI_1 { - interface eth1 - state SLAVE - virtual_router_id 61 - priority 80 - advert_int 3 - authentication { - auth_type PASS - auth_pass papas_con_tomate - } - virtual_ipaddress { - 192.168.0.100 # default CIDR mask is /32 - } -} - -vrrp_instance VI_2 { - interface eth0 - state SLAVE - virtual_router_id 62 - priority 80 - advert_int 3 - authentication { - auth_type PASS - auth_pass papas_con_tomate - } - virtual_ipaddress { - 192.168.1.100 - } -} diff --git a/examples/sync/persistent/script_backup.sh b/examples/sync/persistent/script_backup.sh deleted file mode 100755 index 8ea2ad8..0000000 --- a/examples/sync/persistent/script_backup.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -/usr/sbin/conntrackd -B diff --git a/examples/sync/persistent/script_master.sh b/examples/sync/persistent/script_master.sh deleted file mode 100755 index 70c26c9..0000000 --- a/examples/sync/persistent/script_master.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -/usr/sbin/conntrackd -c -/usr/sbin/conntrackd -R diff --git a/include/conntrackd.h b/include/conntrackd.h index 2722f00..1bb3879 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -34,11 +34,11 @@ #define DEFAULT_SYSLOG_FACILITY LOG_DAEMON enum { - SYNC_MODE_PERSISTENT_BIT = 0, - SYNC_MODE_PERSISTENT = (1 << SYNC_MODE_PERSISTENT_BIT), + SYNC_MODE_ALARM_BIT = 0, + SYNC_MODE_ALARM = (1 << SYNC_MODE_ALARM_BIT), - SYNC_MODE_NACK_BIT = 1, - SYNC_MODE_NACK = (1 << SYNC_MODE_NACK_BIT), + SYNC_MODE_FTFW_BIT = 1, + SYNC_MODE_FTFW = (1 << SYNC_MODE_FTFW_BIT), DONT_CHECKSUM_BIT = 2, DONT_CHECKSUM = (1 << DONT_CHECKSUM_BIT), @@ -84,7 +84,7 @@ struct ct_conf { unsigned int listen_to_len; unsigned int flags; int family; /* protocol family */ - unsigned int resend_buffer_size;/* NACK protocol */ + unsigned int resend_buffer_size;/* FTFW protocol */ unsigned int window_size; int cache_write_through; }; diff --git a/include/sync.h b/include/sync.h index 6345513..a27fb93 100644 --- a/include/sync.h +++ b/include/sync.h @@ -18,7 +18,7 @@ struct sync_mode { void (*run)(int step); }; -extern struct sync_mode notrack; -extern struct sync_mode nack; +extern struct sync_mode alarm; +extern struct sync_mode ftfw; #endif diff --git a/src/Makefile.am b/src/Makefile.am index 8f5c620..1fac3dc 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -15,7 +15,7 @@ conntrackd_SOURCES = alarm.c main.c run.c hash.c buffer.c \ ignore_pool.c \ cache.c cache_iterators.c \ cache_lifetime.c cache_timer.c cache_wt.c \ - sync-mode.c sync-notrack.c sync-nack.c \ + sync-mode.c sync-alarm.c sync-ftfw.c \ traffic_stats.c stats-mode.c \ network.c \ state_helper.c state_helper_tcp.c \ diff --git a/src/main.c b/src/main.c index 712b572..a3164a6 100644 --- a/src/main.c +++ b/src/main.c @@ -46,7 +46,7 @@ static const char usage_client_commands[] = " -k, kill conntrack daemon\n" " -s, dump statistics\n" " -R, resync with kernel conntrack table\n" - " -n, request resync with other node (only NACK mode)\n" + " -n, request resync with other node (only FT-FW mode)\n" " -x, dump cache in XML format (requires -i or -e)"; static const char usage_options[] = diff --git a/src/read_config_lex.l b/src/read_config_lex.l index 844cae1..55794a8 100644 --- a/src/read_config_lex.l +++ b/src/read_config_lex.l @@ -45,6 +45,8 @@ ip6 {ip6_form1}|{ip6_form2} string [a-zA-Z][a-zA-Z0-9]* persistent [P|p][E|e][R|r][S|s][I|i][S|s][T|t][E|e][N|n][T|T] nack [N|n][A|a][C|c][K|k] +alarm [A|a][L|l][A|a][R|r][M|m] +ftfw [F|f][T|t][F|f][W|w] %% "UNIX" { return T_UNIX; } @@ -107,8 +109,16 @@ nack [N|n][A|a][C|c][K|k] {ip4} { yylval.string = strdup(yytext); return T_IP; } {ip6} { yylval.string = strdup(yytext); return T_IP; } {path} { yylval.string = strdup(yytext); return T_PATH_VAL; } -{persistent} { return T_PERSISTENT; } -{nack} { return T_NACK; } +{alarm} { return T_ALARM; } +{persistent} { printf("WARNING: Now `persistent' mode is called " + "`alarm'. Please, update your " + "your conntrackd.conf file.\n"); + return T_ALARM; } +{ftfw} { return T_FTFW; } +{nack} { printf("WARNING: Now `nack' mode is called " + "`ftfw'. Please, update your " + "your conntrackd.conf file.\n"); + return T_FTFW; } {string} { yylval.string = strdup(yytext); return T_STRING; } {comment} ; diff --git a/src/read_config_yy.y b/src/read_config_yy.y index e5ce195..795aae9 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -45,7 +45,7 @@ struct ct_conf conf; %token T_LOCK T_STRIP_NAT T_BUFFER_SIZE_MAX_GROWN T_EXPIRE T_TIMEOUT %token T_GENERAL T_SYNC T_STATS T_RELAX_TRANSITIONS T_BUFFER_SIZE T_DELAY %token T_SYNC_MODE T_LISTEN_TO T_FAMILY T_RESEND_BUFFER_SIZE -%token T_PERSISTENT T_NACK T_CHECKSUM T_WINDOWSIZE T_ON T_OFF +%token T_ALARM T_FTFW T_CHECKSUM T_WINDOWSIZE T_ON T_OFF %token T_REPLICATE T_FOR T_IFACE %token T_ESTABLISHED T_SYN_SENT T_SYN_RECV T_FIN_WAIT %token T_CLOSE_WAIT T_LAST_ACK T_TIME_WAIT T_CLOSE T_LISTEN @@ -369,14 +369,14 @@ sync_line: refreshtime | cache_writethrough ; -sync_mode_persistent: T_SYNC_MODE T_PERSISTENT '{' sync_mode_persistent_list '}' +sync_mode_persistent: T_SYNC_MODE T_ALARM '{' sync_mode_persistent_list '}' { - conf.flags |= SYNC_MODE_PERSISTENT; + conf.flags |= SYNC_MODE_ALARM; }; -sync_mode_nack: T_SYNC_MODE T_NACK '{' sync_mode_nack_list '}' +sync_mode_nack: T_SYNC_MODE T_FTFW '{' sync_mode_nack_list '}' { - conf.flags |= SYNC_MODE_NACK; + conf.flags |= SYNC_MODE_FTFW; }; sync_mode_persistent_list: diff --git a/src/sync-alarm.c b/src/sync-alarm.c new file mode 100644 index 0000000..a0791ac --- /dev/null +++ b/src/sync-alarm.c @@ -0,0 +1,104 @@ +/* + * (C) 2006-2007 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "conntrackd.h" +#include "sync.h" +#include "network.h" +#include "us-conntrack.h" +#include "alarm.h" + +static void refresher(struct alarm_list *a, void *data) +{ + int len; + struct nethdr *net; + struct us_conntrack *u = data; + + debug_ct(u->ct, "persistence update"); + + a->expires = random() % CONFIG(refresh) + 1; + net = BUILD_NETMSG(u->ct, NFCT_Q_UPDATE); + len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); + mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); +} + +static void cache_alarm_add(struct us_conntrack *u, void *data) +{ + struct alarm_list *alarm = data; + + init_alarm(alarm); + set_alarm_expiration(alarm, (random() % conf.refresh) + 1); + set_alarm_data(alarm, u); + set_alarm_function(alarm, refresher); + add_alarm(alarm); +} + +static void cache_alarm_update(struct us_conntrack *u, void *data) +{ + struct alarm_list *alarm = data; + mod_alarm(alarm, (random() % conf.refresh) + 1); +} + +static void cache_alarm_destroy(struct us_conntrack *u, void *data) +{ + struct alarm_list *alarm = data; + del_alarm(alarm); +} + +static struct cache_extra cache_alarm_extra = { + .size = sizeof(struct alarm_list), + .add = cache_alarm_add, + .update = cache_alarm_update, + .destroy = cache_alarm_destroy +}; + +static int alarm_recv(const struct nethdr *net) +{ + unsigned int exp_seq; + + /* + * Ignore error messages: Although this message type is not ever + * generated in alarm mode, we don't want to crash the daemon + * if someone nuts mixes ftfw and alarm. + */ + if (net->flags) + return 1; + + /* + * Multicast sequence tracking: we keep track of multicast messages + * although we don't do any explicit message recovery. So, why do + * we do sequence tracking? Just to let know the sysadmin. + * + * Let t be 1 < t < RefreshTime. To ensure consistency, conntrackd + * retransmit every t seconds a message with the state of a certain + * entry even if such entry did not change. This mechanism also + * provides passive resynchronization, in other words, there is + * no facility to request a full synchronization from new nodes that + * just joined the cluster, instead they just get resynchronized in + * RefreshTime seconds at worst case. + */ + mcast_track_seq(net->seq, &exp_seq); + + return 0; +} + +struct sync_mode alarm = { + .internal_cache_flags = LIFETIME, + .external_cache_flags = TIMER | LIFETIME, + .internal_cache_extra = &cache_alarm_extra, + .recv = alarm_recv, +}; diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c new file mode 100644 index 0000000..2f27fe6 --- /dev/null +++ b/src/sync-ftfw.c @@ -0,0 +1,366 @@ +/* + * (C) 2006-2007 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include "conntrackd.h" +#include "sync.h" +#include "linux_list.h" +#include "us-conntrack.h" +#include "buffer.h" +#include "debug.h" +#include "network.h" +#include "alarm.h" +#include +#include + +#if 0 +#define dp printf +#else +#define dp +#endif + +static LIST_HEAD(rs_list); +static LIST_HEAD(tx_list); +static unsigned int tx_list_len; +static struct buffer *rs_queue; +static struct buffer *tx_queue; + +struct cache_ftfw { + struct list_head rs_list; + struct list_head tx_list; + u_int32_t seq; +}; + +static void cache_ftfw_add(struct us_conntrack *u, void *data) +{ + struct cache_ftfw *cn = data; + INIT_LIST_HEAD(&cn->rs_list); + INIT_LIST_HEAD(&cn->tx_list); +} + +static void cache_ftfw_del(struct us_conntrack *u, void *data) +{ + struct cache_ftfw *cn = data; + + if (cn->rs_list.next == &cn->rs_list && + cn->rs_list.prev == &cn->rs_list) + return; + + list_del(&cn->rs_list); +} + +static struct cache_extra cache_ftfw_extra = { + .size = sizeof(struct cache_ftfw), + .add = cache_ftfw_add, + .destroy = cache_ftfw_del +}; + +static int ftfw_init() +{ + tx_queue = buffer_create(CONFIG(resend_buffer_size)); + if (tx_queue == NULL) { + dlog(STATE(log), LOG_ERR, "cannot create tx buffer"); + return -1; + } + + rs_queue = buffer_create(CONFIG(resend_buffer_size)); + if (rs_queue == NULL) { + dlog(STATE(log), LOG_ERR, "cannot create rs buffer"); + return -1; + } + + INIT_LIST_HEAD(&tx_list); + INIT_LIST_HEAD(&rs_list); + + return 0; +} + +static void ftfw_kill() +{ + buffer_destroy(rs_queue); + buffer_destroy(tx_queue); +} + +static void tx_queue_add_ctlmsg(u_int32_t flags, u_int32_t from, u_int32_t to) +{ + struct nethdr_ack ack = { + .flags = flags, + .from = from, + .to = to, + }; + + buffer_add(tx_queue, &ack, NETHDR_ACK_SIZ); +} + +static int do_cache_to_tx(void *data1, void *data2) +{ + struct us_conntrack *u = data2; + struct cache_ftfw *cn = cache_get_extra(STATE_SYNC(internal), u); + + /* add to tx list */ + list_add(&cn->tx_list, &tx_list); + tx_list_len++; + + return 0; +} + +static int ftfw_local(int fd, int type, void *data) +{ + int ret = 1; + + switch(type) { + case REQUEST_DUMP: + dlog(STATE(log), LOG_NOTICE, "request resync"); + tx_queue_add_ctlmsg(NET_F_RESYNC, 0, 0); + break; + case SEND_BULK: + dlog(STATE(log), LOG_NOTICE, "sending bulk update"); + cache_iterate(STATE_SYNC(internal), NULL, do_cache_to_tx); + break; + default: + ret = 0; + break; + } + + return ret; +} + +static int rs_queue_to_tx(void *data1, void *data2) +{ + struct nethdr *net = data1; + struct nethdr_ack *nack = data2; + + if (between(net->seq, nack->from, nack->to)) { + dp("rs_queue_to_tx sq: %u fl:%u len:%u\n", + net->seq, net->flags, net->len); + buffer_add(tx_queue, net, net->len); + } + return 0; +} + +static int rs_queue_empty(void *data1, void *data2) +{ + struct nethdr *net = data1; + struct nethdr_ack *h = data2; + + if (between(net->seq, h->from, h->to)) { + dp("remove from buffer (seq=%u)\n", net->seq); + buffer_del(rs_queue, data1); + } + return 0; +} + +static void rs_list_to_tx(struct cache *c, unsigned int from, unsigned int to) +{ + struct list_head *n; + struct us_conntrack *u; + + list_for_each(n, &rs_list) { + struct cache_ftfw *cn = (struct cache_ftfw *) n; + struct us_conntrack *u; + + u = cache_get_conntrack(STATE_SYNC(internal), cn); + if (between(cn->seq, from, to)) { + dp("resending nack'ed (oldseq=%u)\n", cn->seq); + list_add(&cn->tx_list, &tx_list); + tx_list_len++; + } + } +} + +static void rs_list_empty(struct cache *c, unsigned int from, unsigned int to) +{ + struct list_head *n, *tmp; + + list_for_each_safe(n, tmp, &rs_list) { + struct cache_ftfw *cn = (struct cache_ftfw *) n; + struct us_conntrack *u; + + u = cache_get_conntrack(STATE_SYNC(internal), cn); + if (between(cn->seq, from, to)) { + dp("queue: deleting from queue (seq=%u)\n", cn->seq); + list_del(&cn->rs_list); + INIT_LIST_HEAD(&cn->rs_list); + } + } +} + +static int ftfw_recv(const struct nethdr *net) +{ + static unsigned int window = 0; + unsigned int exp_seq; + + if (window == 0) + window = CONFIG(window_size); + + if (!mcast_track_seq(net->seq, &exp_seq)) { + dp("OOS: sending nack (seq=%u)\n", exp_seq); + tx_queue_add_ctlmsg(NET_F_NACK, exp_seq, net->seq-1); + window = CONFIG(window_size); + } else { + /* received a window, send an acknowledgement */ + if (--window == 0) { + dp("sending ack (seq=%u)\n", net->seq); + tx_queue_add_ctlmsg(NET_F_ACK, + net->seq - CONFIG(window_size), + net->seq); + } + } + + if (IS_NACK(net)) { + struct nethdr_ack *nack = (struct nethdr_ack *) net; + + dp("NACK: from seq=%u to seq=%u\n", nack->from, nack->to); + rs_list_to_tx(STATE_SYNC(internal), nack->from, nack->to); + buffer_iterate(rs_queue, nack, rs_queue_to_tx); + return 1; + } else if (IS_RESYNC(net)) { + dp("RESYNC ALL\n"); + cache_iterate(STATE_SYNC(internal), NULL, do_cache_to_tx); + return 1; + } else if (IS_ACK(net)) { + struct nethdr_ack *h = (struct nethdr_ack *) net; + + dp("ACK: from seq=%u to seq=%u\n", h->from, h->to); + rs_list_empty(STATE_SYNC(internal), h->from, h->to); + buffer_iterate(rs_queue, h, rs_queue_empty); + return 1; + } else if (IS_ALIVE(net)) + return 1; + + return 0; +} + +static void ftfw_send(struct nethdr *net, struct us_conntrack *u) +{ + struct netpld *pld = NETHDR_DATA(net); + struct cache_ftfw *cn; + + HDR_NETWORK2HOST(net); + + switch(ntohs(pld->query)) { + case NFCT_Q_CREATE: + case NFCT_Q_UPDATE: + cn = (struct cache_ftfw *) + cache_get_extra(STATE_SYNC(internal), u); + + if (cn->rs_list.next == &cn->rs_list && + cn->rs_list.prev == &cn->rs_list) + goto insert; + + list_del(&cn->rs_list); + INIT_LIST_HEAD(&cn->rs_list); +insert: + cn->seq = net->seq; + list_add(&cn->rs_list, &rs_list); + break; + case NFCT_Q_DESTROY: + buffer_add(rs_queue, net, net->len); + break; + } +} + +static int tx_queue_xmit(void *data1, void *data2) +{ + struct nethdr *net = data1; + int len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); + + dp("tx_queue sq: %u fl:%u len:%u\n", + ntohl(net->seq), ntohs(net->flags), ntohs(net->len)); + + mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); + HDR_NETWORK2HOST(net); + + if (IS_DATA(net) || IS_ACK(net) || IS_NACK(net)) { + dp("-> back_to_tx_queue sq: %u fl:%u len:%u\n", + net->seq, net->flags, net->len); + buffer_add(rs_queue, net, net->len); + } + buffer_del(tx_queue, net); + + return 0; +} + +static int tx_list_xmit(struct list_head *i, struct us_conntrack *u) +{ + int ret; + struct nethdr *net = BUILD_NETMSG(u->ct, NFCT_Q_UPDATE); + int len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); + + dp("tx_list sq: %u fl:%u len:%u\n", + ntohl(net->seq), ntohs(net->flags), + ntohs(net->len)); + + list_del(i); + INIT_LIST_HEAD(i); + tx_list_len--; + + ret = mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); + if (STATE_SYNC(sync)->send) + STATE_SYNC(sync)->send(net, u); + + return ret; +} + +static struct alarm_list alive_alarm; + +static void do_alive_alarm(struct alarm_list *a, void *data) +{ + del_alarm(a); + tx_queue_add_ctlmsg(NET_F_ALIVE, 0, 0); +} + +static void ftfw_run(int step) +{ + struct list_head *i, *tmp; + + /* send messages in the tx_queue */ + buffer_iterate(tx_queue, NULL, tx_queue_xmit); + + /* send conntracks in the tx_list */ + list_for_each_safe(i, tmp, &tx_list) { + struct cache_ftfw *cn; + struct us_conntrack *u; + + cn = container_of(i, struct cache_ftfw, tx_list); + u = cache_get_conntrack(STATE_SYNC(internal), cn); + tx_list_xmit(i, u); + } + + if (alive_alarm.expires > 0) + mod_alarm(&alive_alarm, 1); + else { + init_alarm(&alive_alarm); + /* XXX: alive message expiration configurable */ + set_alarm_expiration(&alive_alarm, 1); + set_alarm_function(&alive_alarm, do_alive_alarm); + add_alarm(&alive_alarm); + } +} + +struct sync_mode ftfw = { + .internal_cache_flags = LIFETIME, + .external_cache_flags = LIFETIME, + .internal_cache_extra = &cache_ftfw_extra, + .init = ftfw_init, + .kill = ftfw_kill, + .local = ftfw_local, + .recv = ftfw_recv, + .send = ftfw_send, + .run = ftfw_run, +}; diff --git a/src/sync-mode.c b/src/sync-mode.c index 8a19ac5..7cd2b84 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -126,11 +126,11 @@ static int init_sync(void) } memset(state.sync, 0, sizeof(struct ct_sync_state)); - if (CONFIG(flags) & SYNC_MODE_NACK) - STATE_SYNC(sync) = &nack; + if (CONFIG(flags) & SYNC_MODE_FTFW) + STATE_SYNC(sync) = &ftfw; else - /* default to persistent mode */ - STATE_SYNC(sync) = ¬rack; + /* default to ftfw mode */ + STATE_SYNC(sync) = &ftfw; if (STATE_SYNC(sync)->init) STATE_SYNC(sync)->init(); diff --git a/src/sync-nack.c b/src/sync-nack.c deleted file mode 100644 index fa61be4..0000000 --- a/src/sync-nack.c +++ /dev/null @@ -1,366 +0,0 @@ -/* - * (C) 2006-2007 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include "conntrackd.h" -#include "sync.h" -#include "linux_list.h" -#include "us-conntrack.h" -#include "buffer.h" -#include "debug.h" -#include "network.h" -#include "alarm.h" -#include -#include - -#if 0 -#define dp printf -#else -#define dp -#endif - -static LIST_HEAD(rs_list); -static LIST_HEAD(tx_list); -static unsigned int tx_list_len; -static struct buffer *rs_queue; -static struct buffer *tx_queue; - -struct cache_nack { - struct list_head rs_list; - struct list_head tx_list; - u_int32_t seq; -}; - -static void cache_nack_add(struct us_conntrack *u, void *data) -{ - struct cache_nack *cn = data; - INIT_LIST_HEAD(&cn->rs_list); - INIT_LIST_HEAD(&cn->tx_list); -} - -static void cache_nack_del(struct us_conntrack *u, void *data) -{ - struct cache_nack *cn = data; - - if (cn->rs_list.next == &cn->rs_list && - cn->rs_list.prev == &cn->rs_list) - return; - - list_del(&cn->rs_list); -} - -static struct cache_extra cache_nack_extra = { - .size = sizeof(struct cache_nack), - .add = cache_nack_add, - .destroy = cache_nack_del -}; - -static int nack_init() -{ - tx_queue = buffer_create(CONFIG(resend_buffer_size)); - if (tx_queue == NULL) { - dlog(STATE(log), LOG_ERR, "cannot create tx buffer"); - return -1; - } - - rs_queue = buffer_create(CONFIG(resend_buffer_size)); - if (rs_queue == NULL) { - dlog(STATE(log), LOG_ERR, "cannot create rs buffer"); - return -1; - } - - INIT_LIST_HEAD(&tx_list); - INIT_LIST_HEAD(&rs_list); - - return 0; -} - -static void nack_kill() -{ - buffer_destroy(rs_queue); - buffer_destroy(tx_queue); -} - -static void tx_queue_add_ctlmsg(u_int32_t flags, u_int32_t from, u_int32_t to) -{ - struct nethdr_ack ack = { - .flags = flags, - .from = from, - .to = to, - }; - - buffer_add(tx_queue, &ack, NETHDR_ACK_SIZ); -} - -static int do_cache_to_tx(void *data1, void *data2) -{ - struct us_conntrack *u = data2; - struct cache_nack *cn = cache_get_extra(STATE_SYNC(internal), u); - - /* add to tx list */ - list_add(&cn->tx_list, &tx_list); - tx_list_len++; - - return 0; -} - -static int nack_local(int fd, int type, void *data) -{ - int ret = 1; - - switch(type) { - case REQUEST_DUMP: - dlog(STATE(log), LOG_NOTICE, "request resync"); - tx_queue_add_ctlmsg(NET_F_RESYNC, 0, 0); - break; - case SEND_BULK: - dlog(STATE(log), LOG_NOTICE, "sending bulk update"); - cache_iterate(STATE_SYNC(internal), NULL, do_cache_to_tx); - break; - default: - ret = 0; - break; - } - - return ret; -} - -static int rs_queue_to_tx(void *data1, void *data2) -{ - struct nethdr *net = data1; - struct nethdr_ack *nack = data2; - - if (between(net->seq, nack->from, nack->to)) { - dp("rs_queue_to_tx sq: %u fl:%u len:%u\n", - net->seq, net->flags, net->len); - buffer_add(tx_queue, net, net->len); - } - return 0; -} - -static int rs_queue_empty(void *data1, void *data2) -{ - struct nethdr *net = data1; - struct nethdr_ack *h = data2; - - if (between(net->seq, h->from, h->to)) { - dp("remove from buffer (seq=%u)\n", net->seq); - buffer_del(rs_queue, data1); - } - return 0; -} - -static void rs_list_to_tx(struct cache *c, unsigned int from, unsigned int to) -{ - struct list_head *n; - struct us_conntrack *u; - - list_for_each(n, &rs_list) { - struct cache_nack *cn = (struct cache_nack *) n; - struct us_conntrack *u; - - u = cache_get_conntrack(STATE_SYNC(internal), cn); - if (between(cn->seq, from, to)) { - dp("resending nack'ed (oldseq=%u)\n", cn->seq); - list_add(&cn->tx_list, &tx_list); - tx_list_len++; - } - } -} - -static void rs_list_empty(struct cache *c, unsigned int from, unsigned int to) -{ - struct list_head *n, *tmp; - - list_for_each_safe(n, tmp, &rs_list) { - struct cache_nack *cn = (struct cache_nack *) n; - struct us_conntrack *u; - - u = cache_get_conntrack(STATE_SYNC(internal), cn); - if (between(cn->seq, from, to)) { - dp("queue: deleting from queue (seq=%u)\n", cn->seq); - list_del(&cn->rs_list); - INIT_LIST_HEAD(&cn->rs_list); - } - } -} - -static int nack_recv(const struct nethdr *net) -{ - static unsigned int window = 0; - unsigned int exp_seq; - - if (window == 0) - window = CONFIG(window_size); - - if (!mcast_track_seq(net->seq, &exp_seq)) { - dp("OOS: sending nack (seq=%u)\n", exp_seq); - tx_queue_add_ctlmsg(NET_F_NACK, exp_seq, net->seq-1); - window = CONFIG(window_size); - } else { - /* received a window, send an acknowledgement */ - if (--window == 0) { - dp("sending ack (seq=%u)\n", net->seq); - tx_queue_add_ctlmsg(NET_F_ACK, - net->seq - CONFIG(window_size), - net->seq); - } - } - - if (IS_NACK(net)) { - struct nethdr_ack *nack = (struct nethdr_ack *) net; - - dp("NACK: from seq=%u to seq=%u\n", nack->from, nack->to); - rs_list_to_tx(STATE_SYNC(internal), nack->from, nack->to); - buffer_iterate(rs_queue, nack, rs_queue_to_tx); - return 1; - } else if (IS_RESYNC(net)) { - dp("RESYNC ALL\n"); - cache_iterate(STATE_SYNC(internal), NULL, do_cache_to_tx); - return 1; - } else if (IS_ACK(net)) { - struct nethdr_ack *h = (struct nethdr_ack *) net; - - dp("ACK: from seq=%u to seq=%u\n", h->from, h->to); - rs_list_empty(STATE_SYNC(internal), h->from, h->to); - buffer_iterate(rs_queue, h, rs_queue_empty); - return 1; - } else if (IS_ALIVE(net)) - return 1; - - return 0; -} - -static void nack_send(struct nethdr *net, struct us_conntrack *u) -{ - struct netpld *pld = NETHDR_DATA(net); - struct cache_nack *cn; - - HDR_NETWORK2HOST(net); - - switch(ntohs(pld->query)) { - case NFCT_Q_CREATE: - case NFCT_Q_UPDATE: - cn = (struct cache_nack *) - cache_get_extra(STATE_SYNC(internal), u); - - if (cn->rs_list.next == &cn->rs_list && - cn->rs_list.prev == &cn->rs_list) - goto insert; - - list_del(&cn->rs_list); - INIT_LIST_HEAD(&cn->rs_list); -insert: - cn->seq = net->seq; - list_add(&cn->rs_list, &rs_list); - break; - case NFCT_Q_DESTROY: - buffer_add(rs_queue, net, net->len); - break; - } -} - -static int tx_queue_xmit(void *data1, void *data2) -{ - struct nethdr *net = data1; - int len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); - - dp("tx_queue sq: %u fl:%u len:%u\n", - ntohl(net->seq), ntohs(net->flags), ntohs(net->len)); - - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); - HDR_NETWORK2HOST(net); - - if (IS_DATA(net) || IS_ACK(net) || IS_NACK(net)) { - dp("-> back_to_tx_queue sq: %u fl:%u len:%u\n", - net->seq, net->flags, net->len); - buffer_add(rs_queue, net, net->len); - } - buffer_del(tx_queue, net); - - return 0; -} - -static int tx_list_xmit(struct list_head *i, struct us_conntrack *u) -{ - int ret; - struct nethdr *net = BUILD_NETMSG(u->ct, NFCT_Q_UPDATE); - int len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); - - dp("tx_list sq: %u fl:%u len:%u\n", - ntohl(net->seq), ntohs(net->flags), - ntohs(net->len)); - - list_del(i); - INIT_LIST_HEAD(i); - tx_list_len--; - - ret = mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); - if (STATE_SYNC(sync)->send) - STATE_SYNC(sync)->send(net, u); - - return ret; -} - -static struct alarm_list alive_alarm; - -static void do_alive_alarm(struct alarm_list *a, void *data) -{ - del_alarm(a); - tx_queue_add_ctlmsg(NET_F_ALIVE, 0, 0); -} - -static void nack_run(int step) -{ - struct list_head *i, *tmp; - - /* send messages in the tx_queue */ - buffer_iterate(tx_queue, NULL, tx_queue_xmit); - - /* send conntracks in the tx_list */ - list_for_each_safe(i, tmp, &tx_list) { - struct cache_nack *cn; - struct us_conntrack *u; - - cn = container_of(i, struct cache_nack, tx_list); - u = cache_get_conntrack(STATE_SYNC(internal), cn); - tx_list_xmit(i, u); - } - - if (alive_alarm.expires > 0) - mod_alarm(&alive_alarm, 1); - else { - init_alarm(&alive_alarm); - /* XXX: alive message expiration configurable */ - set_alarm_expiration(&alive_alarm, 1); - set_alarm_function(&alive_alarm, do_alive_alarm); - add_alarm(&alive_alarm); - } -} - -struct sync_mode nack = { - .internal_cache_flags = LIFETIME, - .external_cache_flags = LIFETIME, - .internal_cache_extra = &cache_nack_extra, - .init = nack_init, - .kill = nack_kill, - .local = nack_local, - .recv = nack_recv, - .send = nack_send, - .run = nack_run, -}; diff --git a/src/sync-notrack.c b/src/sync-notrack.c deleted file mode 100644 index 8588ecf..0000000 --- a/src/sync-notrack.c +++ /dev/null @@ -1,104 +0,0 @@ -/* - * (C) 2006-2007 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "conntrackd.h" -#include "sync.h" -#include "network.h" -#include "us-conntrack.h" -#include "alarm.h" - -static void refresher(struct alarm_list *a, void *data) -{ - int len; - struct nethdr *net; - struct us_conntrack *u = data; - - debug_ct(u->ct, "persistence update"); - - a->expires = random() % CONFIG(refresh) + 1; - net = BUILD_NETMSG(u->ct, NFCT_Q_UPDATE); - len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); -} - -static void cache_notrack_add(struct us_conntrack *u, void *data) -{ - struct alarm_list *alarm = data; - - init_alarm(alarm); - set_alarm_expiration(alarm, (random() % conf.refresh) + 1); - set_alarm_data(alarm, u); - set_alarm_function(alarm, refresher); - add_alarm(alarm); -} - -static void cache_notrack_update(struct us_conntrack *u, void *data) -{ - struct alarm_list *alarm = data; - mod_alarm(alarm, (random() % conf.refresh) + 1); -} - -static void cache_notrack_destroy(struct us_conntrack *u, void *data) -{ - struct alarm_list *alarm = data; - del_alarm(alarm); -} - -static struct cache_extra cache_notrack_extra = { - .size = sizeof(struct alarm_list), - .add = cache_notrack_add, - .update = cache_notrack_update, - .destroy = cache_notrack_destroy -}; - -static int notrack_recv(const struct nethdr *net) -{ - unsigned int exp_seq; - - /* - * Ignore error messages: Although this message type is not ever - * generated in notrack mode, we don't want to crash the daemon - * if someone nuts mixes nack and notrack. - */ - if (net->flags) - return 1; - - /* - * Multicast sequence tracking: we keep track of multicast messages - * although we don't do any explicit message recovery. So, why do - * we do sequence tracking? Just to let know the sysadmin. - * - * Let t be 1 < t < RefreshTime. To ensure consistency, conntrackd - * retransmit every t seconds a message with the state of a certain - * entry even if such entry did not change. This mechanism also - * provides passive resynchronization, in other words, there is - * no facility to request a full synchronization from new nodes that - * just joined the cluster, instead they just get resynchronized in - * RefreshTime seconds at worst case. - */ - mcast_track_seq(net->seq, &exp_seq); - - return 0; -} - -struct sync_mode notrack = { - .internal_cache_flags = LIFETIME, - .external_cache_flags = TIMER | LIFETIME, - .internal_cache_extra = &cache_notrack_extra, - .recv = notrack_recv, -}; -- cgit v1.2.3 From be072dced4efa3447a7c01d9f7dc90bd717fec7b Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Fri, 21 Dec 2007 18:08:48 +0000 Subject: fix minor typo in warning message --- src/read_config_lex.l | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/read_config_lex.l b/src/read_config_lex.l index 55794a8..81ae64f 100644 --- a/src/read_config_lex.l +++ b/src/read_config_lex.l @@ -110,13 +110,13 @@ ftfw [F|f][T|t][F|f][W|w] {ip6} { yylval.string = strdup(yytext); return T_IP; } {path} { yylval.string = strdup(yytext); return T_PATH_VAL; } {alarm} { return T_ALARM; } -{persistent} { printf("WARNING: Now `persistent' mode is called " - "`alarm'. Please, update your " +{persistent} { printf("\nWARNING: Now `persistent' mode is called " + "`alarm'. Please, update " "your conntrackd.conf file.\n"); return T_ALARM; } {ftfw} { return T_FTFW; } -{nack} { printf("WARNING: Now `nack' mode is called " - "`ftfw'. Please, update your " +{nack} { printf("\nWARNING: Now `nack' mode is called " + "`ftfw'. Please, update " "your conntrackd.conf file.\n"); return T_FTFW; } {string} { yylval.string = strdup(yytext); return T_STRING; } -- cgit v1.2.3 From fb17dccd91ba9448c2adaca2dcf0f9d665e1e8a4 Mon Sep 17 00:00:00 2001 From: "Ayuso/emailAddress=pablo@netfilter.org" Date: Fri, 21 Dec 2007 18:35:10 +0000 Subject: o add support for related conntracks (requires Linux kernel >= 2.6.22) o update leftover references to `persistent' and `nack' modes --- ChangeLog | 1 + INSTALL | 8 ++++---- TODO | 8 ++++---- src/build.c | 14 ++++++++++++++ src/parse.c | 6 ++++++ src/read_config_yy.y | 20 ++++++++++---------- 6 files changed, 39 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index e893439..2a3a112 100644 --- a/ChangeLog +++ b/ChangeLog @@ -22,6 +22,7 @@ o Use more appropriate names for the existing synchronization modes: o rename `nack' mode to `ftfw' o Now default synchronization mode is ftfw instead of alarm o rename `examples' directory to `doc' +o add support for related conntracks (requires Linux kernel >= 2.6.22) version 0.9.5 (2007/07/29) ------------------------------ diff --git a/INSTALL b/INSTALL index f619c1e..cfb642e 100644 --- a/INSTALL +++ b/INSTALL @@ -115,9 +115,9 @@ Copyright (C) 2005-2007 Pablo Neira Ayuso # cp examples/sync/_type_/node1/conntrackd.conf /etc/conntrackd.conf Where _type_ is the synchronization type selected, currently there are - two: the persistent mode and the NACK mode. The persistent mode consumes - more resources than the NACK mode but resolves synchronization issues - better. On the other the NACK mode reduces resource consumption. I'll + two: the alarm mode and the FTFW mode. The alarm mode consumes + more resources than the FTFW mode but resolves synchronization issues + better. On the other the FTFW mode reduces resource consumption. I'll provide more information on both approaches soon. Do not forget to edit the files in order to adapt them to the @@ -171,7 +171,7 @@ Copyright (C) 2005-2007 Pablo Neira Ayuso Therefore, on failure event, the candidate node takes over the virtual IPs and the connections that the failing active was processing. Observe - that this file differs for the NACK mode. + that this file differs for the FTFW mode. 6) Disable TCP window tracking diff --git a/TODO b/TODO index 7f5b949..61f7e69 100644 --- a/TODO +++ b/TODO @@ -3,12 +3,12 @@ by dificulty levels: = Relatively easy = [ ] improve shell scripts for keepalived/heartbeat: *really* important - [ ] NACK as default protocol - [ ] rename persistent to alarm + [X] NACK as default protocol + [X] rename persistent to alarm, rename nack to ftfw [X] manpage for conntrackd(8) [ ] add scripts to use the floating priority feature in keepalived to avoid premature take over. - [ ] ignorepool with unlimited size and ignore networks + [X] ignorepool with unlimited size and ignore networks [ ] selective conntracks removal [ ] debian/rpm packages [ ] improve website @@ -18,7 +18,7 @@ by dificulty levels: = Requires some work = [ ] study better keepalived transitions [ ] test/fix ipv6 support - [ ] add support setup related conntracks + [X] add support setup related conntracks [ ] NAT sequence adjustment support = Open issues that won't be ever resolved = diff --git a/src/build.c b/src/build.c index 109b26e..5fdc83f 100644 --- a/src/build.c +++ b/src/build.c @@ -102,6 +102,20 @@ void build_netpld(struct nf_conntrack *ct, struct netpld *pld, int query) if (nfct_attr_is_set(ct, ATTR_STATUS)) __build_u32(ct, pld, ATTR_STATUS); + /* setup the master conntrack */ + if (nfct_attr_is_set(ct, ATTR_MASTER_IPV4_SRC)) + __build_u32(ct, pld, ATTR_MASTER_IPV4_SRC); + if (nfct_attr_is_set(ct, ATTR_MASTER_IPV4_DST)) + __build_u32(ct, pld, ATTR_MASTER_IPV4_DST); + if (nfct_attr_is_set(ct, ATTR_MASTER_L3PROTO)) + __build_u8(ct, pld, ATTR_MASTER_L3PROTO); + if (nfct_attr_is_set(ct, ATTR_MASTER_PORT_SRC)) + __build_u16(ct, pld, ATTR_MASTER_PORT_SRC); + if (nfct_attr_is_set(ct, ATTR_MASTER_PORT_DST)) + __build_u16(ct, pld, ATTR_MASTER_PORT_DST); + if (nfct_attr_is_set(ct, ATTR_MASTER_L4PROTO)) + __build_u8(ct, pld, ATTR_MASTER_L4PROTO); + /* NAT */ if (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) { u_int32_t data = nfct_get_attr_u32(ct, ATTR_REPL_IPV4_DST); diff --git a/src/parse.c b/src/parse.c index 8816e7a..0650995 100644 --- a/src/parse.c +++ b/src/parse.c @@ -56,6 +56,12 @@ parse h[ATTR_MAX] = { [ATTR_MARK] = parse_u32, [ATTR_STATUS] = parse_u32, [ATTR_SECMARK] = parse_u32, + [ATTR_MASTER_IPV4_SRC] = parse_u32, + [ATTR_MASTER_IPV4_DST] = parse_u32, + [ATTR_MASTER_L3PROTO] = parse_u8, + [ATTR_MASTER_PORT_SRC] = parse_u16, + [ATTR_MASTER_PORT_DST] = parse_u16, + [ATTR_MASTER_L4PROTO] = parse_u8 }; void parse_netpld(struct nf_conntrack *ct, struct netpld *pld, int *query) diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 795aae9..6201923 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -362,37 +362,37 @@ sync_line: refreshtime | multicast_line | relax_transitions | delay_destroy_msgs - | sync_mode_persistent - | sync_mode_nack + | sync_mode_alarm + | sync_mode_ftfw | listen_to | state_replication | cache_writethrough ; -sync_mode_persistent: T_SYNC_MODE T_ALARM '{' sync_mode_persistent_list '}' +sync_mode_alarm: T_SYNC_MODE T_ALARM '{' sync_mode_alarm_list '}' { conf.flags |= SYNC_MODE_ALARM; }; -sync_mode_nack: T_SYNC_MODE T_FTFW '{' sync_mode_nack_list '}' +sync_mode_ftfw: T_SYNC_MODE T_FTFW '{' sync_mode_ftfw_list '}' { conf.flags |= SYNC_MODE_FTFW; }; -sync_mode_persistent_list: - | sync_mode_persistent_list sync_mode_persistent_line; +sync_mode_alarm_list: + | sync_mode_alarm_list sync_mode_alarm_line; -sync_mode_persistent_line: refreshtime +sync_mode_alarm_line: refreshtime | expiretime | timeout | relax_transitions | delay_destroy_msgs ; -sync_mode_nack_list: - | sync_mode_nack_list sync_mode_nack_line; +sync_mode_ftfw_list: + | sync_mode_ftfw_list sync_mode_ftfw_line; -sync_mode_nack_line: resend_buffer_size +sync_mode_ftfw_line: resend_buffer_size | timeout | window_size ; -- cgit v1.2.3 From 9884badf87d34f230aa0f8d80ab4860aafe589d5 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Mon, 24 Dec 2007 13:51:12 +0000 Subject: show error and warning messages to stderr --- ChangeLog | 1 + src/conntrack.c | 7 ++++--- src/main.c | 2 +- src/read_config_lex.l | 12 ++++++------ src/read_config_yy.y | 19 ++++++++++--------- 5 files changed, 22 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 2a3a112..bbc2819 100644 --- a/ChangeLog +++ b/ChangeLog @@ -23,6 +23,7 @@ o Use more appropriate names for the existing synchronization modes: o Now default synchronization mode is ftfw instead of alarm o rename `examples' directory to `doc' o add support for related conntracks (requires Linux kernel >= 2.6.22) +o show error and warning messages to stderr version 0.9.5 (2007/07/29) ------------------------------ diff --git a/src/conntrack.c b/src/conntrack.c index 65dc4a7..fa6ae0a 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -929,8 +929,8 @@ int main(int argc, char *argv[]) l3protonum); break; case 'a': - printf("warning: ignoring --nat-range, " - "use --src-nat or --dst-nat instead.\n"); + fprintf(stderr, "warning: ignoring --nat-range, " + "use --src-nat or --dst-nat instead.\n"); break; case 'n': options |= CT_OPT_SRC_NAT; @@ -958,7 +958,8 @@ int main(int argc, char *argv[]) nfct_set_attr_u32(obj, ATTR_SECMARK, atol(optarg)); break; case 'i': - printf("warning: ignoring --id. deprecated option.\n"); + fprintf(stderr, + "warning: ignoring --id. deprecated option.\n"); break; case 'f': options |= CT_OPT_FAMILY; diff --git a/src/main.c b/src/main.c index a3164a6..3a54911 100644 --- a/src/main.c +++ b/src/main.c @@ -248,7 +248,7 @@ int main(int argc, char *argv[]) */ STATE(log) = init_log(CONFIG(logfile)); if (config_set && !STATE(log)) { - fprintf(stdout, "can't open logfile `%s\n'", CONFIG(logfile)); + fprintf(stderr, "can't open logfile `%s\n'", CONFIG(logfile)); exit(EXIT_FAILURE); } diff --git a/src/read_config_lex.l b/src/read_config_lex.l index 81ae64f..847ec74 100644 --- a/src/read_config_lex.l +++ b/src/read_config_lex.l @@ -110,14 +110,14 @@ ftfw [F|f][T|t][F|f][W|w] {ip6} { yylval.string = strdup(yytext); return T_IP; } {path} { yylval.string = strdup(yytext); return T_PATH_VAL; } {alarm} { return T_ALARM; } -{persistent} { printf("\nWARNING: Now `persistent' mode is called " - "`alarm'. Please, update " - "your conntrackd.conf file.\n"); +{persistent} { fprintf(stderr, "\nWARNING: Now `persistent' mode " + "is called `alarm'. Please, update " + "your conntrackd.conf file.\n"); return T_ALARM; } {ftfw} { return T_FTFW; } -{nack} { printf("\nWARNING: Now `nack' mode is called " - "`ftfw'. Please, update " - "your conntrackd.conf file.\n"); +{nack} { fprintf(stderr, "\nWARNING: Now `nack' mode " + "is called `ftfw'. Please, update " + "your conntrackd.conf file.\n"); return T_FTFW; } {string} { yylval.string = strdup(yytext); return T_STRING; } diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 6201923..92806f8 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -119,7 +119,8 @@ syslog_facility : T_SYSLOG T_STRING else if (!strcmp($2, "local7")) conf.syslog_facility = LOG_LOCAL7; else { - fprintf(stderr, "'%s' is not a known syslog facility, ignoring.\n", $2); + fprintf(stderr, "'%s' is not a known syslog facility, " + "ignoring.\n", $2); return; } }; @@ -180,24 +181,24 @@ ignore_traffic_option : T_IPV4_ADDR T_IP #endif if (!family) { - fprintf(stdout, "%s is not a valid IP, ignoring", $2); + fprintf(stderr, "%s is not a valid IP, ignoring", $2); return; } if (!STATE(ignore_pool)) { STATE(ignore_pool) = ignore_pool_create(family); if (!STATE(ignore_pool)) { - fprintf(stdout, "Can't create ignore pool!\n"); + fprintf(stderr, "Can't create ignore pool!\n"); exit(EXIT_FAILURE); } } if (!ignore_pool_add(STATE(ignore_pool), &ip)) { if (errno == EEXIST) - fprintf(stdout, "IP %s is repeated " + fprintf(stderr, "IP %s is repeated " "in the ignore pool\n", $2); if (errno == ENOSPC) - fprintf(stdout, "Too many IP in the ignore pool!\n"); + fprintf(stderr, "Too many IP in the ignore pool!\n"); } }; @@ -327,7 +328,7 @@ ignore_proto: T_NUMBER if ($1 < IPPROTO_MAX) conf.ignore_protocol[$1] = 1; else - fprintf(stdout, "Protocol number `%d' is freak\n", $1); + fprintf(stderr, "Protocol number `%d' is freak\n", $1); }; ignore_proto: T_UDP @@ -563,8 +564,8 @@ stat_line: int yyerror(char *msg) { - printf("Error parsing config file: "); - printf("line (%d), symbol '%s': %s\n", yylineno, yytext, msg); + fprintf(stderr, "Error parsing config file: "); + fprintf(stderr, "line (%d), symbol '%s': %s\n", yylineno, yytext, msg); exit(EXIT_FAILURE); } @@ -611,7 +612,7 @@ init_config(char *filename) if (!STATE(ignore_pool)) { STATE(ignore_pool) = ignore_pool_create(CONFIG(family)); if (!STATE(ignore_pool)) { - fprintf(stdout, "Can't create ignore pool!\n"); + fprintf(stderr, "Can't create ignore pool!\n"); exit(EXIT_FAILURE); } } -- cgit v1.2.3 From d6978c9faadf9552bcb522d56d40c8aefa2e503e Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Mon, 31 Dec 2007 20:37:54 +0000 Subject: - hash lookup speedups based on comments from netdev's discussions - minor fix for hash6 in cache.c (however, ipv6 support is still broken - several updates in the TODO file --- ChangeLog | 1 + TODO | 5 +++-- src/cache.c | 15 +++++++++++---- 3 files changed, 15 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index bbc2819..bf79b6a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -24,6 +24,7 @@ o Now default synchronization mode is ftfw instead of alarm o rename `examples' directory to `doc' o add support for related conntracks (requires Linux kernel >= 2.6.22) o show error and warning messages to stderr +o hash lookup speedups based on comments from netdev's discussions version 0.9.5 (2007/07/29) ------------------------------ diff --git a/TODO b/TODO index 61f7e69..ff74c12 100644 --- a/TODO +++ b/TODO @@ -11,9 +11,10 @@ by dificulty levels: [X] ignorepool with unlimited size and ignore networks [ ] selective conntracks removal [ ] debian/rpm packages - [ ] improve website - [ ] Dumazet improvement hashtable (multiply vs. divide) + [X] improve website + [X] Dumazet improvement hashtable (multiply vs. divide) [X] add secmark support + [ ] logging support for the statistics mode = Requires some work = [ ] study better keepalived transitions diff --git a/src/cache.c b/src/cache.c index 80cde01..b92957a 100644 --- a/src/cache.c +++ b/src/cache.c @@ -38,7 +38,14 @@ static u_int32_t hash(const void *data, struct hashtable *table) ((nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC) << 16) | (nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST)))); - return jhash_2words(a, b, 0) % table->hashsize; + /* + * Instead of returning hash % table->hashsize (implying a divide) + * we return the high 32 bits of the (hash * table->hashsize) that will + * give results between [0 and hashsize-1] and same hash distribution, + * but using a multiply, less expensive than a divide. See: + * http://www.mail-archive.com/netdev@vger.kernel.org/msg56623.html + */ + return ((u_int64_t)jhash_2words(a, b, 0) * table->hashsize) >> 32; } static u_int32_t hash6(const void *data, struct hashtable *table) @@ -47,15 +54,15 @@ static u_int32_t hash6(const void *data, struct hashtable *table) const struct us_conntrack *u = data; struct nf_conntrack *ct = u->ct; - a = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV6_SRC), sizeof(u_int32_t), + a = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV6_SRC), sizeof(u_int32_t)*4, ((nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO) << 16) | (nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO)))); - b = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV6_DST), sizeof(u_int32_t), + b = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV6_DST), sizeof(u_int32_t)*4, ((nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC) << 16) | (nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST)))); - return jhash_2words(a, b, 0) % table->hashsize; + return ((u_int64_t)jhash_2words(a, b, 0) * table->hashsize) >> 32; } static int __compare(const struct nf_conntrack *ct1, -- cgit v1.2.3 From c41a0d3efc957505e72067e99a873ce66be0834a Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Thu, 3 Jan 2008 15:51:48 +0000 Subject: o add support for connection logging to the statistics mode via Logfile o minor irrelevant fixes for uncommon error paths and fix several typos o use LOG_INFO for connection logging, use LOG_NOTICE for other information o minor error handling updates --- ChangeLog | 2 ++ doc/stats/conntrackd.conf | 22 +++++++++++---- include/conntrackd.h | 6 ++++ include/log.h | 7 ++--- src/cache_iterators.c | 10 +++---- src/ignore_pool.c | 4 +-- src/log.c | 56 +++++++++++++++++++++++++++++-------- src/main.c | 14 ++++------ src/netlink.c | 6 ++-- src/network.c | 4 +-- src/read_config_yy.y | 70 +++++++++++++++++++++++++++++++++++++++++++++-- src/run.c | 26 +++++++++--------- src/stats-mode.c | 9 ++++++ src/sync-mode.c | 5 ++-- 14 files changed, 182 insertions(+), 59 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index bf79b6a..83e1524 100644 --- a/ChangeLog +++ b/ChangeLog @@ -25,6 +25,8 @@ o rename `examples' directory to `doc' o add support for related conntracks (requires Linux kernel >= 2.6.22) o show error and warning messages to stderr o hash lookup speedups based on comments from netdev's discussions +o add support for connection logging to the statistics mode via Logfile +o minor irrelevant fixes for uncommon error paths and fix several typos version 0.9.5 (2007/07/29) ------------------------------ diff --git a/doc/stats/conntrackd.conf b/doc/stats/conntrackd.conf index 07deaa8..198b8a3 100644 --- a/doc/stats/conntrackd.conf +++ b/doc/stats/conntrackd.conf @@ -49,6 +49,23 @@ General { SocketBufferSizeMaxGrown 655355 } +Stats { + # + # Enable connection logging. Default is off. + # Logfile: on, off, or a filename + # Default file: (/var/log/conntrackd-stats.log) + # + LogFile on + + # + # Enable connection logging via Syslog. Default is off. + # Syslog: on, off or a facility name (daemon (default) or local0..7) + # If you set the facility, use the same as in the General clause, + # otherwise you'll get a warning message. + # + #Syslog on +} + # # Ignore traffic for a certain set of IP's: Usually # all the IP assigned to the firewall since local @@ -69,8 +86,3 @@ IgnoreProtocol { # VRRP # numeric numbers also valid } - -# -# Strip NAT traffic -# -StripNAT diff --git a/include/conntrackd.h b/include/conntrackd.h index 1bb3879..e5b8a4e 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -31,6 +31,7 @@ #define DEFAULT_CONFIGFILE "/etc/conntrackd/conntrackd.conf" #define DEFAULT_LOCKFILE "/var/lock/conntrackd.lock" #define DEFAULT_LOGFILE "/var/log/conntrackd.log" +#define DEFAULT_STATS_LOGFILE "/var/log/conntrackd-stats.log" #define DEFAULT_SYSLOG_FACILITY LOG_DAEMON enum { @@ -87,6 +88,10 @@ struct ct_conf { unsigned int resend_buffer_size;/* FTFW protocol */ unsigned int window_size; int cache_write_through; + struct { + char logfile[FILENAME_MAXLEN]; + int syslog_facility; + } stats; }; #define STATE(x) st.x @@ -94,6 +99,7 @@ struct ct_conf { struct ct_general_state { sigset_t block; FILE *log; + FILE *stats_log; int local; struct ct_mode *mode; struct ignore_pool *ignore_pool; diff --git a/include/log.h b/include/log.h index f6f450c..467ae8f 100644 --- a/include/log.h +++ b/include/log.h @@ -1,10 +1,9 @@ #ifndef _LOG_H_ #define _LOG_H_ -#include - -FILE *init_log(char *filename); +int init_log(); void dlog(FILE *fd, int priority, char *format, ...); -void close_log(FILE *fd); +void dlog_ct(FILE *fd, struct nf_conntrack *ct); +void close_log(); #endif diff --git a/src/cache_iterators.c b/src/cache_iterators.c index c29100c..85f87ab 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -120,14 +120,14 @@ void cache_commit(struct cache *c) commit_exist = c->commit_exist - commit_exist; /* log results */ - dlog(STATE(log), LOG_INFO, "Committed %u new entries", commit_ok); + dlog(STATE(log), LOG_NOTICE, "Committed %u new entries", commit_ok); if (commit_exist) - dlog(STATE(log), LOG_INFO, "%u entries ignored, " - "already exist", commit_exist); + dlog(STATE(log), LOG_NOTICE, "%u entries ignored, " + "already exist", commit_exist); if (commit_fail) - dlog(STATE(log), LOG_INFO, "%u entries can't be " - "committed", commit_fail); + dlog(STATE(log), LOG_NOTICE, "%u entries can't be " + "committed", commit_fail); } static int do_flush(void *data1, void *data2) diff --git a/src/ignore_pool.c b/src/ignore_pool.c index 619c2fa..ee457ba 100644 --- a/src/ignore_pool.c +++ b/src/ignore_pool.c @@ -118,7 +118,7 @@ int __ignore_pool_test_ipv6(struct ignore_pool *ip, struct nf_conntrack *ct) int ignore_pool_test(struct ignore_pool *ip, struct nf_conntrack *ct) { - int ret; + int ret = 0; switch(nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO)) { case AF_INET: @@ -128,7 +128,7 @@ int ignore_pool_test(struct ignore_pool *ip, struct nf_conntrack *ct) ret = __ignore_pool_test_ipv6(ip, ct); break; default: - dlog(STATE(log), "unknown conntrack layer 3 protocol?"); + dlog(STATE(log), LOG_WARNING, "unknown layer 3 protocol?"); break; } diff --git a/src/log.c b/src/log.c index 5fea1c3..e3f2102 100644 --- a/src/log.c +++ b/src/log.c @@ -24,22 +24,31 @@ #include #include "conntrackd.h" -FILE *init_log(char *filename) +int init_log(void) { - FILE *fd = NULL; + if (CONFIG(logfile)[0]) { + STATE(log) = fopen(CONFIG(logfile), "a+"); + if (STATE(log) == NULL) { + fprintf(stderr, "can't open log file `%s'\n", + CONFIG(logfile)); + return -1; + } + } - if (filename[0]) { - fd = fopen(filename, "a+"); - if (fd == NULL) { - fprintf(stderr, "can't open log file `%s'\n", filename); - return NULL; + if (CONFIG(stats).logfile[0]) { + STATE(stats_log) = fopen(CONFIG(stats).logfile, "a+"); + if (STATE(stats_log) == NULL) { + fprintf(stderr, "can't open log file `%s'\n", + CONFIG(stats).logfile); + return -1; } } - if (CONFIG(syslog_facility) != -1) + if (CONFIG(syslog_facility) != -1 || + CONFIG(stats).syslog_facility != -1) openlog(PACKAGE, LOG_PID, CONFIG(syslog_facility)); - return fd; + return 0; } void dlog(FILE *fd, int priority, char *format, ...) @@ -85,10 +94,33 @@ void dlog(FILE *fd, int priority, char *format, ...) } } -void close_log(FILE *fd) +void dlog_ct(FILE *fd, struct nf_conntrack *ct) +{ + time_t t; + char buf[1024]; + char *tmp; + + if (fd) { + t = time(NULL); + ctime_r(&t, buf); + tmp = buf + strlen(buf); + buf[strlen(buf)-1]='\t'; + nfct_snprintf(buf+strlen(buf), 1024-strlen(buf), ct, 0, 0, 0); + fprintf(fd, "%s\n", buf); + fflush(fd); + } + + if (CONFIG(stats).syslog_facility != -1) + syslog(LOG_INFO, "%s", tmp); +} + +void close_log(void) { - if (fd != NULL) - fclose(fd); + if (STATE(log) != NULL) + fclose(STATE(log)); + + if (STATE(stats_log) != NULL) + fclose(STATE(stats_log)); if (CONFIG(syslog_facility) != -1) closelog(); diff --git a/src/main.c b/src/main.c index 3a54911..e0ca46d 100644 --- a/src/main.c +++ b/src/main.c @@ -246,8 +246,7 @@ int main(int argc, char *argv[]) /* * Setting up logging */ - STATE(log) = init_log(CONFIG(logfile)); - if (config_set && !STATE(log)) { + if (config_set && init_log() == -1) { fprintf(stderr, "can't open logfile `%s\n'", CONFIG(logfile)); exit(EXIT_FAILURE); } @@ -255,7 +254,7 @@ int main(int argc, char *argv[]) if (type == REQUEST) { if (do_local_request(action, &conf.local, local_step) == -1) { fprintf(stderr, "can't connect: is conntrackd " - "running? appropiate permissions?\n"); + "running? appropriate permissions?\n"); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); @@ -276,22 +275,21 @@ int main(int argc, char *argv[]) pid_t pid; if ((pid = fork()) == -1) { - dlog(STATE(log), LOG_ERR, "fork() failed: " - "%s", strerror(errno)); + perror("fork has failed: "); exit(EXIT_FAILURE); } else if (pid) exit(EXIT_SUCCESS); - dlog(STATE(log), LOG_INFO, "--- starting in daemon mode ---"); + dlog(STATE(log), LOG_NOTICE, "-- starting in daemon mode --"); } else - dlog(STATE(log), LOG_INFO, "--- starting in console mode ---"); + dlog(STATE(log), LOG_NOTICE, "-- starting in console mode --"); /* * initialization process */ if (init(mode) == -1) { - close_log(STATE(log)); + close_log(); fprintf(stderr, "ERROR: conntrackd cannot start, please " "check the logfile for more info\n"); unlink(CONFIG(lockfile)); diff --git a/src/netlink.c b/src/netlink.c index d453fe1..ab945d8 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -185,9 +185,9 @@ void nl_resize_socket_buffer(struct nfct_handle *h) CONFIG(netlink_buffer_size) = nfnl_rcvbufsiz(nfct_nfnlh(h), s); /* notify the sysadmin */ - dlog(STATE(log), LOG_INFO, "netlink socket buffer size " - "has been set to %u bytes", - CONFIG(netlink_buffer_size)); + dlog(STATE(log), LOG_NOTICE, "netlink socket buffer size " + "has been set to %u bytes", + CONFIG(netlink_buffer_size)); } int nl_dump_conntrack_table(void) diff --git a/src/network.c b/src/network.c index 9bd3469..a20c1e0 100644 --- a/src/network.c +++ b/src/network.c @@ -221,8 +221,8 @@ int mcast_track_seq(u_int32_t seq, u_int32_t *exp_seq) /* out of sequence: replayed/delayed packet? */ if (before(seq, STATE_SYNC(last_seq_recv)+1)) - dlog(STATE(log), "delayed packet? exp=%u rcv=%u", - STATE_SYNC(last_seq_recv)+1, seq); + dlog(STATE(log), LOG_WARNING, "delayed packet? exp=%u rcv=%u", + STATE_SYNC(last_seq_recv)+1, seq); out: *exp_seq = STATE_SYNC(last_seq_recv)+1; diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 92806f8..ebb1c73 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -123,6 +123,11 @@ syslog_facility : T_SYSLOG T_STRING "ignoring.\n", $2); return; } + + if (conf.stats.syslog_facility != -1 && + conf.syslog_facility != conf.stats.syslog_facility) + fprintf(stderr, "WARNING: Conflicting Syslog facility " + "values, defaulting to General.\n"); }; lock : T_LOCK T_PATH_VAL @@ -549,16 +554,74 @@ family : T_FAMILY T_STRING conf.family = AF_INET; }; -stats: T_SYNC '{' stats_list '}'; +stats: T_STATS '{' stats_list '}'; stats_list: | stats_list stat_line ; -stat_line: - | +stat_line: stat_logfile_bool + | stat_logfile_path + | stat_syslog_bool + | stat_syslog_facility ; +stat_logfile_bool : T_LOG T_ON +{ + strncpy(conf.stats.logfile, DEFAULT_STATS_LOGFILE, FILENAME_MAXLEN); +}; + +stat_logfile_bool : T_LOG T_OFF +{ +}; + +stat_logfile_path : T_LOG T_PATH_VAL +{ + strncpy(conf.stats.logfile, $2, FILENAME_MAXLEN); +}; + +stat_syslog_bool : T_SYSLOG T_ON +{ + conf.stats.syslog_facility = DEFAULT_SYSLOG_FACILITY; +}; + +stat_syslog_bool : T_SYSLOG T_OFF +{ + conf.stats.syslog_facility = -1; +} + +stat_syslog_facility : T_SYSLOG T_STRING +{ + if (!strcmp($2, "daemon")) + conf.stats.syslog_facility = LOG_DAEMON; + else if (!strcmp($2, "local0")) + conf.stats.syslog_facility = LOG_LOCAL0; + else if (!strcmp($2, "local1")) + conf.stats.syslog_facility = LOG_LOCAL1; + else if (!strcmp($2, "local2")) + conf.stats.syslog_facility = LOG_LOCAL2; + else if (!strcmp($2, "local3")) + conf.stats.syslog_facility = LOG_LOCAL3; + else if (!strcmp($2, "local4")) + conf.stats.syslog_facility = LOG_LOCAL4; + else if (!strcmp($2, "local5")) + conf.stats.syslog_facility = LOG_LOCAL5; + else if (!strcmp($2, "local6")) + conf.stats.syslog_facility = LOG_LOCAL6; + else if (!strcmp($2, "local7")) + conf.stats.syslog_facility = LOG_LOCAL7; + else { + fprintf(stderr, "'%s' is not a known syslog facility, " + "ignoring.\n", $2); + return; + } + + if (conf.syslog_facility != -1 && + conf.stats.syslog_facility != conf.syslog_facility) + fprintf(stderr, "WARNING: Conflicting Syslog facility " + "values, defaulting to General.\n"); +}; + %% int @@ -580,6 +643,7 @@ init_config(char *filename) /* Zero may be a valid facility */ CONFIG(syslog_facility) = -1; + CONFIG(stats).syslog_facility = -1; yyrestart(fp); yyparse(); diff --git a/src/run.c b/src/run.c index 9ce9923..0411fcb 100644 --- a/src/run.c +++ b/src/run.c @@ -40,7 +40,7 @@ void killer(int foo) STATE(mode)->kill(); destroy_alarm_scheduler(); unlink(CONFIG(lockfile)); - dlog(STATE(log), LOG_INFO, "------- shutdown received ----"); + dlog(STATE(log), LOG_NOTICE, "---- shutdown received ----"); close_log(STATE(log)); sigprocmask(SIG_UNBLOCK, &STATE(block), NULL); @@ -60,18 +60,16 @@ void local_handler(int fd, void *data) ret = read(fd, &type, sizeof(type)); if (ret == -1) { - dlog(STATE(log), LOG_INFO, "can't read from unix socket"); + dlog(STATE(log), LOG_ERR, "can't read from unix socket"); return; } - if (ret == 0) { - dlog(STATE(log), LOG_INFO, "local request: nothing received?"); + if (ret == 0) return; - } switch(type) { case FLUSH_MASTER: - dlog(STATE(log), LOG_NOTICE, "`conntrackd -F' is deprecated. " - "Use conntrack -F instead."); + dlog(STATE(log), LOG_WARNING, "`conntrackd -F' is deprecated. " + "Use conntrack -F instead."); if (fork() == 0) { execlp("conntrack", "conntrack", "-F", NULL); exit(EXIT_SUCCESS); @@ -84,7 +82,7 @@ void local_handler(int fd, void *data) } if (!STATE(mode)->local(fd, type, data)) - dlog(STATE(log), LOG_ERR, "unknown local request %d", type); + dlog(STATE(log), LOG_WARNING, "unknown local request %d", type); } int init(int mode) @@ -152,7 +150,7 @@ int init(int mode) if (signal(SIGCHLD, child) == SIG_ERR) return -1; - dlog(STATE(log), LOG_INFO, "initialization completed"); + dlog(STATE(log), LOG_NOTICE, "initialization completed"); return 0; } @@ -181,7 +179,8 @@ static void __run(long credit, int step) if (errno == EINTR) return; - dlog(STATE(log), "select() failed: %s", strerror(errno)); + dlog(STATE(log), LOG_WARNING, + "select failed: %s", strerror(errno)); return; } @@ -218,8 +217,8 @@ static void __run(long credit, int step) case EAGAIN: break; default: - dlog(STATE(log), "event catch says: %s", - strerror(errno)); + dlog(STATE(log), LOG_WARNING, + "event catch says: %s", strerror(errno)); break; } } @@ -251,7 +250,8 @@ void run(void) timer_stop(&timer); if (timer_adjust_credit(&timer)) - dlog(STATE(log), "alarm run takes too long!"); + dlog(STATE(log), LOG_WARNING, + "alarm run takes too long!"); step = (step + 1) < STEPS_PER_SECONDS ? step + 1 : 0; } diff --git a/src/stats-mode.c b/src/stats-mode.c index 1d68e02..e817c4e 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -88,6 +88,8 @@ static int local_handler_stats(int fd, int type, void *data) static void dump_stats(struct nf_conntrack *ct) { + nfct_attr_unset(ct, ATTR_TIMEOUT); + if (cache_update_force(STATE_STATS(cache), ct)) debug_ct(ct, "resync entry"); } @@ -140,6 +142,8 @@ static void overrun_stats() static void event_new_stats(struct nf_conntrack *ct) { + nfct_attr_unset(ct, ATTR_TIMEOUT); + if (cache_add(STATE_STATS(cache), ct)) { debug_ct(ct, "cache new"); } else { @@ -153,6 +157,8 @@ static void event_new_stats(struct nf_conntrack *ct) static void event_update_stats(struct nf_conntrack *ct) { + nfct_attr_unset(ct, ATTR_TIMEOUT); + if (!cache_update_force(STATE_STATS(cache), ct)) { debug_ct(ct, "can't update"); return; @@ -162,8 +168,11 @@ static void event_update_stats(struct nf_conntrack *ct) static int event_destroy_stats(struct nf_conntrack *ct) { + nfct_attr_unset(ct, ATTR_TIMEOUT); + if (cache_del(STATE_STATS(cache), ct)) { debug_ct(ct, "cache destroy"); + dlog_ct(STATE(stats_log), ct); return 1; } else { debug_ct(ct, "can't destroy!"); diff --git a/src/sync-mode.c b/src/sync-mode.c index 7cd2b84..7c42c78 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -273,13 +273,14 @@ static int local_handler_sync(int fd, int type, void *data) case COMMIT: ret = fork(); if (ret == 0) { - dlog(STATE(log), LOG_INFO, "committing external cache"); + dlog(STATE(log), LOG_NOTICE, + "committing external cache"); cache_commit(STATE_SYNC(external)); exit(EXIT_SUCCESS); } break; case FLUSH_CACHE: - dlog(STATE(log), LOG_INFO, "flushing caches"); + dlog(STATE(log), LOG_NOTICE, "flushing caches"); cache_flush(STATE_SYNC(internal)); cache_flush(STATE_SYNC(external)); break; -- cgit v1.2.3 From cf36ca8cc146f0bc2052f078e6aae3479822ca54 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Sat, 5 Jan 2008 12:34:45 +0000 Subject: Ben Lentz : Fix the crash when stats LogFile is off and stats Syslog is on -Esta línea y las que están debajo serán ignoradas-- MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit M conntrack-tools/src/log.c --- src/log.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/log.c b/src/log.c index e3f2102..a4d51ec 100644 --- a/src/log.c +++ b/src/log.c @@ -99,13 +99,14 @@ void dlog_ct(FILE *fd, struct nf_conntrack *ct) time_t t; char buf[1024]; char *tmp; + + t = time(NULL); + ctime_r(&t, buf); + tmp = buf + strlen(buf); + buf[strlen(buf)-1]='\t'; + nfct_snprintf(buf+strlen(buf), 1024-strlen(buf), ct, 0, 0, 0); if (fd) { - t = time(NULL); - ctime_r(&t, buf); - tmp = buf + strlen(buf); - buf[strlen(buf)-1]='\t'; - nfct_snprintf(buf+strlen(buf), 1024-strlen(buf), ct, 0, 0, 0); fprintf(fd, "%s\n", buf); fflush(fd); } -- cgit v1.2.3 From 70d1f229a46565c48cfaa6412e865ddd4bc5c585 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Sat, 5 Jan 2008 12:37:21 +0000 Subject: Ben Lentz : Detach daemon from its terminal --- ChangeLog | 1 + src/main.c | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 83e1524..78e3034 100644 --- a/ChangeLog +++ b/ChangeLog @@ -27,6 +27,7 @@ o show error and warning messages to stderr o hash lookup speedups based on comments from netdev's discussions o add support for connection logging to the statistics mode via Logfile o minor irrelevant fixes for uncommon error paths and fix several typos +o detach daemon from its terminal (Ben Lenitz ) version 0.9.5 (2007/07/29) ------------------------------ diff --git a/src/main.c b/src/main.c index e0ca46d..ee6abf3 100644 --- a/src/main.c +++ b/src/main.c @@ -272,7 +272,7 @@ int main(int argc, char *argv[]) /* Daemonize conntrackd */ if (type == DAEMON) { - pid_t pid; + pid_t pid, sid; if ((pid = fork()) == -1) { perror("fork has failed: "); @@ -280,6 +280,13 @@ int main(int argc, char *argv[]) } else if (pid) exit(EXIT_SUCCESS); + sid = setsid(); + + if (sid < 0) { + perror("setsid has failed: "); + exit(EXIT_FAILURE); + } + dlog(STATE(log), LOG_NOTICE, "-- starting in daemon mode --"); } else dlog(STATE(log), LOG_NOTICE, "-- starting in console mode --"); -- cgit v1.2.3 From 7763eff37cd8ab4b1af0021c18f1ff86e1f19acd Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Sat, 5 Jan 2008 14:13:11 +0000 Subject: obsolete `-S' option: Use information provided by the config file --- ChangeLog | 1 + conntrackd.8 | 5 +---- include/conntrackd.h | 6 ++++-- src/main.c | 12 ++++++------ src/read_config_yy.y | 24 ++++++++++++++++++++---- src/run.c | 22 +++++++++------------- src/sync-mode.c | 10 +++++++--- 7 files changed, 48 insertions(+), 32 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 78e3034..d9c9411 100644 --- a/ChangeLog +++ b/ChangeLog @@ -28,6 +28,7 @@ o hash lookup speedups based on comments from netdev's discussions o add support for connection logging to the statistics mode via Logfile o minor irrelevant fixes for uncommon error paths and fix several typos o detach daemon from its terminal (Ben Lenitz ) +o obsolete `-S' option: Use information provided by the config file version 0.9.5 (2007/07/29) ------------------------------ diff --git a/conntrackd.8 b/conntrackd.8 index 8e2f2cc..0520ed7 100644 --- a/conntrackd.8 +++ b/conntrackd.8 @@ -19,10 +19,7 @@ can be divided into several different groups. These options specify the particular operation mode in which conntrackd runs. Only one of them can be specified at any given time. .TP .BI "-d " -Run conntrackd in daemon mode. This option can be combined with "-S" -.TP -.BI "-S " -Run conntrackd in statistics mode. Default mode is synchronization mode, so if you want to use +Run conntrackd in daemon mode. .B conntrackd in statistics mode, you have to pass this option .SS CLIENT COMMANDS diff --git a/include/conntrackd.h b/include/conntrackd.h index e5b8a4e..116ab9d 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -51,8 +51,10 @@ enum { #define REQUEST 2 /* conntrackd modes */ -#define SYNC_MODE 0 -#define STATS_MODE 1 +#define CTD_SYNC_MODE (1UL << 0) +#define CTD_STATS_MODE (1UL << 1) +#define CTD_SYNC_FTFW (1UL << 2) +#define CTD_SYNC_ALARM (1UL << 3) /* FILENAME_MAX is 4096 on my system, perhaps too much? */ #ifndef FILENAME_MAXLEN diff --git a/src/main.c b/src/main.c index ee6abf3..c8b1074 100644 --- a/src/main.c +++ b/src/main.c @@ -33,8 +33,7 @@ union ct_state state; static const char usage_daemon_commands[] = "Daemon mode commands:\n" - " -d [options]\t\tRun in daemon mode\n" - " -S [options]\t\tRun in statistics mode\n"; + " -d [options]\t\tRun in daemon mode\n"; static const char usage_client_commands[] = "Client mode commands:\n" @@ -63,7 +62,7 @@ void show_usage(char *progname) } /* These live in run.c */ -int init(int); +int init(void); void run(void); void set_operation_mode(int *current, int want, char *argv[]) @@ -116,7 +115,7 @@ int main(int argc, char *argv[]) { int ret, i, config_set = 0, action; char config_file[PATH_MAX]; - int type = 0, mode = 0; + int type = 0; struct utsname u; int version, major, minor; @@ -209,7 +208,8 @@ int main(int argc, char *argv[]) action = STATS; break; case 'S': - set_operation_mode(&mode, STATS_MODE, argv); + fprintf(stderr, "WARNING: -S option is obsolete. " + "Ignoring.\n"); break; case 'n': set_operation_mode(&type, REQUEST, argv); @@ -295,7 +295,7 @@ int main(int argc, char *argv[]) * initialization process */ - if (init(mode) == -1) { + if (init() == -1) { close_log(); fprintf(stderr, "ERROR: conntrackd cannot start, please " "check the logfile for more info\n"); diff --git a/src/read_config_yy.y b/src/read_config_yy.y index ebb1c73..e2bb4c8 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -356,7 +356,15 @@ ignore_proto: T_IGMP conf.ignore_protocol[IPPROTO_IGMP] = 1; }; -sync: T_SYNC '{' sync_list '}'; +sync: T_SYNC '{' sync_list '}' +{ + if (conf.flags & CTD_STATS_MODE) { + fprintf(stderr, "ERROR: Cannot use both Stats and Sync " + "clauses in conntrackd.conf.\n"); + exit(EXIT_FAILURE); + } + conf.flags |= CTD_SYNC_MODE; +}; sync_list: | sync_list sync_line; @@ -377,12 +385,12 @@ sync_line: refreshtime sync_mode_alarm: T_SYNC_MODE T_ALARM '{' sync_mode_alarm_list '}' { - conf.flags |= SYNC_MODE_ALARM; + conf.flags |= CTD_SYNC_ALARM; }; sync_mode_ftfw: T_SYNC_MODE T_FTFW '{' sync_mode_ftfw_list '}' { - conf.flags |= SYNC_MODE_FTFW; + conf.flags |= CTD_SYNC_FTFW; }; sync_mode_alarm_list: @@ -554,7 +562,15 @@ family : T_FAMILY T_STRING conf.family = AF_INET; }; -stats: T_STATS '{' stats_list '}'; +stats: T_STATS '{' stats_list '}' +{ + if (conf.flags & CTD_SYNC_MODE) { + fprintf(stderr, "ERROR: Cannot use both Stats and Sync " + "clauses in conntrackd.conf.\n"); + exit(EXIT_FAILURE); + } + conf.flags |= CTD_STATS_MODE; +}; stats_list: | stats_list stat_line diff --git a/src/run.c b/src/run.c index 0411fcb..ebf4b3c 100644 --- a/src/run.c +++ b/src/run.c @@ -85,20 +85,16 @@ void local_handler(int fd, void *data) dlog(STATE(log), LOG_WARNING, "unknown local request %d", type); } -int init(int mode) +int init(void) { - switch(mode) { - case STATS_MODE: - STATE(mode) = &stats_mode; - break; - case SYNC_MODE: - STATE(mode) = &sync_mode; - break; - default: - fprintf(stderr, "Unknown running mode! default " - "to synchronization mode\n"); - STATE(mode) = &sync_mode; - break; + if (CONFIG(flags) & CTD_STATS_MODE) + STATE(mode) = &stats_mode; + else if (CONFIG(flags) & CTD_SYNC_MODE) + STATE(mode) = &sync_mode; + else { + fprintf(stderr, "WARNING: No running mode specified. " + "Defaulting to statistics mode.\n"); + STATE(mode) = &stats_mode; } /* Initialization */ diff --git a/src/sync-mode.c b/src/sync-mode.c index 7c42c78..d54e169 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -126,11 +126,15 @@ static int init_sync(void) } memset(state.sync, 0, sizeof(struct ct_sync_state)); - if (CONFIG(flags) & SYNC_MODE_FTFW) + if (CONFIG(flags) & CTD_SYNC_FTFW) STATE_SYNC(sync) = &ftfw; - else - /* default to ftfw mode */ + else if (CONFIG(flags) & CTD_SYNC_ALARM) + STATE_SYNC(sync) = &alarm; + else { + fprintf(stderr, "WARNING: No synchronization mode specified. " + "Defaulting to FT-FW mode.\n"); STATE_SYNC(sync) = &ftfw; + } if (STATE_SYNC(sync)->init) STATE_SYNC(sync)->init(); -- cgit v1.2.3 From 18d19a287315b950a6cef6051f8d4e844e37c6ba Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Sat, 5 Jan 2008 14:37:07 +0000 Subject: daemonize conntrackd after initialization --- ChangeLog | 1 + src/main.c | 28 ++++++++++++++++------------ 2 files changed, 17 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index d9c9411..34ad928 100644 --- a/ChangeLog +++ b/ChangeLog @@ -29,6 +29,7 @@ o add support for connection logging to the statistics mode via Logfile o minor irrelevant fixes for uncommon error paths and fix several typos o detach daemon from its terminal (Ben Lenitz ) o obsolete `-S' option: Use information provided by the config file +o daemonize conntrackd after initialization version 0.9.5 (2007/07/29) ------------------------------ diff --git a/src/main.c b/src/main.c index c8b1074..3cf44ba 100644 --- a/src/main.c +++ b/src/main.c @@ -270,6 +270,18 @@ int main(int argc, char *argv[]) } close(ret); + /* + * initialization process + */ + + if (init() == -1) { + close_log(); + fprintf(stderr, "ERROR: conntrackd cannot start, please " + "check the logfile for more info\n"); + unlink(CONFIG(lockfile)); + exit(EXIT_FAILURE); + } + /* Daemonize conntrackd */ if (type == DAEMON) { pid_t pid, sid; @@ -287,22 +299,14 @@ int main(int argc, char *argv[]) exit(EXIT_FAILURE); } + close(STDIN_FILENO); + close(STDOUT_FILENO); + close(STDERR_FILENO); + dlog(STATE(log), LOG_NOTICE, "-- starting in daemon mode --"); } else dlog(STATE(log), LOG_NOTICE, "-- starting in console mode --"); - /* - * initialization process - */ - - if (init() == -1) { - close_log(); - fprintf(stderr, "ERROR: conntrackd cannot start, please " - "check the logfile for more info\n"); - unlink(CONFIG(lockfile)); - exit(EXIT_FAILURE); - } - /* * run main process */ -- cgit v1.2.3 From 1c0b4d3721e40586219fb7676e61e6ba19affdd2 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Sat, 5 Jan 2008 15:34:30 +0000 Subject: rename class `buffer' to `queue' which is what it really implements --- ChangeLog | 1 + include/buffer.h | 31 ------------- include/conntrackd.h | 2 +- include/queue.h | 31 +++++++++++++ src/Makefile.am | 2 +- src/buffer.c | 128 --------------------------------------------------- src/queue.c | 128 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/read_config_yy.y | 10 ++-- src/sync-ftfw.c | 40 ++++++++-------- src/sync-mode.c | 1 - 10 files changed, 187 insertions(+), 187 deletions(-) delete mode 100644 include/buffer.h create mode 100644 include/queue.h delete mode 100644 src/buffer.c create mode 100644 src/queue.c (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 34ad928..82072f4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -30,6 +30,7 @@ o minor irrelevant fixes for uncommon error paths and fix several typos o detach daemon from its terminal (Ben Lenitz ) o obsolete `-S' option: Use information provided by the config file o daemonize conntrackd after initialization +o rename class `buffer' to `queue' which is what it really implements version 0.9.5 (2007/07/29) ------------------------------ diff --git a/include/buffer.h b/include/buffer.h deleted file mode 100644 index cb42f51..0000000 --- a/include/buffer.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef _BUFFER_H_ -#define _BUFFER_H_ - -#include -#include -#include -#include "linux_list.h" - -struct buffer { - size_t max_size; - size_t cur_size; - unsigned int num_elems; - struct list_head head; -}; - -struct buffer_node { - struct list_head head; - size_t size; - char data[0]; -}; - -struct buffer *buffer_create(size_t max_size); -void buffer_destroy(struct buffer *b); -unsigned int buffer_len(struct buffer *b); -int buffer_add(struct buffer *b, const void *data, size_t size); -void buffer_del(struct buffer *b, void *data); -void buffer_iterate(struct buffer *b, - void *data, - int (*iterate)(void *data1, void *data2)); - -#endif diff --git a/include/conntrackd.h b/include/conntrackd.h index 116ab9d..a4a91ea 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -87,7 +87,7 @@ struct ct_conf { unsigned int listen_to_len; unsigned int flags; int family; /* protocol family */ - unsigned int resend_buffer_size;/* FTFW protocol */ + unsigned int resend_queue_size; /* FTFW protocol */ unsigned int window_size; int cache_write_through; struct { diff --git a/include/queue.h b/include/queue.h new file mode 100644 index 0000000..691138f --- /dev/null +++ b/include/queue.h @@ -0,0 +1,31 @@ +#ifndef _QUEUE_H_ +#define _QUEUE_H_ + +#include +#include +#include +#include "linux_list.h" + +struct queue { + size_t max_size; + size_t cur_size; + unsigned int num_elems; + struct list_head head; +}; + +struct queue_node { + struct list_head head; + size_t size; + char data[0]; +}; + +struct queue *queue_create(size_t max_size); +void queue_destroy(struct queue *b); +unsigned int queue_len(struct queue *b); +int queue_add(struct queue *b, const void *data, size_t size); +void queue_del(struct queue *b, void *data); +void queue_iterate(struct queue *b, + void *data, + int (*iterate)(void *data1, void *data2)); + +#endif diff --git a/src/Makefile.am b/src/Makefile.am index 1fac3dc..62a7467 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -10,7 +10,7 @@ conntrack_SOURCES = conntrack.c conntrack_LDADD = ../extensions/libct_proto_tcp.la ../extensions/libct_proto_udp.la ../extensions/libct_proto_icmp.la conntrack_LDFLAGS = $(all_libraries) @LIBNETFILTER_CONNTRACK_LIBS@ -conntrackd_SOURCES = alarm.c main.c run.c hash.c buffer.c \ +conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c \ local.c log.c mcast.c netlink.c \ ignore_pool.c \ cache.c cache_iterators.c \ diff --git a/src/buffer.c b/src/buffer.c deleted file mode 100644 index 23f7797..0000000 --- a/src/buffer.c +++ /dev/null @@ -1,128 +0,0 @@ -/* - * (C) 2006-2007 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "buffer.h" - -struct buffer *buffer_create(size_t max_size) -{ - struct buffer *b; - - b = malloc(sizeof(struct buffer)); - if (b == NULL) - return NULL; - memset(b, 0, sizeof(struct buffer)); - - b->max_size = max_size; - INIT_LIST_HEAD(&b->head); - - return b; -} - -void buffer_destroy(struct buffer *b) -{ - struct list_head *i, *tmp; - struct buffer_node *node; - - /* XXX: set cur_size and num_elems */ - list_for_each_safe(i, tmp, &b->head) { - node = (struct buffer_node *) i; - list_del(i); - free(node); - } - free(b); -} - -static struct buffer_node *buffer_node_create(const void *data, size_t size) -{ - struct buffer_node *n; - - n = malloc(sizeof(struct buffer_node) + size); - if (n == NULL) - return NULL; - - INIT_LIST_HEAD(&n->head); - n->size = size; - memcpy(n->data, data, size); - - return n; -} - -int buffer_add(struct buffer *b, const void *data, size_t size) -{ - int ret = 0; - struct buffer_node *n; - - /* does it fit this buffer? */ - if (size > b->max_size) { - errno = ENOSPC; - ret = -1; - goto err; - } - -retry: - /* buffer is full: kill the oldest entry */ - if (b->cur_size + size > b->max_size) { - n = (struct buffer_node *) b->head.prev; - list_del(b->head.prev); - b->cur_size -= n->size; - free(n); - goto retry; - } - - n = buffer_node_create(data, size); - if (n == NULL) { - ret = -1; - goto err; - } - - list_add(&n->head, &b->head); - b->cur_size += size; - b->num_elems++; - -err: - return ret; -} - -void buffer_del(struct buffer *b, void *data) -{ - struct buffer_node *n = container_of(data, struct buffer_node, data); - - list_del(&n->head); - b->cur_size -= n->size; - b->num_elems--; - free(n); -} - -void buffer_iterate(struct buffer *b, - void *data, - int (*iterate)(void *data1, void *data2)) -{ - struct list_head *i, *tmp; - struct buffer_node *n; - - list_for_each_safe(i, tmp, &b->head) { - n = (struct buffer_node *) i; - if (iterate(n->data, data)) - break; - } -} - -unsigned int buffer_len(struct buffer *b) -{ - return b->num_elems; -} diff --git a/src/queue.c b/src/queue.c new file mode 100644 index 0000000..3413013 --- /dev/null +++ b/src/queue.c @@ -0,0 +1,128 @@ +/* + * (C) 2006-2008 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "queue.h" + +struct queue *queue_create(size_t max_size) +{ + struct queue *b; + + b = malloc(sizeof(struct queue)); + if (b == NULL) + return NULL; + memset(b, 0, sizeof(struct queue)); + + b->max_size = max_size; + INIT_LIST_HEAD(&b->head); + + return b; +} + +void queue_destroy(struct queue *b) +{ + struct list_head *i, *tmp; + struct queue_node *node; + + /* XXX: set cur_size and num_elems */ + list_for_each_safe(i, tmp, &b->head) { + node = (struct queue_node *) i; + list_del(i); + free(node); + } + free(b); +} + +static struct queue_node *queue_node_create(const void *data, size_t size) +{ + struct queue_node *n; + + n = malloc(sizeof(struct queue_node) + size); + if (n == NULL) + return NULL; + + INIT_LIST_HEAD(&n->head); + n->size = size; + memcpy(n->data, data, size); + + return n; +} + +int queue_add(struct queue *b, const void *data, size_t size) +{ + int ret = 0; + struct queue_node *n; + + /* does it fit this queue? */ + if (size > b->max_size) { + errno = ENOSPC; + ret = -1; + goto err; + } + +retry: + /* queue is full: kill the oldest entry */ + if (b->cur_size + size > b->max_size) { + n = (struct queue_node *) b->head.prev; + list_del(b->head.prev); + b->cur_size -= n->size; + free(n); + goto retry; + } + + n = queue_node_create(data, size); + if (n == NULL) { + ret = -1; + goto err; + } + + list_add(&n->head, &b->head); + b->cur_size += size; + b->num_elems++; + +err: + return ret; +} + +void queue_del(struct queue *b, void *data) +{ + struct queue_node *n = container_of(data, struct queue_node, data); + + list_del(&n->head); + b->cur_size -= n->size; + b->num_elems--; + free(n); +} + +void queue_iterate(struct queue *b, + void *data, + int (*iterate)(void *data1, void *data2)) +{ + struct list_head *i, *tmp; + struct queue_node *n; + + list_for_each_safe(i, tmp, &b->head) { + n = (struct queue_node *) i; + if (iterate(n->data, data)) + break; + } +} + +unsigned int queue_len(struct queue *b) +{ + return b->num_elems; +} diff --git a/src/read_config_yy.y b/src/read_config_yy.y index e2bb4c8..9cb304a 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -406,14 +406,14 @@ sync_mode_alarm_line: refreshtime sync_mode_ftfw_list: | sync_mode_ftfw_list sync_mode_ftfw_line; -sync_mode_ftfw_line: resend_buffer_size +sync_mode_ftfw_line: resend_queue_size | timeout | window_size ; -resend_buffer_size: T_RESEND_BUFFER_SIZE T_NUMBER +resend_queue_size: T_RESEND_BUFFER_SIZE T_NUMBER { - conf.resend_buffer_size = $2; + conf.resend_queue_size = $2; }; window_size: T_WINDOWSIZE T_NUMBER @@ -685,8 +685,8 @@ init_config(char *filename) if (CONFIG(refresh) == 0) CONFIG(refresh) = 60; - if (CONFIG(resend_buffer_size) == 0) - CONFIG(resend_buffer_size) = 262144; + if (CONFIG(resend_queue_size) == 0) + CONFIG(resend_queue_size) = 262144; /* create empty pool */ if (!STATE(ignore_pool)) { diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 2f27fe6..c3b9f61 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -1,5 +1,5 @@ /* - * (C) 2006-2007 by Pablo Neira Ayuso + * (C) 2006-2008 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 @@ -21,7 +21,7 @@ #include "sync.h" #include "linux_list.h" #include "us-conntrack.h" -#include "buffer.h" +#include "queue.h" #include "debug.h" #include "network.h" #include "alarm.h" @@ -37,8 +37,8 @@ static LIST_HEAD(rs_list); static LIST_HEAD(tx_list); static unsigned int tx_list_len; -static struct buffer *rs_queue; -static struct buffer *tx_queue; +static struct queue *rs_queue; +static struct queue *tx_queue; struct cache_ftfw { struct list_head rs_list; @@ -72,15 +72,15 @@ static struct cache_extra cache_ftfw_extra = { static int ftfw_init() { - tx_queue = buffer_create(CONFIG(resend_buffer_size)); + tx_queue = queue_create(CONFIG(resend_queue_size)); if (tx_queue == NULL) { - dlog(STATE(log), LOG_ERR, "cannot create tx buffer"); + dlog(STATE(log), LOG_ERR, "cannot create tx queue"); return -1; } - rs_queue = buffer_create(CONFIG(resend_buffer_size)); + rs_queue = queue_create(CONFIG(resend_queue_size)); if (rs_queue == NULL) { - dlog(STATE(log), LOG_ERR, "cannot create rs buffer"); + dlog(STATE(log), LOG_ERR, "cannot create rs queue"); return -1; } @@ -92,8 +92,8 @@ static int ftfw_init() static void ftfw_kill() { - buffer_destroy(rs_queue); - buffer_destroy(tx_queue); + queue_destroy(rs_queue); + queue_destroy(tx_queue); } static void tx_queue_add_ctlmsg(u_int32_t flags, u_int32_t from, u_int32_t to) @@ -104,7 +104,7 @@ static void tx_queue_add_ctlmsg(u_int32_t flags, u_int32_t from, u_int32_t to) .to = to, }; - buffer_add(tx_queue, &ack, NETHDR_ACK_SIZ); + queue_add(tx_queue, &ack, NETHDR_ACK_SIZ); } static int do_cache_to_tx(void *data1, void *data2) @@ -148,7 +148,7 @@ static int rs_queue_to_tx(void *data1, void *data2) if (between(net->seq, nack->from, nack->to)) { dp("rs_queue_to_tx sq: %u fl:%u len:%u\n", net->seq, net->flags, net->len); - buffer_add(tx_queue, net, net->len); + queue_add(tx_queue, net, net->len); } return 0; } @@ -159,8 +159,8 @@ static int rs_queue_empty(void *data1, void *data2) struct nethdr_ack *h = data2; if (between(net->seq, h->from, h->to)) { - dp("remove from buffer (seq=%u)\n", net->seq); - buffer_del(rs_queue, data1); + dp("remove from queue (seq=%u)\n", net->seq); + queue_del(rs_queue, data1); } return 0; } @@ -227,7 +227,7 @@ static int ftfw_recv(const struct nethdr *net) dp("NACK: from seq=%u to seq=%u\n", nack->from, nack->to); rs_list_to_tx(STATE_SYNC(internal), nack->from, nack->to); - buffer_iterate(rs_queue, nack, rs_queue_to_tx); + queue_iterate(rs_queue, nack, rs_queue_to_tx); return 1; } else if (IS_RESYNC(net)) { dp("RESYNC ALL\n"); @@ -238,7 +238,7 @@ static int ftfw_recv(const struct nethdr *net) dp("ACK: from seq=%u to seq=%u\n", h->from, h->to); rs_list_empty(STATE_SYNC(internal), h->from, h->to); - buffer_iterate(rs_queue, h, rs_queue_empty); + queue_iterate(rs_queue, h, rs_queue_empty); return 1; } else if (IS_ALIVE(net)) return 1; @@ -270,7 +270,7 @@ insert: list_add(&cn->rs_list, &rs_list); break; case NFCT_Q_DESTROY: - buffer_add(rs_queue, net, net->len); + queue_add(rs_queue, net, net->len); break; } } @@ -289,9 +289,9 @@ static int tx_queue_xmit(void *data1, void *data2) if (IS_DATA(net) || IS_ACK(net) || IS_NACK(net)) { dp("-> back_to_tx_queue sq: %u fl:%u len:%u\n", net->seq, net->flags, net->len); - buffer_add(rs_queue, net, net->len); + queue_add(rs_queue, net, net->len); } - buffer_del(tx_queue, net); + queue_del(tx_queue, net); return 0; } @@ -330,7 +330,7 @@ static void ftfw_run(int step) struct list_head *i, *tmp; /* send messages in the tx_queue */ - buffer_iterate(tx_queue, NULL, tx_queue_xmit); + queue_iterate(tx_queue, NULL, tx_queue_xmit); /* send conntracks in the tx_list */ list_for_each_safe(i, tmp, &tx_list) { diff --git a/src/sync-mode.c b/src/sync-mode.c index d54e169..a90e529 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -27,7 +27,6 @@ #include #include "sync.h" #include "network.h" -#include "buffer.h" #include "debug.h" static void do_mcast_handler_step(struct nethdr *net) -- cgit v1.2.3 From 1102a95296e39f671efe51bb6bd9b30e5c14c91e Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Sat, 5 Jan 2008 16:41:15 +0000 Subject: implement buffered connection logging to improve performance --- ChangeLog | 1 + doc/stats/conntrackd.conf | 10 +++++++ include/buffer.h | 18 +++++++++++++ include/conntrackd.h | 3 +++ include/log.h | 8 +++++- src/Makefile.am | 2 +- src/buffer.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++ src/log.c | 28 +++++++++++++++++--- src/read_config_lex.l | 1 + src/read_config_yy.y | 8 +++++- src/stats-mode.c | 12 ++++++++- 11 files changed, 151 insertions(+), 7 deletions(-) create mode 100644 include/buffer.h create mode 100644 src/buffer.c (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 82072f4..ed21d7f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -26,6 +26,7 @@ o add support for related conntracks (requires Linux kernel >= 2.6.22) o show error and warning messages to stderr o hash lookup speedups based on comments from netdev's discussions o add support for connection logging to the statistics mode via Logfile +o implement buffered connection logging to improve performance o minor irrelevant fixes for uncommon error paths and fix several typos o detach daemon from its terminal (Ben Lenitz ) o obsolete `-S' option: Use information provided by the config file diff --git a/doc/stats/conntrackd.conf b/doc/stats/conntrackd.conf index 4bc5642..8f899b4 100644 --- a/doc/stats/conntrackd.conf +++ b/doc/stats/conntrackd.conf @@ -58,6 +58,16 @@ Stats { # LogFile on + # + # Set Logfile buffer size. Default is 0. + # You can set the size of the connection logging buffer size. This + # value determines how often the logging information is written to + # the harddisk. High values improves performances. If your firewall + # is very busy and you need connection logging, use a big buffer. + # Default buffer size is 0 that means direct write through. + # + #LogFileBufferSize 4096 + # # Enable connection logging via Syslog. Default is off. # Syslog: on, off or a facility name (daemon (default) or local0..7) diff --git a/include/buffer.h b/include/buffer.h new file mode 100644 index 0000000..5b854f3 --- /dev/null +++ b/include/buffer.h @@ -0,0 +1,18 @@ +#ifndef _BUFFER_H_ +#define _BUFFER_H_ + +struct buffer { + unsigned char *data; + unsigned int size; + unsigned int cur_size; +}; + +struct buffer *buffer_create(unsigned int size); +int buffer_add(struct buffer *b, void *data, unsigned int size); +void buffer_flush(struct buffer *b, + void (*cb)(void *buffer_data, + void *data), + void *data); +unsigned int buffer_size(struct buffer *b); + +#endif diff --git a/include/conntrackd.h b/include/conntrackd.h index a4a91ea..3bfcf18 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -7,6 +7,7 @@ #include #include #include "cache.h" +#include "buffer.h" #include "debug.h" #include #include "state_helper.h" @@ -93,6 +94,7 @@ struct ct_conf { struct { char logfile[FILENAME_MAXLEN]; int syslog_facility; + unsigned int buffer_size; } stats; }; @@ -136,6 +138,7 @@ struct ct_sync_state { struct ct_stats_state { struct cache *cache; /* internal events cache (netlink) */ + struct buffer *buffer_log; }; union ct_state { diff --git a/include/log.h b/include/log.h index 467ae8f..b5bbddb 100644 --- a/include/log.h +++ b/include/log.h @@ -1,9 +1,15 @@ #ifndef _LOG_H_ #define _LOG_H_ +#include + +struct buffer; +struct nf_conntrack; + int init_log(); void dlog(FILE *fd, int priority, char *format, ...); -void dlog_ct(FILE *fd, struct nf_conntrack *ct); +void dlog_buffered_ct(FILE *fd, struct buffer *b, struct nf_conntrack *ct); +void dlog_buffered_ct_flush(void *buffer_data, void *data); void close_log(); #endif diff --git a/src/Makefile.am b/src/Makefile.am index 62a7467..a7e82cf 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -10,7 +10,7 @@ conntrack_SOURCES = conntrack.c conntrack_LDADD = ../extensions/libct_proto_tcp.la ../extensions/libct_proto_udp.la ../extensions/libct_proto_icmp.la conntrack_LDFLAGS = $(all_libraries) @LIBNETFILTER_CONNTRACK_LIBS@ -conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c \ +conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c buffer.c \ local.c log.c mcast.c netlink.c \ ignore_pool.c \ cache.c cache_iterators.c \ diff --git a/src/buffer.c b/src/buffer.c new file mode 100644 index 0000000..3283c15 --- /dev/null +++ b/src/buffer.c @@ -0,0 +1,67 @@ +/* + * (C) 2006-2008 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include "buffer.h" + +struct buffer *buffer_create(unsigned int size) +{ + struct buffer *b; + + b = malloc(sizeof(struct buffer)); + if (b == NULL) + return NULL; + memset(b, 0, sizeof(struct buffer)); + + b->size = size; + + b->data = malloc(size); + if (b->data == NULL) { + free(b); + return NULL; + } + memset(b->data, 0, size); + + return b; +} + +int buffer_add(struct buffer *b, void *data, unsigned int size) +{ + if (b->size - b->cur_size < size) { + errno = ENOSPC; + return -1; + } + + memcpy(b->data + b->cur_size, data, size); + b->cur_size += size; +} + +void buffer_flush(struct buffer *b, + void (*cb)(void *buffer_data, void *data), + void *data) +{ + cb(b->data, data); + b->cur_size = 0; + memset(b->data, 0, b->size); +} + +unsigned int buffer_size(struct buffer *b) +{ + return b->size; +} diff --git a/src/log.c b/src/log.c index a4d51ec..3e3dd12 100644 --- a/src/log.c +++ b/src/log.c @@ -22,6 +22,7 @@ #include #include #include +#include "buffer.h" #include "conntrackd.h" int init_log(void) @@ -94,7 +95,15 @@ void dlog(FILE *fd, int priority, char *format, ...) } } -void dlog_ct(FILE *fd, struct nf_conntrack *ct) +void dlog_buffered_ct_flush(void *buffer_data, void *data) +{ + FILE *fd = data; + + fprintf(fd, "%s", buffer_data); + fflush(fd); +} + +void dlog_buffered_ct(FILE *fd, struct buffer *b, struct nf_conntrack *ct) { time_t t; char buf[1024]; @@ -107,8 +116,21 @@ void dlog_ct(FILE *fd, struct nf_conntrack *ct) nfct_snprintf(buf+strlen(buf), 1024-strlen(buf), ct, 0, 0, 0); if (fd) { - fprintf(fd, "%s\n", buf); - fflush(fd); + snprintf(buf+strlen(buf), 1024-strlen(buf), "\n"); + /* zero size buffer: force fflush */ + if (buffer_size(b) == 0) { + fprintf(fd, "%s", buf); + fflush(fd); + } + + if (buffer_add(b, buf, strlen(buf)) == -1) { + buffer_flush(b, dlog_buffered_ct_flush, fd); + if (buffer_add(b, buf, strlen(buf)) == -1) { + /* buffer too small, catacrocket! */ + fprintf(fd, "%s", buf); + fflush(fd); + } + } } if (CONFIG(stats).syslog_facility != -1) diff --git a/src/read_config_lex.l b/src/read_config_lex.l index 847ec74..0acd98c 100644 --- a/src/read_config_lex.l +++ b/src/read_config_lex.l @@ -102,6 +102,7 @@ ftfw [F|f][T|t][F|f][W|w] "TIME_WAIT" { return T_TIME_WAIT; } "CLOSE" { return T_CLOSE; } "LISTEN" { return T_LISTEN; } +"LogFileBufferSize" { return T_STAT_BUFFER_SIZE; } {is_on} { return T_ON; } {is_off} { return T_OFF; } diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 9cb304a..bbc5115 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -49,7 +49,7 @@ struct ct_conf conf; %token T_REPLICATE T_FOR T_IFACE %token T_ESTABLISHED T_SYN_SENT T_SYN_RECV T_FIN_WAIT %token T_CLOSE_WAIT T_LAST_ACK T_TIME_WAIT T_CLOSE T_LISTEN -%token T_SYSLOG T_WRITE_THROUGH +%token T_SYSLOG T_WRITE_THROUGH T_STAT_BUFFER_SIZE %token T_IP T_PATH_VAL @@ -580,6 +580,7 @@ stat_line: stat_logfile_bool | stat_logfile_path | stat_syslog_bool | stat_syslog_facility + | buffer_size ; stat_logfile_bool : T_LOG T_ON @@ -638,6 +639,11 @@ stat_syslog_facility : T_SYSLOG T_STRING "values, defaulting to General.\n"); }; +buffer_size: T_STAT_BUFFER_SIZE T_NUMBER +{ + conf.stats.buffer_size = $2; +}; + %% int diff --git a/src/stats-mode.c b/src/stats-mode.c index e817c4e..05a1b2c 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -18,6 +18,7 @@ #include #include "cache.h" +#include "log.h" #include "conntrackd.h" #include #include @@ -37,6 +38,12 @@ static int init_stats(void) } memset(state.stats, 0, sizeof(struct ct_stats_state)); + STATE_STATS(buffer_log) = buffer_create(CONFIG(stats).buffer_size); + if (!STATE_STATS(buffer_log)) { + dlog(STATE(log), LOG_ERR, "can't allocate stats buffer"); + return -1; + } + STATE_STATS(cache) = cache_create("stats", LIFETIME, CONFIG(family), @@ -53,6 +60,9 @@ static int init_stats(void) static void kill_stats() { cache_destroy(STATE_STATS(cache)); + buffer_flush(STATE_STATS(buffer_log), + dlog_buffered_ct_flush, + STATE(stats_log)); } /* handler for requests coming via UNIX socket */ @@ -172,7 +182,7 @@ static int event_destroy_stats(struct nf_conntrack *ct) if (cache_del(STATE_STATS(cache), ct)) { debug_ct(ct, "cache destroy"); - dlog_ct(STATE(stats_log), ct); + dlog_buffered_ct(STATE(stats_log), STATE_STATS(buffer_log), ct); return 1; } else { debug_ct(ct, "can't destroy!"); -- cgit v1.2.3 From 974d151ef8587d5ba3b6442eec500fefb18b4a9c Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Sat, 5 Jan 2008 17:21:28 +0000 Subject: fix logfiles permissions, do not default to umask --- ChangeLog | 1 + src/log.c | 38 ++++++++++++++++++++++++++++++++------ src/main.c | 4 +--- 3 files changed, 34 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index ed21d7f..6d0bdc0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -32,6 +32,7 @@ o detach daemon from its terminal (Ben Lenitz ) o obsolete `-S' option: Use information provided by the config file o daemonize conntrackd after initialization o rename class `buffer' to `queue' which is what it really implements +o fix logfiles permissions, do not default to umask version 0.9.5 (2007/07/29) ------------------------------ diff --git a/src/log.c b/src/log.c index 3e3dd12..176bdcd 100644 --- a/src/log.c +++ b/src/log.c @@ -19,28 +19,54 @@ */ #include +#include +#include +#include #include #include #include +#include #include "buffer.h" #include "conntrackd.h" int init_log(void) { if (CONFIG(logfile)[0]) { - STATE(log) = fopen(CONFIG(logfile), "a+"); + int fd; + + fd = open(CONFIG(logfile), O_CREAT | O_RDWR, 0600); + if (fd == -1) { + fprintf(stderr, "ERROR: can't open logfile `%s'." + "Reason: %s\n", CONFIG(logfile), + strerror(errno)); + return -1; + } + + STATE(log) = fdopen(fd, "a+"); if (STATE(log) == NULL) { - fprintf(stderr, "can't open log file `%s'\n", - CONFIG(logfile)); + fprintf(stderr, "ERROR: can't open logfile `%s'." + "Reason: %s\n", CONFIG(logfile), + strerror(errno)); return -1; } } if (CONFIG(stats).logfile[0]) { - STATE(stats_log) = fopen(CONFIG(stats).logfile, "a+"); + int fd; + + fd = open(CONFIG(stats).logfile, O_CREAT | O_RDWR, 0600); + if (fd == -1) { + fprintf(stderr, "ERROR: can't open logfile `%s'." + "Reason: %s\n", CONFIG(stats).logfile, + strerror(errno)); + return -1; + } + + STATE(stats_log) = fdopen(fd, "a+"); if (STATE(stats_log) == NULL) { - fprintf(stderr, "can't open log file `%s'\n", - CONFIG(stats).logfile); + fprintf(stderr, "ERROR: can't open logfile `%s'." + "Reason: %s\n", CONFIG(stats).logfile, + strerror(errno)); return -1; } } diff --git a/src/main.c b/src/main.c index 3cf44ba..33235e9 100644 --- a/src/main.c +++ b/src/main.c @@ -246,10 +246,8 @@ int main(int argc, char *argv[]) /* * Setting up logging */ - if (config_set && init_log() == -1) { - fprintf(stderr, "can't open logfile `%s\n'", CONFIG(logfile)); + if (config_set && init_log() == -1) exit(EXIT_FAILURE); - } if (type == REQUEST) { if (do_local_request(action, &conf.local, local_step) == -1) { -- cgit v1.2.3 From 6023de67c84e531939b77454783835c65f694bff Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Mon, 7 Jan 2008 16:32:10 +0000 Subject: fix segfaul in the exit path for the statistics mode (introduced in r7175) --- src/log.c | 3 ++- src/run.c | 2 +- src/stats-mode.c | 8 +++++--- 3 files changed, 8 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/log.c b/src/log.c index 176bdcd..51109b6 100644 --- a/src/log.c +++ b/src/log.c @@ -171,6 +171,7 @@ void close_log(void) if (STATE(stats_log) != NULL) fclose(STATE(stats_log)); - if (CONFIG(syslog_facility) != -1) + if (CONFIG(syslog_facility) != -1 || + CONFIG(stats).syslog_facility != -1) closelog(); } diff --git a/src/run.c b/src/run.c index ebf4b3c..609b454 100644 --- a/src/run.c +++ b/src/run.c @@ -41,7 +41,7 @@ void killer(int foo) destroy_alarm_scheduler(); unlink(CONFIG(lockfile)); dlog(STATE(log), LOG_NOTICE, "---- shutdown received ----"); - close_log(STATE(log)); + close_log(); sigprocmask(SIG_UNBLOCK, &STATE(block), NULL); diff --git a/src/stats-mode.c b/src/stats-mode.c index 05a1b2c..ee9b3fd 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -60,9 +60,11 @@ static int init_stats(void) static void kill_stats() { cache_destroy(STATE_STATS(cache)); - buffer_flush(STATE_STATS(buffer_log), - dlog_buffered_ct_flush, - STATE(stats_log)); + /* flush the buffer before exiting */ + if (STATE(stats_log) != NULL) + buffer_flush(STATE(stats_log), + dlog_buffered_ct_flush, + STATE(stats_log)); } /* handler for requests coming via UNIX socket */ -- cgit v1.2.3 From 920b90f2b03c60b6940e83cdce8c4b4bfbbc4268 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Wed, 9 Jan 2008 22:52:31 +0000 Subject: wake up the daemon iff there are real events to handle instead of polling (Based on comments from Max Kellerman) --- ChangeLog | 1 + include/Makefile.am | 2 +- include/alarm.h | 2 +- include/conntrackd.h | 2 +- include/sync.h | 2 +- include/timer.h | 17 ------------ src/Makefile.am | 1 - src/alarm.c | 74 ++++++++++++++++++++++----------------------------- src/cache_timer.c | 8 ++++-- src/main.c | 2 +- src/run.c | 47 +++++++++++--------------------- src/sync-alarm.c | 14 +++++++--- src/sync-ftfw.c | 60 +++++++++++++++++++++-------------------- src/sync-mode.c | 4 +-- src/timer.c | 75 ---------------------------------------------------- 15 files changed, 103 insertions(+), 208 deletions(-) delete mode 100644 include/timer.h delete mode 100644 src/timer.c (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 6d0bdc0..8634c1e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -33,6 +33,7 @@ o obsolete `-S' option: Use information provided by the config file o daemonize conntrackd after initialization o rename class `buffer' to `queue' which is what it really implements o fix logfiles permissions, do not default to umask +o wake up the daemon iff there are real events to handle instead of polling version 0.9.5 (2007/07/29) ------------------------------ diff --git a/include/Makefile.am b/include/Makefile.am index 7eaca35..4322f26 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -2,5 +2,5 @@ noinst_HEADERS = alarm.h jhash.h slist.h cache.h linux_list.h \ sync.h conntrackd.h local.h us-conntrack.h \ debug.h log.h hash.h mcast.h buffer.h conntrack.h \ - state_helper.h network.h ignore.h timer.h queue.h + state_helper.h network.h ignore.h queue.h diff --git a/include/alarm.h b/include/alarm.h index 93e6482..82a1612 100644 --- a/include/alarm.h +++ b/include/alarm.h @@ -5,7 +5,7 @@ struct alarm_list { struct list_head head; - unsigned long expires; + struct timeval tv; void *data; void (*function)(struct alarm_list *a, void *data); }; diff --git a/include/conntrackd.h b/include/conntrackd.h index 3bfcf18..e8b90cc 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -159,7 +159,7 @@ extern struct ct_general_state st; struct ct_mode { int (*init)(void); int (*add_fds_to_set)(fd_set *readfds); - void (*run)(fd_set *readfds, int step); + void (*run)(fd_set *readfds); int (*local)(int fd, int type, void *data); void (*kill)(void); void (*dump)(struct nf_conntrack *ct); diff --git a/include/sync.h b/include/sync.h index a27fb93..e6ce327 100644 --- a/include/sync.h +++ b/include/sync.h @@ -15,7 +15,7 @@ struct sync_mode { int (*local)(int fd, int type, void *data); int (*recv)(const struct nethdr *net); void (*send)(struct nethdr *net, struct us_conntrack *u); - void (*run)(int step); + void (*run)(void); }; extern struct sync_mode alarm; diff --git a/include/timer.h b/include/timer.h deleted file mode 100644 index 37b0fc9..0000000 --- a/include/timer.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef _TIMER_H_ -#define _TIMER_H_ - -#include - -struct timer { - long credits; - struct timeval start; - struct timeval stop; - struct timeval diff; -}; - -#define GET_CREDITS(x) x.credits -#define GET_STARTTIME(x) x.start -#define GET_STOPTIME(x) x.stop - -#endif diff --git a/src/Makefile.am b/src/Makefile.am index a7e82cf..c2e684a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -19,7 +19,6 @@ conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c buffer.c \ traffic_stats.c stats-mode.c \ network.c \ state_helper.c state_helper_tcp.c \ - timer.c \ build.c parse.c \ read_config_yy.y read_config_lex.l diff --git a/src/alarm.c b/src/alarm.c index b4db167..e1d2e24 100644 --- a/src/alarm.c +++ b/src/alarm.c @@ -18,6 +18,7 @@ #include #include +#include #include "linux_list.h" #include "conntrackd.h" #include "alarm.h" @@ -25,23 +26,16 @@ #include #include -/* alarm cascade */ -#define ALARM_CASCADE_SIZE STEPS_PER_SECONDS -static struct list_head *alarm_cascade; +static LIST_HEAD(alarm_list); -struct alarm_list *create_alarm() -{ - return (struct alarm_list *) malloc(sizeof(struct alarm_list)); -} - -void destroy_alarm(struct alarm_list *t) +void set_alarm_expiration_secs(struct alarm_list *t, unsigned long expires) { - free(t); + t->tv.tv_sec = expires; } -void set_alarm_expiration(struct alarm_list *t, unsigned long expires) +void set_alarm_expiration_usecs(struct alarm_list *t, unsigned long expires) { - t->expires = expires; + t->tv.tv_usec = expires; } void set_alarm_function(struct alarm_list *t, @@ -59,16 +53,18 @@ void init_alarm(struct alarm_list *t) { INIT_LIST_HEAD(&t->head); - t->expires = 0; + timerclear(&t->tv); t->data = 0; t->function = NULL; } void add_alarm(struct alarm_list *alarm) { - unsigned int pos = jhash(alarm, sizeof(alarm), 0) % ALARM_CASCADE_SIZE; + struct timeval tv; - list_add(&alarm->head, &alarm_cascade[pos]); + gettimeofday(&tv, NULL); + alarm->tv.tv_sec += tv.tv_sec; + list_add_tail(&alarm->head, &alarm_list); } void del_alarm(struct alarm_list *alarm) @@ -76,41 +72,35 @@ void del_alarm(struct alarm_list *alarm) list_del(&alarm->head); } -int mod_alarm(struct alarm_list *alarm, unsigned long expires) +void mod_alarm(struct alarm_list *alarm, unsigned long sc, unsigned long usc) { - alarm->expires = expires; - return 0; + struct timeval tv; + + list_del(&alarm->head); + INIT_LIST_HEAD(&alarm->head); + gettimeofday(&tv, NULL); + alarm->tv.tv_sec = tv.tv_sec + sc; + alarm->tv.tv_usec = tv.tv_usec + usc; + list_add_tail(&alarm->head, &alarm_list); } -void do_alarm_run(int step) +void do_alarm_run(struct timeval *next_alarm) { struct list_head *i, *tmp; struct alarm_list *t; + struct timeval tv; - list_for_each_safe(i, tmp, &alarm_cascade[step]) { - t = (struct alarm_list *) i; - - t->expires--; - if (t->expires == 0) - t->function(t, t->data); - } -} + gettimeofday(&tv, NULL); -int init_alarm_scheduler() -{ - int i; - - alarm_cascade = malloc(sizeof(struct list_head) * ALARM_CASCADE_SIZE); - if (alarm_cascade == NULL) - return -1; + list_for_each_safe(i, tmp, &alarm_list) { + t = (struct alarm_list *) i; - for (i=0; itv, &tv, >)) { + timersub(&t->tv, &tv, next_alarm); + break; + } - return 0; -} - -void destroy_alarm_scheduler() -{ - free(alarm_cascade); + del_alarm(t); + t->function(t, t->data); + } } diff --git a/src/cache_timer.c b/src/cache_timer.c index f3940f3..c0075f5 100644 --- a/src/cache_timer.c +++ b/src/cache_timer.c @@ -17,6 +17,7 @@ */ #include +#include #include "conntrackd.h" #include "us-conntrack.h" #include "cache.h" @@ -35,7 +36,7 @@ static void timer_add(struct us_conntrack *u, void *data) struct alarm_list *alarm = data; init_alarm(alarm); - set_alarm_expiration(alarm, CONFIG(cache_timeout)); + set_alarm_expiration_secs(alarm, CONFIG(cache_timeout)); set_alarm_data(alarm, u); set_alarm_function(alarm, timeout); add_alarm(alarm); @@ -55,12 +56,15 @@ static void timer_destroy(struct us_conntrack *u, void *data) static int timer_dump(struct us_conntrack *u, void *data, char *buf, int type) { + struct timeval tv, tmp; struct alarm_list *alarm = data; if (type == NFCT_O_XML) return 0; - return sprintf(buf, " [expires in %ds]", alarm->expires); + gettimeofday(&tv, NULL); + timersub(&tv, &alarm->tv, &tmp); + return sprintf(buf, " [expires in %ds]", tmp.tv_sec); } struct cache_feature timer_feature = { diff --git a/src/main.c b/src/main.c index 33235e9..19d999a 100644 --- a/src/main.c +++ b/src/main.c @@ -246,7 +246,7 @@ int main(int argc, char *argv[]) /* * Setting up logging */ - if (config_set && init_log() == -1) + if (init_log() == -1) exit(EXIT_FAILURE); if (type == REQUEST) { diff --git a/src/run.c b/src/run.c index 609b454..3dc8ecc 100644 --- a/src/run.c +++ b/src/run.c @@ -25,7 +25,6 @@ #include #include #include -#include "timer.h" void killer(int foo) { @@ -38,7 +37,6 @@ void killer(int foo) ignore_pool_destroy(STATE(ignore_pool)); local_server_destroy(STATE(local)); STATE(mode)->kill(); - destroy_alarm_scheduler(); unlink(CONFIG(lockfile)); dlog(STATE(log), LOG_NOTICE, "---- shutdown received ----"); close_log(); @@ -103,11 +101,6 @@ int init(void) return -1; } - if (init_alarm_scheduler() == -1) { - dlog(STATE(log), LOG_ERR, "can't initialize alarm scheduler"); - return -1; - } - /* local UNIX socket */ STATE(local) = local_server_create(&CONFIG(local)); if (!STATE(local)) { @@ -151,14 +144,10 @@ int init(void) return 0; } -static void __run(long credit, int step) +static int __run(struct timeval *next_alarm) { int max, ret; fd_set readfds; - struct timeval tv = { - .tv_sec = 0, - .tv_usec = credit, - }; FD_ZERO(&readfds); FD_SET(STATE(local), &readfds); @@ -169,7 +158,7 @@ static void __run(long credit, int step) if (STATE(mode)->add_fds_to_set) max = MAX(max, STATE(mode)->add_fds_to_set(&readfds)); - ret = select(max+1, &readfds, NULL, NULL, &tv); + ret = select(max+1, &readfds, NULL, NULL, next_alarm); if (ret == -1) { /* interrupted syscall, retry */ if (errno == EINTR) @@ -180,6 +169,10 @@ static void __run(long credit, int step) return; } + /* timeout expired, run the alarm list */ + if (ret == 0) + return 1; + /* signals are racy */ sigprocmask(SIG_BLOCK, &STATE(block), NULL); @@ -221,35 +214,25 @@ static void __run(long credit, int step) } if (STATE(mode)->run) - STATE(mode)->run(&readfds, step); + STATE(mode)->run(&readfds); sigprocmask(SIG_UNBLOCK, &STATE(block), NULL); + + return 0; } void run(void) { - int step = 0; - struct timer timer; - - timer_init(&timer); + struct timeval next_alarm = { + .tv_sec = 1, + .tv_usec = 0 + }; while(1) { - timer_start(&timer); - __run(GET_CREDITS(timer), step); - timer_stop(&timer); - - if (timer_adjust_credit(&timer)) { - timer_start(&timer); + if (__run(&next_alarm)) { sigprocmask(SIG_BLOCK, &STATE(block), NULL); - do_alarm_run(step); + do_alarm_run(&next_alarm); sigprocmask(SIG_UNBLOCK, &STATE(block), NULL); - timer_stop(&timer); - - if (timer_adjust_credit(&timer)) - dlog(STATE(log), LOG_WARNING, - "alarm run takes too long!"); - - step = (step + 1) < STEPS_PER_SECONDS ? step + 1 : 0; } } } diff --git a/src/sync-alarm.c b/src/sync-alarm.c index a0791ac..632eff2 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -30,7 +30,14 @@ static void refresher(struct alarm_list *a, void *data) debug_ct(u->ct, "persistence update"); - a->expires = random() % CONFIG(refresh) + 1; + init_alarm(a); + set_alarm_expiration_secs(a, random() % CONFIG(refresh) + 1); + set_alarm_expiration_usecs(a, random() % 999999 + 1); + + set_alarm_data(a, u); + set_alarm_function(a, refresher); + add_alarm(a); + net = BUILD_NETMSG(u->ct, NFCT_Q_UPDATE); len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); @@ -41,7 +48,8 @@ static void cache_alarm_add(struct us_conntrack *u, void *data) struct alarm_list *alarm = data; init_alarm(alarm); - set_alarm_expiration(alarm, (random() % conf.refresh) + 1); + set_alarm_expiration_secs(alarm, random() % CONFIG(refresh) + 1); + set_alarm_expiration_usecs(alarm, random() % 999999 + 1); set_alarm_data(alarm, u); set_alarm_function(alarm, refresher); add_alarm(alarm); @@ -50,7 +58,7 @@ static void cache_alarm_add(struct us_conntrack *u, void *data) static void cache_alarm_update(struct us_conntrack *u, void *data) { struct alarm_list *alarm = data; - mod_alarm(alarm, (random() % conf.refresh) + 1); + mod_alarm(alarm, random() % CONFIG(refresh) + 1, random() % 999999 + 1); } static void cache_alarm_destroy(struct us_conntrack *u, void *data) diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index c3b9f61..ac1b8b6 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -70,6 +70,29 @@ static struct cache_extra cache_ftfw_extra = { .destroy = cache_ftfw_del }; +static void tx_queue_add_ctlmsg(u_int32_t flags, u_int32_t from, u_int32_t to) +{ + struct nethdr_ack ack = { + .flags = flags, + .from = from, + .to = to, + }; + + queue_add(tx_queue, &ack, NETHDR_ACK_SIZ); +} + +static struct alarm_list alive_alarm; + +static void do_alive_alarm(struct alarm_list *a, void *data) +{ + tx_queue_add_ctlmsg(NET_F_ALIVE, 0, 0); + + init_alarm(&alive_alarm); + set_alarm_expiration_secs(&alive_alarm, 1); + set_alarm_function(&alive_alarm, do_alive_alarm); + add_alarm(&alive_alarm); +} + static int ftfw_init() { tx_queue = queue_create(CONFIG(resend_queue_size)); @@ -87,6 +110,12 @@ static int ftfw_init() INIT_LIST_HEAD(&tx_list); INIT_LIST_HEAD(&rs_list); + /* XXX: alive message expiration configurable */ + init_alarm(&alive_alarm); + set_alarm_expiration_secs(&alive_alarm, 1); + set_alarm_function(&alive_alarm, do_alive_alarm); + add_alarm(&alive_alarm); + return 0; } @@ -96,17 +125,6 @@ static void ftfw_kill() queue_destroy(tx_queue); } -static void tx_queue_add_ctlmsg(u_int32_t flags, u_int32_t from, u_int32_t to) -{ - struct nethdr_ack ack = { - .flags = flags, - .from = from, - .to = to, - }; - - queue_add(tx_queue, &ack, NETHDR_ACK_SIZ); -} - static int do_cache_to_tx(void *data1, void *data2) { struct us_conntrack *u = data2; @@ -317,15 +335,7 @@ static int tx_list_xmit(struct list_head *i, struct us_conntrack *u) return ret; } -static struct alarm_list alive_alarm; - -static void do_alive_alarm(struct alarm_list *a, void *data) -{ - del_alarm(a); - tx_queue_add_ctlmsg(NET_F_ALIVE, 0, 0); -} - -static void ftfw_run(int step) +static void ftfw_run() { struct list_head *i, *tmp; @@ -342,15 +352,7 @@ static void ftfw_run(int step) tx_list_xmit(i, u); } - if (alive_alarm.expires > 0) - mod_alarm(&alive_alarm, 1); - else { - init_alarm(&alive_alarm); - /* XXX: alive message expiration configurable */ - set_alarm_expiration(&alive_alarm, 1); - set_alarm_function(&alive_alarm, do_alive_alarm); - add_alarm(&alive_alarm); - } + mod_alarm(&alive_alarm, 1, 0); } struct sync_mode ftfw = { diff --git a/src/sync-mode.c b/src/sync-mode.c index a90e529..3bd6f59 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -198,14 +198,14 @@ static int add_fds_to_set_sync(fd_set *readfds) return STATE_SYNC(mcast_server->fd); } -static void run_sync(fd_set *readfds, int step) +static void run_sync(fd_set *readfds) { /* multicast packet has been received */ if (FD_ISSET(STATE_SYNC(mcast_server->fd), readfds)) mcast_handler(); if (STATE_SYNC(sync)->run) - STATE_SYNC(sync)->run(step); + STATE_SYNC(sync)->run(); /* flush pending messages */ mcast_buffered_pending_netmsg(STATE_SYNC(mcast_client)); diff --git a/src/timer.c b/src/timer.c deleted file mode 100644 index b85c286..0000000 --- a/src/timer.c +++ /dev/null @@ -1,75 +0,0 @@ -/* - * (C) 2006-2007 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#include -#include -#include -#include "conntrackd.h" -#include "timer.h" - -#define TIMESLICE_CREDIT (1000000 / STEPS_PER_SECONDS) /* 200 ms timeslice */ - -void timer_init(struct timer *timer) -{ - memset(timer, 0, sizeof(struct timer)); - timer->credits = TIMESLICE_CREDIT; -} - -void timer_start(struct timer *timer) -{ - gettimeofday(&timer->start, NULL); -} - -static int timeval_subtract(struct timeval *diff, - struct timeval *start, - struct timeval *stop) -{ - diff->tv_sec = stop->tv_sec - start->tv_sec; - diff->tv_usec = stop->tv_usec - start->tv_usec; - - if (diff->tv_usec < 0) { - diff->tv_usec += 1000000; - diff->tv_sec--; - } - - /* Return 1 if result is negative. */ - return diff->tv_sec < 0; -} - -void timer_stop(struct timer *timer) -{ - gettimeofday(&timer->stop, NULL); - timeval_subtract(&timer->diff, &timer->start, &timer->stop); -} - -int timer_adjust_credit(struct timer *timer) -{ - if (timer->diff.tv_sec != 0) { - timer->credits = TIMESLICE_CREDIT; - return 1; - } - - timer->credits -= timer->diff.tv_usec; - - if (timer->credits < 0) { - timer->credits += TIMESLICE_CREDIT; - if (timer->credits < 0) - timer->credits = TIMESLICE_CREDIT; - return 1; - } - return 0; -} -- cgit v1.2.3 From 3370112cc3c9f0446fbe7375bdb32831872814f4 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Wed, 9 Jan 2008 23:15:31 +0000 Subject: fix statistics mode CPU sucks up (broken with 7178) --- src/run.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/run.c b/src/run.c index 3dc8ecc..7d166bb 100644 --- a/src/run.c +++ b/src/run.c @@ -227,11 +227,15 @@ void run(void) .tv_sec = 1, .tv_usec = 0 }; + struct timeval *next = &next_alarm; + + if (CONFIG(flags) & CTD_STATS_MODE) + next = NULL; while(1) { - if (__run(&next_alarm)) { + if (__run(next)) { sigprocmask(SIG_BLOCK, &STATE(block), NULL); - do_alarm_run(&next_alarm); + do_alarm_run(next); sigprocmask(SIG_UNBLOCK, &STATE(block), NULL); } } -- cgit v1.2.3 From a7cec817806de3855e42bc1a81f60fd4154b8cf2 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Fri, 11 Jan 2008 01:17:01 +0000 Subject: fix buffer flush before exiting --- src/stats-mode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/stats-mode.c b/src/stats-mode.c index ee9b3fd..20efc95 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -62,7 +62,7 @@ static void kill_stats() cache_destroy(STATE_STATS(cache)); /* flush the buffer before exiting */ if (STATE(stats_log) != NULL) - buffer_flush(STATE(stats_log), + buffer_flush(STATE_STATS(buffer_log), dlog_buffered_ct_flush, STATE(stats_log)); } -- cgit v1.2.3 From d6d156c2c062b83f173963e5d93f904898d3e93a Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Fri, 11 Jan 2008 01:48:36 +0000 Subject: add support for tagged vlan interfaces in the config file, e.g. eth0.1 --- ChangeLog | 1 + src/read_config_lex.l | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 8634c1e..805f307 100644 --- a/ChangeLog +++ b/ChangeLog @@ -34,6 +34,7 @@ o daemonize conntrackd after initialization o rename class `buffer' to `queue' which is what it really implements o fix logfiles permissions, do not default to umask o wake up the daemon iff there are real events to handle instead of polling +o add support for tagged vlan interfaces in the config file, e.g. eth0.1 version 0.9.5 (2007/07/29) ------------------------------ diff --git a/src/read_config_lex.l b/src/read_config_lex.l index 0acd98c..6211fee 100644 --- a/src/read_config_lex.l +++ b/src/read_config_lex.l @@ -42,7 +42,7 @@ ip6_part {hex_255}":"? ip6_form1 {ip6_part}{0,16}"::"{ip6_part}{0,16} ip6_form2 ({hex_255}":"){16}{hex_255} ip6 {ip6_form1}|{ip6_form2} -string [a-zA-Z][a-zA-Z0-9]* +string [a-zA-Z][a-zA-Z0-9\.]* persistent [P|p][E|e][R|r][S|s][I|i][S|s][T|t][E|e][N|n][T|T] nack [N|n][A|a][C|c][K|k] alarm [A|a][L|l][A|a][R|r][M|m] -- cgit v1.2.3 From c9de420557cdf546f09defbff3d5f682c01250aa Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Sun, 13 Jan 2008 16:14:17 +0000 Subject: add support for `conntrack -E -o xml,timestamp' --- ChangeLog | 1 + configure.in | 2 +- src/conntrack.c | 13 ++++++++----- 3 files changed, 10 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 0bea030..6d4759a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -11,6 +11,7 @@ o fix missing `-g' and `-n' options in getopt_long control string o add support for secmark (requires Linux kernel >= 2.6.25) o add mark and secmark information to the manpage o cleanup error message +o add support for -E -o xml,timestamp = conntrackd = o Remove window tracking disabling limitation (requires Linux kernel >= 2.6.22) diff --git a/configure.in b/configure.in index 78d88bd..75c6898 100644 --- a/configure.in +++ b/configure.in @@ -18,7 +18,7 @@ esac dnl Dependencies LIBNFNETLINK_REQUIRED=0.0.25 -LIBNETFILTER_CONNTRACK_REQUIRED=0.0.87 +LIBNETFILTER_CONNTRACK_REQUIRED=0.0.88 PKG_CHECK_MODULES(LIBNFNETLINK, libnfnetlink >= $LIBNFNETLINK_REQUIRED,, AC_MSG_ERROR(Cannot find libnfnetlink >= $LIBNFNETLINK_REQUIRED)) diff --git a/src/conntrack.c b/src/conntrack.c index fa6ae0a..20d86f9 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -591,11 +591,14 @@ static int event_cb(enum nf_conntrack_msg_type type, output_type = NFCT_O_XML; if (output_mask & _O_EXT) output_flags = NFCT_OF_SHOW_LAYER3; - if ((output_mask & _O_TMS) && !(output_mask & _O_XML)) { - struct timeval tv; - gettimeofday(&tv, NULL); - printf("[%-8ld.%-6ld]\t", tv.tv_sec, tv.tv_usec); - } + if (output_mask & _O_TMS) { + if (!(output_mask & _O_XML)) { + struct timeval tv; + gettimeofday(&tv, NULL); + printf("[%-8ld.%-6ld]\t", tv.tv_sec, tv.tv_usec); + } else + output_flags |= NFCT_OF_TIME; + } nfct_snprintf(buf, 1024, ct, type, output_type, output_flags); printf("%s\n", buf); -- cgit v1.2.3 From 94aa8b70f2e8cf7cf664d7c0e86a9ebc287010ef Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Mon, 14 Jan 2008 14:29:58 +0000 Subject: set up the configuration flags when defaulting --- src/run.c | 1 + src/sync-mode.c | 1 + 2 files changed, 2 insertions(+) (limited to 'src') diff --git a/src/run.c b/src/run.c index 7d166bb..eab3ad2 100644 --- a/src/run.c +++ b/src/run.c @@ -92,6 +92,7 @@ int init(void) else { fprintf(stderr, "WARNING: No running mode specified. " "Defaulting to statistics mode.\n"); + CONFIG(flags) |= CTD_STATS_MODE; STATE(mode) = &stats_mode; } diff --git a/src/sync-mode.c b/src/sync-mode.c index 3bd6f59..16642c2 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -132,6 +132,7 @@ static int init_sync(void) else { fprintf(stderr, "WARNING: No synchronization mode specified. " "Defaulting to FT-FW mode.\n"); + CONFIG(flags) |= CTD_SYNC_FTFW; STATE_SYNC(sync) = &ftfw; } -- cgit v1.2.3 From 6e5b6c91625fd431ac3d1339f55a4aa278ff2604 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Mon, 14 Jan 2008 15:22:24 +0000 Subject: improve alarm framework based on suggestions from Max Duempel --- ChangeLog | 1 + include/alarm.h | 7 +++++++ src/alarm.c | 33 ++++++++++++++++++--------------- src/cache_timer.c | 2 +- src/run.c | 15 ++++++++------- src/sync-alarm.c | 10 ++++++---- src/sync-ftfw.c | 4 ++-- 7 files changed, 43 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 6d4759a..c090831 100644 --- a/ChangeLog +++ b/ChangeLog @@ -38,6 +38,7 @@ o rename class `buffer' to `queue' which is what it really implements o fix logfiles permissions, do not default to umask o wake up the daemon iff there are real events to handle instead of polling o add support for tagged vlan interfaces in the config file, e.g. eth0.1 +o improve alarm framework based on suggestions from Max Duempel version 0.9.5 (2007/07/29) ------------------------------ diff --git a/include/alarm.h b/include/alarm.h index 82a1612..fbe34f6 100644 --- a/include/alarm.h +++ b/include/alarm.h @@ -10,4 +10,11 @@ struct alarm_list { void (*function)(struct alarm_list *a, void *data); }; +static inline void +set_alarm_expiration(struct alarm_list *t, long tv_sec, long tv_usec) +{ + t->tv.tv_sec = tv_sec; + t->tv.tv_usec = tv_usec; +} + #endif diff --git a/src/alarm.c b/src/alarm.c index e1d2e24..eb2226b 100644 --- a/src/alarm.c +++ b/src/alarm.c @@ -28,16 +28,6 @@ static LIST_HEAD(alarm_list); -void set_alarm_expiration_secs(struct alarm_list *t, unsigned long expires) -{ - t->tv.tv_sec = expires; -} - -void set_alarm_expiration_usecs(struct alarm_list *t, unsigned long expires) -{ - t->tv.tv_usec = expires; -} - void set_alarm_function(struct alarm_list *t, void (*fcn)(struct alarm_list *a, void *data)) { @@ -51,8 +41,6 @@ void set_alarm_data(struct alarm_list *t, void *data) void init_alarm(struct alarm_list *t) { - INIT_LIST_HEAD(&t->head); - timerclear(&t->tv); t->data = 0; t->function = NULL; @@ -77,14 +65,26 @@ void mod_alarm(struct alarm_list *alarm, unsigned long sc, unsigned long usc) struct timeval tv; list_del(&alarm->head); - INIT_LIST_HEAD(&alarm->head); gettimeofday(&tv, NULL); alarm->tv.tv_sec = tv.tv_sec + sc; alarm->tv.tv_usec = tv.tv_usec + usc; list_add_tail(&alarm->head, &alarm_list); } -void do_alarm_run(struct timeval *next_alarm) +int get_next_alarm(struct timeval *tv, struct timeval *next_alarm) +{ + struct list_head *i; + struct alarm_list *t; + + list_for_each(i, &alarm_list) { + t = (struct alarm_list *) i; + timersub(&t->tv, tv, next_alarm); + return 1; + } + return 0; +} + +int do_alarm_run(struct timeval *next_alarm) { struct list_head *i, *tmp; struct alarm_list *t; @@ -97,10 +97,13 @@ void do_alarm_run(struct timeval *next_alarm) if (timercmp(&t->tv, &tv, >)) { timersub(&t->tv, &tv, next_alarm); - break; + return 1; } del_alarm(t); t->function(t, t->data); } + + /* check for refreshed alarms to get the next one */ + return get_next_alarm(&tv, next_alarm); } diff --git a/src/cache_timer.c b/src/cache_timer.c index c0075f5..02f3ae4 100644 --- a/src/cache_timer.c +++ b/src/cache_timer.c @@ -36,7 +36,7 @@ static void timer_add(struct us_conntrack *u, void *data) struct alarm_list *alarm = data; init_alarm(alarm); - set_alarm_expiration_secs(alarm, CONFIG(cache_timeout)); + set_alarm_expiration(alarm, CONFIG(cache_timeout), 0); set_alarm_data(alarm, u); set_alarm_function(alarm, timeout); add_alarm(alarm); diff --git a/src/run.c b/src/run.c index eab3ad2..3481193 100644 --- a/src/run.c +++ b/src/run.c @@ -224,19 +224,20 @@ static int __run(struct timeval *next_alarm) void run(void) { - struct timeval next_alarm = { - .tv_sec = 1, - .tv_usec = 0 - }; + struct timeval next_alarm; struct timeval *next = &next_alarm; + struct timeval tv; - if (CONFIG(flags) & CTD_STATS_MODE) - next = NULL; + /* initialization: get the first alarm available */ + gettimeofday(&tv, NULL); + get_next_alarm(&tv, next); while(1) { if (__run(next)) { sigprocmask(SIG_BLOCK, &STATE(block), NULL); - do_alarm_run(next); + next = &next_alarm; + if (!do_alarm_run(next)) + next = NULL; /* no next alarms */ sigprocmask(SIG_UNBLOCK, &STATE(block), NULL); } } diff --git a/src/sync-alarm.c b/src/sync-alarm.c index 632eff2..3d20867 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -31,8 +31,9 @@ static void refresher(struct alarm_list *a, void *data) debug_ct(u->ct, "persistence update"); init_alarm(a); - set_alarm_expiration_secs(a, random() % CONFIG(refresh) + 1); - set_alarm_expiration_usecs(a, random() % 999999 + 1); + set_alarm_expiration(a, + random() % CONFIG(refresh) + 1, + random() % 999999 + 1); set_alarm_data(a, u); set_alarm_function(a, refresher); @@ -48,8 +49,9 @@ static void cache_alarm_add(struct us_conntrack *u, void *data) struct alarm_list *alarm = data; init_alarm(alarm); - set_alarm_expiration_secs(alarm, random() % CONFIG(refresh) + 1); - set_alarm_expiration_usecs(alarm, random() % 999999 + 1); + set_alarm_expiration(alarm, + random() % CONFIG(refresh) + 1, + random() % 999999 + 1); set_alarm_data(alarm, u); set_alarm_function(alarm, refresher); add_alarm(alarm); diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index ac1b8b6..125e82e 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -88,7 +88,7 @@ static void do_alive_alarm(struct alarm_list *a, void *data) tx_queue_add_ctlmsg(NET_F_ALIVE, 0, 0); init_alarm(&alive_alarm); - set_alarm_expiration_secs(&alive_alarm, 1); + set_alarm_expiration(&alive_alarm, 1, 0); set_alarm_function(&alive_alarm, do_alive_alarm); add_alarm(&alive_alarm); } @@ -112,7 +112,7 @@ static int ftfw_init() /* XXX: alive message expiration configurable */ init_alarm(&alive_alarm); - set_alarm_expiration_secs(&alive_alarm, 1); + set_alarm_expiration(&alive_alarm, 1, 0); set_alarm_function(&alive_alarm, do_alive_alarm); add_alarm(&alive_alarm); -- cgit v1.2.3 From a3f3fce1466938522e3ab8a722486ccf20333aa5 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Mon, 14 Jan 2008 16:56:58 +0000 Subject: make sure add_alarm() and mod_alarm() insert sorted by due time --- src/alarm.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/alarm.c b/src/alarm.c index eb2226b..6aac4a3 100644 --- a/src/alarm.c +++ b/src/alarm.c @@ -46,13 +46,29 @@ void init_alarm(struct alarm_list *t) t->function = NULL; } +void __add_alarm(struct alarm_list *alarm) +{ + struct list_head *i; + struct alarm_list *t; + + list_for_each(i, &alarm_list) { + t = (struct alarm_list *) i; + + if (timercmp(&alarm->tv, &t->tv, <)) { + list_add_tail(&alarm->head, &t->head); + return; + } + } + list_add_tail(&alarm->head, &alarm_list); +} + void add_alarm(struct alarm_list *alarm) { struct timeval tv; gettimeofday(&tv, NULL); alarm->tv.tv_sec += tv.tv_sec; - list_add_tail(&alarm->head, &alarm_list); + __add_alarm(alarm); } void del_alarm(struct alarm_list *alarm) @@ -68,7 +84,7 @@ void mod_alarm(struct alarm_list *alarm, unsigned long sc, unsigned long usc) gettimeofday(&tv, NULL); alarm->tv.tv_sec = tv.tv_sec + sc; alarm->tv.tv_usec = tv.tv_usec + usc; - list_add_tail(&alarm->head, &alarm_list); + __add_alarm(alarm); } int get_next_alarm(struct timeval *tv, struct timeval *next_alarm) -- cgit v1.2.3 From ddd1fd266a0732661fdfd6792dd4bbe70271b0f8 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Mon, 14 Jan 2008 17:16:04 +0000 Subject: fix overflow in usecs in mod_alarm() --- src/alarm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/alarm.c b/src/alarm.c index 6aac4a3..a64c37a 100644 --- a/src/alarm.c +++ b/src/alarm.c @@ -83,7 +83,7 @@ void mod_alarm(struct alarm_list *alarm, unsigned long sc, unsigned long usc) list_del(&alarm->head); gettimeofday(&tv, NULL); alarm->tv.tv_sec = tv.tv_sec + sc; - alarm->tv.tv_usec = tv.tv_usec + usc; + alarm->tv.tv_usec = usc; __add_alarm(alarm); } -- cgit v1.2.3 From 85617e012de1df43070bd4fba80ecce50dd87735 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Mon, 14 Jan 2008 17:56:58 +0000 Subject: fix broken next alarm calculation in the run loop --- src/run.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/run.c b/src/run.c index 3481193..8919b6c 100644 --- a/src/run.c +++ b/src/run.c @@ -230,7 +230,8 @@ void run(void) /* initialization: get the first alarm available */ gettimeofday(&tv, NULL); - get_next_alarm(&tv, next); + if (!get_next_alarm(&tv, next)) + next = NULL; while(1) { if (__run(next)) { -- cgit v1.2.3 From 4197eaf7b57056454cec3112683d84a3d0d7b194 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Tue, 15 Jan 2008 12:44:21 +0000 Subject: Max Kellermann : the global variable "alarm" conflicts with the alarm() function from unistd.h. resolve that conflict by giving those two global variables a better name. --- ChangeLog | 8 +++++++- include/sync.h | 4 ++-- src/sync-alarm.c | 2 +- src/sync-ftfw.c | 2 +- src/sync-mode.c | 6 +++--- 5 files changed, 14 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index c090831..27f48b2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,8 @@ version 0.9.6 (yet unreleased) ------------------------------ +Pablo Neira Ayuso : + o fix compilation problem due to missing headers (Krisztian Kovacs) o include kernel options and Fedora comments in the INSTALL file o remove -lpthread during compilation @@ -38,7 +40,11 @@ o rename class `buffer' to `queue' which is what it really implements o fix logfiles permissions, do not default to umask o wake up the daemon iff there are real events to handle instead of polling o add support for tagged vlan interfaces in the config file, e.g. eth0.1 -o improve alarm framework based on suggestions from Max Duempel +o improve alarm framework based on suggestions from Max Kellerman + +Max Kellermann : += conntrackd = +o resolve global variable "alarm" conflict with alarm() function in unistd.h. version 0.9.5 (2007/07/29) ------------------------------ diff --git a/include/sync.h b/include/sync.h index e6ce327..39e0f46 100644 --- a/include/sync.h +++ b/include/sync.h @@ -18,7 +18,7 @@ struct sync_mode { void (*run)(void); }; -extern struct sync_mode alarm; -extern struct sync_mode ftfw; +extern struct sync_mode sync_alarm; +extern struct sync_mode sync_ftfw; #endif diff --git a/src/sync-alarm.c b/src/sync-alarm.c index 3d20867..1dcfacd 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -106,7 +106,7 @@ static int alarm_recv(const struct nethdr *net) return 0; } -struct sync_mode alarm = { +struct sync_mode sync_alarm = { .internal_cache_flags = LIFETIME, .external_cache_flags = TIMER | LIFETIME, .internal_cache_extra = &cache_alarm_extra, diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 125e82e..23095c4 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -355,7 +355,7 @@ static void ftfw_run() mod_alarm(&alive_alarm, 1, 0); } -struct sync_mode ftfw = { +struct sync_mode sync_ftfw = { .internal_cache_flags = LIFETIME, .external_cache_flags = LIFETIME, .internal_cache_extra = &cache_ftfw_extra, diff --git a/src/sync-mode.c b/src/sync-mode.c index 16642c2..d38d91f 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -126,14 +126,14 @@ static int init_sync(void) memset(state.sync, 0, sizeof(struct ct_sync_state)); if (CONFIG(flags) & CTD_SYNC_FTFW) - STATE_SYNC(sync) = &ftfw; + STATE_SYNC(sync) = &sync_ftfw; else if (CONFIG(flags) & CTD_SYNC_ALARM) - STATE_SYNC(sync) = &alarm; + STATE_SYNC(sync) = &sync_alarm; else { fprintf(stderr, "WARNING: No synchronization mode specified. " "Defaulting to FT-FW mode.\n"); CONFIG(flags) |= CTD_SYNC_FTFW; - STATE_SYNC(sync) = &ftfw; + STATE_SYNC(sync) = &sync_ftfw; } if (STATE_SYNC(sync)->init) -- cgit v1.2.3 From 41f3e135db165fff931a07ef79e7731037d22941 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Tue, 15 Jan 2008 12:46:12 +0000 Subject: Max Kellermann : enable gcc warnings, including -Werror --- ChangeLog | 1 + Make_global.am | 5 +++++ src/Makefile.am | 3 +++ 3 files changed, 9 insertions(+) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 27f48b2..aea2a00 100644 --- a/ChangeLog +++ b/ChangeLog @@ -45,6 +45,7 @@ o improve alarm framework based on suggestions from Max Kellerman Max Kellermann : = conntrackd = o resolve global variable "alarm" conflict with alarm() function in unistd.h. +o enable gcc warnings, including -Werror version 0.9.5 (2007/07/29) ------------------------------ diff --git a/Make_global.am b/Make_global.am index 685add7..252abf9 100644 --- a/Make_global.am +++ b/Make_global.am @@ -1 +1,6 @@ INCLUDES=$(all_includes) -I$(top_srcdir)/include + +AM_CFLAGS = -W -Wall \ + -Werror \ + -Wmissing-prototypes -Wwrite-strings -Wcast-qual -Wfloat-equal -Wshadow -Wpointer-arith -Wbad-function-cast -Wsign-compare -Waggregate-return -Wmissing-declarations -Wredundant-decls -Wnested-externs -Winline -Wstrict-prototypes -Wundef \ + -Wno-unused-parameter diff --git a/src/Makefile.am b/src/Makefile.am index c2e684a..fafb5ff 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -22,6 +22,9 @@ conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c buffer.c \ build.c parse.c \ read_config_yy.y read_config_lex.l +# yacc and lex generate dirty code +read_config_yy.o read_config_lex.o: AM_CFLAGS += -Wno-missing-prototypes -Wno-missing-declarations -Wno-implicit-function-declaration -Wno-nested-externs -Wno-undef -Wno-redundant-decls + conntrackd_LDFLAGS = $(all_libraries) @LIBNETFILTER_CONNTRACK_LIBS@ EXTRA_DIST = read_config_yy.h -- cgit v1.2.3 From b861a707522e8625b4a5b4145b97a8825037572f Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Tue, 15 Jan 2008 12:50:37 +0000 Subject: Max Kellermann Use list_for_each_entry() instead of list_for_each() --- ChangeLog | 1 + src/alarm.c | 16 ++++------------ src/conntrack.c | 4 +--- src/sync-ftfw.c | 19 +++++++------------ 4 files changed, 13 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index aea2a00..dcbe694 100644 --- a/ChangeLog +++ b/ChangeLog @@ -46,6 +46,7 @@ Max Kellermann : = conntrackd = o resolve global variable "alarm" conflict with alarm() function in unistd.h. o enable gcc warnings, including -Werror +o use list_for_each_entry() instead of list_for_each() version 0.9.5 (2007/07/29) ------------------------------ diff --git a/src/alarm.c b/src/alarm.c index a64c37a..8d3ae48 100644 --- a/src/alarm.c +++ b/src/alarm.c @@ -48,12 +48,9 @@ void init_alarm(struct alarm_list *t) void __add_alarm(struct alarm_list *alarm) { - struct list_head *i; struct alarm_list *t; - list_for_each(i, &alarm_list) { - t = (struct alarm_list *) i; - + list_for_each_entry(t, &alarm_list, head) { if (timercmp(&alarm->tv, &t->tv, <)) { list_add_tail(&alarm->head, &t->head); return; @@ -89,11 +86,9 @@ void mod_alarm(struct alarm_list *alarm, unsigned long sc, unsigned long usc) int get_next_alarm(struct timeval *tv, struct timeval *next_alarm) { - struct list_head *i; struct alarm_list *t; - list_for_each(i, &alarm_list) { - t = (struct alarm_list *) i; + list_for_each_entry(t, &alarm_list, head) { timersub(&t->tv, tv, next_alarm); return 1; } @@ -102,15 +97,12 @@ int get_next_alarm(struct timeval *tv, struct timeval *next_alarm) int do_alarm_run(struct timeval *next_alarm) { - struct list_head *i, *tmp; - struct alarm_list *t; + struct alarm_list *t, *tmp; struct timeval tv; gettimeofday(&tv, NULL); - list_for_each_safe(i, tmp, &alarm_list) { - t = (struct alarm_list *) i; - + list_for_each_entry_safe(t, tmp, &alarm_list, head) { if (timercmp(&t->tv, &tv, >)) { timersub(&t->tv, &tv, next_alarm); return 1; diff --git a/src/conntrack.c b/src/conntrack.c index 20d86f9..4f5fd0b 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -161,14 +161,12 @@ void register_proto(struct ctproto_handler *h) static struct ctproto_handler *findproto(char *name) { - struct list_head *i; struct ctproto_handler *cur = NULL, *handler = NULL; if (!name) return handler; - list_for_each(i, &proto_list) { - cur = (struct ctproto_handler *) i; + list_for_each_entry(cur, &proto_list, head) { if (strcmp(cur->name, name) == 0) { handler = cur; break; diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 23095c4..8452e2e 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -185,11 +185,9 @@ static int rs_queue_empty(void *data1, void *data2) static void rs_list_to_tx(struct cache *c, unsigned int from, unsigned int to) { - struct list_head *n; - struct us_conntrack *u; + struct cache_ftfw *cn; - list_for_each(n, &rs_list) { - struct cache_ftfw *cn = (struct cache_ftfw *) n; + list_for_each_entry(cn, &rs_list, rs_list) { struct us_conntrack *u; u = cache_get_conntrack(STATE_SYNC(internal), cn); @@ -203,10 +201,9 @@ static void rs_list_to_tx(struct cache *c, unsigned int from, unsigned int to) static void rs_list_empty(struct cache *c, unsigned int from, unsigned int to) { - struct list_head *n, *tmp; + struct cache_ftfw *cn, *tmp; - list_for_each_safe(n, tmp, &rs_list) { - struct cache_ftfw *cn = (struct cache_ftfw *) n; + list_for_each_entry_safe(cn, tmp, &rs_list, rs_list) { struct us_conntrack *u; u = cache_get_conntrack(STATE_SYNC(internal), cn); @@ -337,19 +334,17 @@ static int tx_list_xmit(struct list_head *i, struct us_conntrack *u) static void ftfw_run() { - struct list_head *i, *tmp; + struct cache_ftfw *cn, *tmp; /* send messages in the tx_queue */ queue_iterate(tx_queue, NULL, tx_queue_xmit); /* send conntracks in the tx_list */ - list_for_each_safe(i, tmp, &tx_list) { - struct cache_ftfw *cn; + list_for_each_entry_safe(cn, tmp, &tx_list, tx_list) { struct us_conntrack *u; - cn = container_of(i, struct cache_ftfw, tx_list); u = cache_get_conntrack(STATE_SYNC(internal), cn); - tx_list_xmit(i, u); + tx_list_xmit(&cn->tx_list, u); } mod_alarm(&alive_alarm, 1, 0); -- cgit v1.2.3 From 17c3451c18389990d74936e79ee19a4aa15e97d0 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Tue, 15 Jan 2008 12:53:58 +0000 Subject: Max Kellermann : use const when possible --- ChangeLog | 1 + include/buffer.h | 2 +- include/cache.h | 2 +- include/hash.h | 2 +- include/queue.h | 2 +- src/buffer.c | 2 +- src/cache.c | 2 +- src/hash.c | 2 +- src/queue.c | 2 +- src/sync-ftfw.c | 4 ++-- 10 files changed, 11 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index dcbe694..e1330bb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -47,6 +47,7 @@ Max Kellermann : o resolve global variable "alarm" conflict with alarm() function in unistd.h. o enable gcc warnings, including -Werror o use list_for_each_entry() instead of list_for_each() +o use const when possible version 0.9.5 (2007/07/29) ------------------------------ diff --git a/include/buffer.h b/include/buffer.h index 5b854f3..aa753b4 100644 --- a/include/buffer.h +++ b/include/buffer.h @@ -13,6 +13,6 @@ void buffer_flush(struct buffer *b, void (*cb)(void *buffer_data, void *data), void *data); -unsigned int buffer_size(struct buffer *b); +unsigned int buffer_size(const struct buffer *b); #endif diff --git a/include/cache.h b/include/cache.h index f5e9576..5ca6ce4 100644 --- a/include/cache.h +++ b/include/cache.h @@ -83,7 +83,7 @@ struct us_conntrack *cache_update(struct cache *c, struct nf_conntrack *ct); struct us_conntrack *cache_update_force(struct cache *c, struct nf_conntrack *ct); int cache_del(struct cache *c, struct nf_conntrack *ct); int cache_test(struct cache *c, struct nf_conntrack *ct); -void cache_stats(struct cache *c, int fd); +void cache_stats(const struct cache *c, int fd); struct us_conntrack *cache_get_conntrack(struct cache *, void *); void *cache_get_extra(struct cache *, void *); void cache_iterate(struct cache *c, void *data, int (*iterate)(void *data1, void *data2)); diff --git a/include/hash.h b/include/hash.h index fd971e7..c9460fa 100644 --- a/include/hash.h +++ b/include/hash.h @@ -42,6 +42,6 @@ int hashtable_del(struct hashtable *table, void *data); int hashtable_flush(struct hashtable *table); int hashtable_iterate(struct hashtable *table, void *data, int (*iterate)(void *data1, void *data2)); -unsigned int hashtable_counter(struct hashtable *table); +unsigned int hashtable_counter(const struct hashtable *table); #endif diff --git a/include/queue.h b/include/queue.h index 691138f..f568da4 100644 --- a/include/queue.h +++ b/include/queue.h @@ -21,7 +21,7 @@ struct queue_node { struct queue *queue_create(size_t max_size); void queue_destroy(struct queue *b); -unsigned int queue_len(struct queue *b); +unsigned int queue_len(const struct queue *b); int queue_add(struct queue *b, const void *data, size_t size); void queue_del(struct queue *b, void *data); void queue_iterate(struct queue *b, diff --git a/src/buffer.c b/src/buffer.c index 3283c15..4f60123 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -61,7 +61,7 @@ void buffer_flush(struct buffer *b, memset(b->data, 0, b->size); } -unsigned int buffer_size(struct buffer *b) +unsigned int buffer_size(const struct buffer *b) { return b->size; } diff --git a/src/cache.c b/src/cache.c index b92957a..a0950d5 100644 --- a/src/cache.c +++ b/src/cache.c @@ -398,7 +398,7 @@ void *cache_get_extra(struct cache *c, void *data) return data + c->extra_offset; } -void cache_stats(struct cache *c, int fd) +void cache_stats(const struct cache *c, int fd) { char buf[512]; int size; diff --git a/src/hash.c b/src/hash.c index 274a140..3ed6ad2 100644 --- a/src/hash.c +++ b/src/hash.c @@ -193,7 +193,7 @@ int hashtable_iterate(struct hashtable *table, void *data, return 0; } -unsigned int hashtable_counter(struct hashtable *table) +unsigned int hashtable_counter(const struct hashtable *table) { return table->count; } diff --git a/src/queue.c b/src/queue.c index 3413013..e73d692 100644 --- a/src/queue.c +++ b/src/queue.c @@ -122,7 +122,7 @@ void queue_iterate(struct queue *b, } } -unsigned int queue_len(struct queue *b) +unsigned int queue_len(const struct queue *b) { return b->num_elems; } diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 8452e2e..0d57f36 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -161,7 +161,7 @@ static int ftfw_local(int fd, int type, void *data) static int rs_queue_to_tx(void *data1, void *data2) { struct nethdr *net = data1; - struct nethdr_ack *nack = data2; + const struct nethdr_ack *nack = data2; if (between(net->seq, nack->from, nack->to)) { dp("rs_queue_to_tx sq: %u fl:%u len:%u\n", @@ -174,7 +174,7 @@ static int rs_queue_to_tx(void *data1, void *data2) static int rs_queue_empty(void *data1, void *data2) { struct nethdr *net = data1; - struct nethdr_ack *h = data2; + const struct nethdr_ack *h = data2; if (between(net->seq, h->from, h->to)) { dp("remove from queue (seq=%u)\n", net->seq); -- cgit v1.2.3 From 4ddee9e2555817bd94521677e808caed665c3393 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Tue, 15 Jan 2008 12:59:27 +0000 Subject: Max Kellermann : yacc generates a function with a return value, and the conntrackd code uses "return;" to ignore a value. this is not legal. convert all of these to "break;" which might be what the author intended to do. --- ChangeLog | 1 + src/read_config_yy.y | 18 +++++++++--------- 2 files changed, 10 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 97ac77e..8da214c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -49,6 +49,7 @@ o enable gcc warnings, including -Werror o use list_for_each_entry() instead of list_for_each() o use const when possible o remove prefetch in slist.h since it confuses gcc +o fix illegal use of return in the yacc code, use break instead version 0.9.5 (2007/07/29) ------------------------------ diff --git a/src/read_config_yy.y b/src/read_config_yy.y index bbc5115..be484fe 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -121,7 +121,7 @@ syslog_facility : T_SYSLOG T_STRING else { fprintf(stderr, "'%s' is not a known syslog facility, " "ignoring.\n", $2); - return; + break; } if (conf.stats.syslog_facility != -1 && @@ -187,7 +187,7 @@ ignore_traffic_option : T_IPV4_ADDR T_IP if (!family) { fprintf(stderr, "%s is not a valid IP, ignoring", $2); - return; + break; } if (!STATE(ignore_pool)) { @@ -216,14 +216,14 @@ multicast_option : T_IPV4_ADDR T_IP { if (!inet_aton($2, &conf.mcast.in)) { fprintf(stderr, "%s is not a valid IPv4 address\n"); - return; + break; } if (conf.mcast.ipproto == AF_INET6) { fprintf(stderr, "Your multicast address is IPv4 but " "is binded to an IPv6 interface? Surely " "this is not what you want\n"); - return; + break; } conf.mcast.ipproto = AF_INET; @@ -240,7 +240,7 @@ multicast_option : T_IPV6_ADDR T_IP fprintf(stderr, "Your multicast address is IPv6 but " "is binded to an IPv4 interface? Surely " "this is not what you want\n"); - return; + break; } conf.mcast.ipproto = AF_INET6; @@ -250,14 +250,14 @@ multicast_option : T_IPV4_IFACE T_IP { if (!inet_aton($2, &conf.mcast.ifa)) { fprintf(stderr, "%s is not a valid IPv4 address\n"); - return; + break; } if (conf.mcast.ipproto == AF_INET6) { fprintf(stderr, "Your multicast interface is IPv4 but " "is binded to an IPv6 interface? Surely " "this is not what you want\n"); - return; + break; } conf.mcast.ipproto = AF_INET; @@ -274,7 +274,7 @@ multicast_option : T_IPV6_IFACE T_IP fprintf(stderr, "Your multicast interface is IPv6 but " "is binded to an IPv4 interface? Surely " "this is not what you want\n"); - return; + break; } conf.mcast.ipproto = AF_INET6; @@ -630,7 +630,7 @@ stat_syslog_facility : T_SYSLOG T_STRING else { fprintf(stderr, "'%s' is not a known syslog facility, " "ignoring.\n", $2); - return; + break; } if (conf.syslog_facility != -1 && -- cgit v1.2.3 From ba364998484de5a3ed37b843a8e34eacb2a21953 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Tue, 15 Jan 2008 13:01:46 +0000 Subject: Max Kellermann : fix shadow warnings by renaming variables or making them local --- ChangeLog | 3 +++ src/alarm.c | 1 - src/conntrack.c | 18 +++++++++--------- src/network.c | 12 ++++++------ src/state_helper.c | 4 ++-- src/state_helper_tcp.c | 4 ++-- 6 files changed, 22 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 8da214c..c9de1ed 100644 --- a/ChangeLog +++ b/ChangeLog @@ -43,6 +43,9 @@ o add support for tagged vlan interfaces in the config file, e.g. eth0.1 o improve alarm framework based on suggestions from Max Kellerman Max Kellermann : + +o fix shadow warnings by renaming variables or making them local + = conntrackd = o resolve global variable "alarm" conflict with alarm() function in unistd.h. o enable gcc warnings, including -Werror diff --git a/src/alarm.c b/src/alarm.c index 8d3ae48..2c65ef3 100644 --- a/src/alarm.c +++ b/src/alarm.c @@ -16,7 +16,6 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include #include #include "linux_list.h" diff --git a/src/conntrack.c b/src/conntrack.c index 4f5fd0b..28340c1 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -144,7 +144,6 @@ static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = static LIST_HEAD(proto_list); static unsigned int options; -static unsigned int command; #define CT_COMPARISON (CT_OPT_PROTO | CT_OPT_ORIG | CT_OPT_REPL | CT_OPT_MARK |\ CT_OPT_SECMARK) @@ -212,9 +211,9 @@ void exit_error(enum exittype status, char *msg, ...) } static void -generic_cmd_check(int command, int options) +generic_cmd_check(int command, int local_options) { - if (cmd_need_param[command] == 0 && !options) + if (cmd_need_param[command] == 0 && !local_options) exit_error(PARAMETER_PROBLEM, "You need to supply parameters to `-%c'\n", cmdflags[command]); @@ -231,7 +230,7 @@ static int bit2cmd(int command) return i; } -void generic_opt_check(int options, +void generic_opt_check(int local_options, int num_opts, char *optset, const char *optflg[]) @@ -239,7 +238,7 @@ void generic_opt_check(int options, int i; for (i = 0; i < num_opts; i++) { - if (!(options & (1<size; i++) - if (strncasecmp(str, p->parameter[i], strlen) == 0) { + if (strncasecmp(str, p->parameter[i], str_length) == 0) { *value |= p->value[i]; ret = 1; break; @@ -670,6 +669,7 @@ int main(int argc, char *argv[]) struct nf_expect *exp = (struct nf_expect *) __exp; int l3protonum; union ct_address ad; + unsigned int command; memset(__obj, 0, sizeof(__obj)); memset(__exptuple, 0, sizeof(__exptuple)); diff --git a/src/network.c b/src/network.c index a20c1e0..8f1dc94 100644 --- a/src/network.c +++ b/src/network.c @@ -96,12 +96,12 @@ static char *tx_buf; #define HEADERSIZ 28 /* IP header (20 bytes) + UDP header 8 (bytes) */ -int mcast_buffered_init(struct mcast_conf *conf) +int mcast_buffered_init(struct mcast_conf *mconf) { - int mtu = conf->mtu - HEADERSIZ; + int mtu = mconf->mtu - HEADERSIZ; /* default to Ethernet MTU 1500 bytes */ - if (conf->mtu == 0) + if (mconf->mtu == 0) mtu = 1500 - HEADERSIZ; tx_buf = malloc(mtu); @@ -199,12 +199,12 @@ int handle_netmsg(struct nethdr *net) int mcast_track_seq(u_int32_t seq, u_int32_t *exp_seq) { - static int seq_set = 0; + static int local_seq_set = 0; int ret = 1; /* netlink sequence tracking initialization */ - if (!seq_set) { - seq_set = 1; + if (!local_seq_set) { + local_seq_set = 1; goto out; } diff --git a/src/state_helper.c b/src/state_helper.c index eba9d8f..de4cf48 100644 --- a/src/state_helper.c +++ b/src/state_helper.c @@ -35,10 +35,10 @@ int state_helper_verdict(int type, struct nf_conntrack *ct) return ST_H_REPLICATE; } -void state_helper_register(struct state_replication_helper *h, int state) +void state_helper_register(struct state_replication_helper *h, int h_state) { if (helper[h->proto] == NULL) helper[h->proto] = h; - helper[h->proto]->state |= (1 << state); + helper[h->proto]->state |= (1 << h_state); } diff --git a/src/state_helper_tcp.c b/src/state_helper_tcp.c index af714dc..e0a51ee 100644 --- a/src/state_helper_tcp.c +++ b/src/state_helper_tcp.c @@ -22,8 +22,8 @@ static int tcp_verdict(const struct state_replication_helper *h, const struct nf_conntrack *ct) { - u_int8_t state = nfct_get_attr_u8(ct, ATTR_TCP_STATE); - if (h->state & (1 << state)) + u_int8_t t_state = nfct_get_attr_u8(ct, ATTR_TCP_STATE); + if (h->state & (1 << t_state)) return ST_H_REPLICATE; return ST_H_SKIP; -- cgit v1.2.3 From 369a532132e9c9f19e0dd07d2e2c554c92c70f67 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Tue, 15 Jan 2008 13:04:16 +0000 Subject: Max Kellermann : fix wrong invocations after prototype cleanup --- ChangeLog | 1 + src/cache_timer.c | 2 +- src/stats-mode.c | 2 +- src/sync-mode.c | 23 ++++++++++++----------- 4 files changed, 15 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index c9de1ed..158a7d2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -53,6 +53,7 @@ o use list_for_each_entry() instead of list_for_each() o use const when possible o remove prefetch in slist.h since it confuses gcc o fix illegal use of return in the yacc code, use break instead +o fix wrong invocations after prototype cleanup version 0.9.5 (2007/07/29) ------------------------------ diff --git a/src/cache_timer.c b/src/cache_timer.c index 02f3ae4..2379f4b 100644 --- a/src/cache_timer.c +++ b/src/cache_timer.c @@ -45,7 +45,7 @@ static void timer_add(struct us_conntrack *u, void *data) static void timer_update(struct us_conntrack *u, void *data) { struct alarm_list *alarm = data; - mod_alarm(alarm, CONFIG(cache_timeout)); + mod_alarm(alarm, CONFIG(cache_timeout), 0); } static void timer_destroy(struct us_conntrack *u, void *data) diff --git a/src/stats-mode.c b/src/stats-mode.c index 20efc95..de53751 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -84,7 +84,7 @@ static int local_handler_stats(int fd, int type, void *data) cache_flush(STATE_STATS(cache)); break; case KILL: - killer(); + killer(0); break; case STATS: cache_stats(STATE_STATS(cache), fd); diff --git a/src/sync-mode.c b/src/sync-mode.c index d38d91f..c3630b6 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -31,7 +31,7 @@ static void do_mcast_handler_step(struct nethdr *net) { - unsigned int query; + int query; struct netpld *pld = NETHDR_DATA(net); char __ct[nfct_maxsize()]; struct nf_conntrack *ct = (struct nf_conntrack *) __ct; @@ -82,7 +82,7 @@ retry: } /* handler for multicast messages received */ -static void mcast_handler() +static void mcast_handler(void) { int numbytes, remain; char __net[65536], *ptr = __net; /* XXX: maximum MTU for IPv4 */ @@ -116,8 +116,6 @@ static void mcast_handler() static int init_sync(void) { - int ret; - state.sync = malloc(sizeof(struct ct_sync_state)); if (!state.sync) { dlog(STATE(log), LOG_ERR, "can't allocate memory for sync"); @@ -212,7 +210,7 @@ static void run_sync(fd_set *readfds) mcast_buffered_pending_netmsg(STATE_SYNC(mcast_client)); } -static void kill_sync() +static void kill_sync(void) { cache_destroy(STATE_SYNC(internal)); cache_destroy(STATE_SYNC(external)); @@ -226,7 +224,7 @@ static void kill_sync() STATE_SYNC(sync)->kill(); } -static dump_stats_sync(int fd) +static void dump_stats_sync(int fd) { char buf[512]; int size; @@ -234,8 +232,8 @@ static dump_stats_sync(int fd) size = sprintf(buf, "multicast sequence tracking:\n" "%20llu Pckts mfrm " "%20llu Pckts lost\n\n", - STATE(malformed), - STATE_SYNC(packets_lost)); + (unsigned long long)STATE(malformed), + (unsigned long long)STATE_SYNC(packets_lost)); send(fd, buf, size, 0); } @@ -289,7 +287,7 @@ static int local_handler_sync(int fd, int type, void *data) cache_flush(STATE_SYNC(external)); break; case KILL: - killer(); + killer(0); break; case STATS: cache_stats(STATE_SYNC(internal), fd); @@ -403,7 +401,7 @@ static int overrun_purge_step(void *data1, void *data2) } /* it's likely that we're losing events, just try to do our best here */ -static void overrun_sync() +static void overrun_sync(void) { int ret; struct nfct_handle *h; @@ -481,8 +479,11 @@ static int event_destroy_sync(struct nf_conntrack *ct) if (cache_del(STATE_SYNC(internal), ct)) { mcast_send_sync(NULL, ct, NFCT_Q_DESTROY); debug_ct(ct, "internal destroy"); - } else + return 1; + } else { debug_ct(ct, "can't destroy"); + return 0; + } } struct ct_mode sync_mode = { -- cgit v1.2.3 From a944cf07400e78ac17f559dd41a670427648c258 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Tue, 15 Jan 2008 13:10:23 +0000 Subject: Max Kellermann : set the return type of the parse functions to "void" --- ChangeLog | 1 + src/alarm.c | 19 +++++-------------- src/cache_timer.c | 4 +--- src/parse.c | 10 +++++----- src/sync-alarm.c | 8 ++------ src/sync-ftfw.c | 6 ++---- 6 files changed, 16 insertions(+), 32 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 158a7d2..557ef83 100644 --- a/ChangeLog +++ b/ChangeLog @@ -54,6 +54,7 @@ o use const when possible o remove prefetch in slist.h since it confuses gcc o fix illegal use of return in the yacc code, use break instead o fix wrong invocations after prototype cleanup +o set the return type of the parse functions to "void" version 0.9.5 (2007/07/29) ------------------------------ diff --git a/src/alarm.c b/src/alarm.c index 2c65ef3..6edf68e 100644 --- a/src/alarm.c +++ b/src/alarm.c @@ -27,22 +27,13 @@ static LIST_HEAD(alarm_list); -void set_alarm_function(struct alarm_list *t, - void (*fcn)(struct alarm_list *a, void *data)) -{ - t->function = fcn; -} - -void set_alarm_data(struct alarm_list *t, void *data) -{ - t->data = data; -} - -void init_alarm(struct alarm_list *t) +void init_alarm(struct alarm_list *t, + void *data, + void (*fcn)(struct alarm_list *a, void *data)) { timerclear(&t->tv); - t->data = 0; - t->function = NULL; + t->data = data; + t->function = fcn; } void __add_alarm(struct alarm_list *alarm) diff --git a/src/cache_timer.c b/src/cache_timer.c index 2379f4b..8b4e4ea 100644 --- a/src/cache_timer.c +++ b/src/cache_timer.c @@ -35,10 +35,8 @@ static void timer_add(struct us_conntrack *u, void *data) { struct alarm_list *alarm = data; - init_alarm(alarm); + init_alarm(alarm, u, timeout); set_alarm_expiration(alarm, CONFIG(cache_timeout), 0); - set_alarm_data(alarm, u); - set_alarm_function(alarm, timeout); add_alarm(alarm); } diff --git a/src/parse.c b/src/parse.c index 0650995..c8a9704 100644 --- a/src/parse.c +++ b/src/parse.c @@ -20,27 +20,27 @@ #include #include "network.h" -static int parse_u8(struct nf_conntrack *ct, int attr, void *data) +static void parse_u8(struct nf_conntrack *ct, int attr, void *data) { u_int8_t *value = (u_int8_t *) data; nfct_set_attr_u8(ct, attr, *value); } -static int parse_u16(struct nf_conntrack *ct, int attr, void *data) +static void parse_u16(struct nf_conntrack *ct, int attr, void *data) { u_int16_t *value = (u_int16_t *) data; nfct_set_attr_u16(ct, attr, ntohs(*value)); } -static int parse_u32(struct nf_conntrack *ct, int attr, void *data) +static void parse_u32(struct nf_conntrack *ct, int attr, void *data) { u_int32_t *value = (u_int32_t *) data; nfct_set_attr_u32(ct, attr, ntohl(*value)); } -typedef int (*parse)(struct nf_conntrack *ct, int attr, void *data); +typedef void (*parse)(struct nf_conntrack *ct, int attr, void *data); -parse h[ATTR_MAX] = { +static parse h[ATTR_MAX] = { [ATTR_IPV4_SRC] = parse_u32, [ATTR_IPV4_DST] = parse_u32, [ATTR_L3PROTO] = parse_u8, diff --git a/src/sync-alarm.c b/src/sync-alarm.c index 1dcfacd..d9a8267 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -30,13 +30,11 @@ static void refresher(struct alarm_list *a, void *data) debug_ct(u->ct, "persistence update"); - init_alarm(a); + init_alarm(a, u, refresher); set_alarm_expiration(a, random() % CONFIG(refresh) + 1, random() % 999999 + 1); - set_alarm_data(a, u); - set_alarm_function(a, refresher); add_alarm(a); net = BUILD_NETMSG(u->ct, NFCT_Q_UPDATE); @@ -48,12 +46,10 @@ static void cache_alarm_add(struct us_conntrack *u, void *data) { struct alarm_list *alarm = data; - init_alarm(alarm); + init_alarm(alarm, u, refresher); set_alarm_expiration(alarm, random() % CONFIG(refresh) + 1, random() % 999999 + 1); - set_alarm_data(alarm, u); - set_alarm_function(alarm, refresher); add_alarm(alarm); } diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 0d57f36..63fd4b2 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -87,9 +87,8 @@ static void do_alive_alarm(struct alarm_list *a, void *data) { tx_queue_add_ctlmsg(NET_F_ALIVE, 0, 0); - init_alarm(&alive_alarm); + init_alarm(&alive_alarm, NULL, do_alive_alarm); set_alarm_expiration(&alive_alarm, 1, 0); - set_alarm_function(&alive_alarm, do_alive_alarm); add_alarm(&alive_alarm); } @@ -111,9 +110,8 @@ static int ftfw_init() INIT_LIST_HEAD(&rs_list); /* XXX: alive message expiration configurable */ - init_alarm(&alive_alarm); + init_alarm(&alive_alarm, NULL, do_alive_alarm); set_alarm_expiration(&alive_alarm, 1, 0); - set_alarm_function(&alive_alarm, do_alive_alarm); add_alarm(&alive_alarm); return 0; -- cgit v1.2.3 From f908987c2ad037b85ec611901b257ec675786cba Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Tue, 15 Jan 2008 13:21:44 +0000 Subject: constify queue_iterate() --- ChangeLog | 1 + include/queue.h | 2 +- src/queue.c | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 557ef83..6f6f890 100644 --- a/ChangeLog +++ b/ChangeLog @@ -41,6 +41,7 @@ o fix logfiles permissions, do not default to umask o wake up the daemon iff there are real events to handle instead of polling o add support for tagged vlan interfaces in the config file, e.g. eth0.1 o improve alarm framework based on suggestions from Max Kellerman +o constify queue_iterate() Max Kellermann : diff --git a/include/queue.h b/include/queue.h index f568da4..2e08e56 100644 --- a/include/queue.h +++ b/include/queue.h @@ -25,7 +25,7 @@ unsigned int queue_len(const struct queue *b); int queue_add(struct queue *b, const void *data, size_t size); void queue_del(struct queue *b, void *data); void queue_iterate(struct queue *b, - void *data, + const void *data, int (*iterate)(void *data1, void *data2)); #endif diff --git a/src/queue.c b/src/queue.c index e73d692..1c31157 100644 --- a/src/queue.c +++ b/src/queue.c @@ -109,7 +109,7 @@ void queue_del(struct queue *b, void *data) } void queue_iterate(struct queue *b, - void *data, + const void *data, int (*iterate)(void *data1, void *data2)) { struct list_head *i, *tmp; -- cgit v1.2.3 From 4e37e2d9079b4c1890a39f26e5082d6b1e7d0024 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Tue, 15 Jan 2008 13:39:46 +0000 Subject: Max Kellermann : add missing function prototypes --- ChangeLog | 1 + include/alarm.h | 17 +++++++++++++++++ include/conntrackd.h | 6 ++++++ include/ignore.h | 1 + include/network.h | 6 ++++++ src/cache_iterators.c | 1 + src/cache_wt.c | 1 + src/main.c | 4 ---- src/netlink.c | 4 ++++ src/network.c | 1 + src/run.c | 1 + src/stats-mode.c | 2 ++ src/sync-mode.c | 4 ++++ src/traffic_stats.c | 1 + 14 files changed, 46 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 8d95e48..d417dab 100644 --- a/ChangeLog +++ b/ChangeLog @@ -57,6 +57,7 @@ o fix illegal use of return in the yacc code, use break instead o fix wrong invocations after prototype cleanup o set the return type of the parse functions to "void" o use the comma operator instead of curly braces +o add missing function prototypes version 0.9.5 (2007/07/29) ------------------------------ diff --git a/include/alarm.h b/include/alarm.h index fbe34f6..c68e7f4 100644 --- a/include/alarm.h +++ b/include/alarm.h @@ -17,4 +17,21 @@ set_alarm_expiration(struct alarm_list *t, long tv_sec, long tv_usec) t->tv.tv_usec = tv_usec; } +void set_alarm_function(struct alarm_list *t, + void (*fcn)(struct alarm_list *a, void *data)); + +void set_alarm_data(struct alarm_list *t, void *data); + +void init_alarm(struct alarm_list *t); + +void add_alarm(struct alarm_list *alarm); + +void del_alarm(struct alarm_list *alarm); + +void mod_alarm(struct alarm_list *alarm, unsigned long sc, unsigned long usc); + +int get_next_alarm(struct timeval *tv, struct timeval *next_alarm); + +int do_alarm_run(struct timeval *next_alarm); + #endif diff --git a/include/conntrackd.h b/include/conntrackd.h index e8b90cc..33732a4 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -175,4 +175,10 @@ extern struct ct_mode stats_mode; #define MAX(x, y) x > y ? x : y +/* These live in run.c */ +void killer(int foo); +void local_handler(int fd, void *data); +int init(void); +void run(void); + #endif diff --git a/include/ignore.h b/include/ignore.h index 40cb02d..96deb93 100644 --- a/include/ignore.h +++ b/include/ignore.h @@ -8,5 +8,6 @@ struct ignore_pool { struct ignore_pool *ignore_pool_create(u_int8_t family); void ignore_pool_destroy(struct ignore_pool *ip); int ignore_pool_add(struct ignore_pool *ip, void *data); +int ignore_pool_test(struct ignore_pool *ip, struct nf_conntrack *ct); #endif diff --git a/include/network.h b/include/network.h index e92f6c3..88ff43b 100644 --- a/include/network.h +++ b/include/network.h @@ -54,6 +54,8 @@ void build_netmsg(struct nf_conntrack *ct, int query, struct nethdr *net); int prepare_send_netmsg(struct mcast_sock *m, void *data); int mcast_send_netmsg(struct mcast_sock *m, void *data); int mcast_recv_netmsg(struct mcast_sock *m, void *data, int len); +int handle_netmsg(struct nethdr *net); +int mcast_track_seq(u_int32_t seq, u_int32_t *exp_seq); struct mcast_conf; @@ -161,4 +163,8 @@ struct netattr { #define NTA_ALIGN(len) (((len) + NTA_ALIGNTO - 1) & ~(NTA_ALIGNTO - 1)) #define NTA_LENGTH(len) (NTA_ALIGN(sizeof(struct netattr)) + (len)) +void build_netpld(struct nf_conntrack *ct, struct netpld *pld, int query); + +void parse_netpld(struct nf_conntrack *ct, struct netpld *pld, int *query); + #endif diff --git a/src/cache_iterators.c b/src/cache_iterators.c index 85f87ab..d43ae6f 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -20,6 +20,7 @@ #include "jhash.h" #include "hash.h" #include "conntrackd.h" +#include "netlink.h" #include #include #include "us-conntrack.h" diff --git a/src/cache_wt.c b/src/cache_wt.c index 2a9d8e7..fee17e2 100644 --- a/src/cache_wt.c +++ b/src/cache_wt.c @@ -16,6 +16,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "netlink.h" #include #include "conntrackd.h" #include "us-conntrack.h" diff --git a/src/main.c b/src/main.c index 19d999a..2497a7f 100644 --- a/src/main.c +++ b/src/main.c @@ -61,10 +61,6 @@ void show_usage(char *progname) fprintf(stdout, "%s\n", usage_options); } -/* These live in run.c */ -int init(void); -void run(void); - void set_operation_mode(int *current, int want, char *argv[]) { if (*current == NOT_SET) { diff --git a/src/netlink.c b/src/netlink.c index ab945d8..7800b10 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -16,7 +16,11 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "netlink.h" #include "conntrackd.h" +#include "traffic_stats.h" +#include "ignore.h" +#include "log.h" #include #include #include diff --git a/src/network.c b/src/network.c index 8f1dc94..e7ffbac 100644 --- a/src/network.c +++ b/src/network.c @@ -20,6 +20,7 @@ #include "network.h" #include "us-conntrack.h" #include "sync.h" +#include "log.h" static unsigned int seq_set, cur_seq; diff --git a/src/run.c b/src/run.c index 8919b6c..7fbeaf5 100644 --- a/src/run.c +++ b/src/run.c @@ -19,6 +19,7 @@ */ #include "conntrackd.h" +#include "netlink.h" #include #include #include "us-conntrack.h" diff --git a/src/stats-mode.c b/src/stats-mode.c index de53751..0983b97 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "netlink.h" +#include "traffic_stats.h" #include #include "cache.h" #include "log.h" diff --git a/src/sync-mode.c b/src/sync-mode.c index c3630b6..8be8c18 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -16,6 +16,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "netlink.h" +#include "traffic_stats.h" +#include "log.h" #include #include "cache.h" #include "conntrackd.h" @@ -28,6 +31,7 @@ #include "sync.h" #include "network.h" #include "debug.h" +#include static void do_mcast_handler_step(struct nethdr *net) { diff --git a/src/traffic_stats.c b/src/traffic_stats.c index b510b77..b2cdaae 100644 --- a/src/traffic_stats.c +++ b/src/traffic_stats.c @@ -16,6 +16,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "traffic_stats.h" #include "cache.h" #include "hash.h" #include "conntrackd.h" -- cgit v1.2.3 From 07a1957516495a89e68baefd808f9db4eea03cd5 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Tue, 15 Jan 2008 13:48:57 +0000 Subject: Max Kellermann : use timeradd() since manipulating tv_sec directly --- ChangeLog | 1 + src/alarm.c | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 71f6a2f..06ccb5b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -42,6 +42,7 @@ o wake up the daemon iff there are real events to handle instead of polling o add support for tagged vlan interfaces in the config file, e.g. eth0.1 o improve alarm framework based on suggestions from Max Kellerman o constify queue_iterate() +o use timeradd() since manipulating tv_sec directly Max Kellermann : diff --git a/src/alarm.c b/src/alarm.c index 6edf68e..16e7a14 100644 --- a/src/alarm.c +++ b/src/alarm.c @@ -54,7 +54,7 @@ void add_alarm(struct alarm_list *alarm) struct timeval tv; gettimeofday(&tv, NULL); - alarm->tv.tv_sec += tv.tv_sec; + timeradd(&alarm->tv, &tv, &alarm->tv); __add_alarm(alarm); } @@ -68,9 +68,9 @@ void mod_alarm(struct alarm_list *alarm, unsigned long sc, unsigned long usc) struct timeval tv; list_del(&alarm->head); + set_alarm_expiration(alarm, sc, usc); gettimeofday(&tv, NULL); - alarm->tv.tv_sec = tv.tv_sec + sc; - alarm->tv.tv_usec = usc; + timeradd(&alarm->tv, &tv, &alarm->tv); __add_alarm(alarm); } -- cgit v1.2.3 From 7fcc1fdfaa157f8f8233f3ccbeb97bb7ea7637df Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Tue, 15 Jan 2008 13:50:41 +0000 Subject: Max Kellermann : use add_alarm() in mod_alarm() --- ChangeLog | 1 + src/alarm.c | 6 +----- 2 files changed, 2 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 06ccb5b..2c3c50f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -60,6 +60,7 @@ o set the return type of the parse functions to "void" o use the comma operator instead of curly braces o add missing function prototypes o merge several *_alarm() functions into init_alarm() +o use add_alarm() in mod_alarm() to avoid code duplication version 0.9.5 (2007/07/29) ------------------------------ diff --git a/src/alarm.c b/src/alarm.c index 16e7a14..3467e7b 100644 --- a/src/alarm.c +++ b/src/alarm.c @@ -65,13 +65,9 @@ void del_alarm(struct alarm_list *alarm) void mod_alarm(struct alarm_list *alarm, unsigned long sc, unsigned long usc) { - struct timeval tv; - list_del(&alarm->head); set_alarm_expiration(alarm, sc, usc); - gettimeofday(&tv, NULL); - timeradd(&alarm->tv, &tv, &alarm->tv); - __add_alarm(alarm); + add_alarm(alarm); } int get_next_alarm(struct timeval *tv, struct timeval *next_alarm) -- cgit v1.2.3 From 5fbcd3f99bca80fcada9345d5204349b28f988f7 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Tue, 15 Jan 2008 13:52:59 +0000 Subject: Max Kellermann : import tcp_state_helper only once --- ChangeLog | 1 + src/read_config_yy.y | 11 ++--------- 2 files changed, 3 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 2c3c50f..63fe5f5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -61,6 +61,7 @@ o use the comma operator instead of curly braces o add missing function prototypes o merge several *_alarm() functions into init_alarm() o use add_alarm() in mod_alarm() to avoid code duplication +o import tcp_state_helper only once version 0.9.5 (2007/07/29) ------------------------------ diff --git a/src/read_config_yy.y b/src/read_config_yy.y index be484fe..317b45a 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -27,6 +27,8 @@ #include "ignore.h" #include +extern struct state_replication_helper tcp_state_helper; + extern char *yytext; extern int yylineno; @@ -471,47 +473,38 @@ state: tcp_state; tcp_state: T_SYN_SENT { - extern struct state_replication_helper tcp_state_helper; state_helper_register(&tcp_state_helper, TCP_CONNTRACK_SYN_SENT); }; tcp_state: T_SYN_RECV { - extern struct state_replication_helper tcp_state_helper; state_helper_register(&tcp_state_helper, TCP_CONNTRACK_SYN_RECV); }; tcp_state: T_ESTABLISHED { - extern struct state_replication_helper tcp_state_helper; state_helper_register(&tcp_state_helper, TCP_CONNTRACK_ESTABLISHED); }; tcp_state: T_FIN_WAIT { - extern struct state_replication_helper tcp_state_helper; state_helper_register(&tcp_state_helper, TCP_CONNTRACK_FIN_WAIT); }; tcp_state: T_CLOSE_WAIT { - extern struct state_replication_helper tcp_state_helper; state_helper_register(&tcp_state_helper, TCP_CONNTRACK_CLOSE_WAIT); }; tcp_state: T_LAST_ACK { - extern struct state_replication_helper tcp_state_helper; state_helper_register(&tcp_state_helper, TCP_CONNTRACK_LAST_ACK); }; tcp_state: T_TIME_WAIT { - extern struct state_replication_helper tcp_state_helper; state_helper_register(&tcp_state_helper, TCP_CONNTRACK_TIME_WAIT); }; tcp_state: T_CLOSE { - extern struct state_replication_helper tcp_state_helper; state_helper_register(&tcp_state_helper, TCP_CONNTRACK_CLOSE); }; tcp_state: T_LISTEN { - extern struct state_replication_helper tcp_state_helper; state_helper_register(&tcp_state_helper, TCP_CONNTRACK_LISTEN); }; -- cgit v1.2.3 From a1728b3d5fd0b417941b7114de2fa9384ece5a35 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Tue, 15 Jan 2008 13:55:23 +0000 Subject: Max Kellermann : add missing printf arguments --- ChangeLog | 1 + src/read_config_yy.y | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 63fe5f5..6543aaf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -62,6 +62,7 @@ o add missing function prototypes o merge several *_alarm() functions into init_alarm() o use add_alarm() in mod_alarm() to avoid code duplication o import tcp_state_helper only once +o add missing printf arguments version 0.9.5 (2007/07/29) ------------------------------ diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 317b45a..8f8759f 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -217,7 +217,7 @@ multicast_options : multicast_option : T_IPV4_ADDR T_IP { if (!inet_aton($2, &conf.mcast.in)) { - fprintf(stderr, "%s is not a valid IPv4 address\n"); + fprintf(stderr, "%s is not a valid IPv4 address\n", $2); break; } @@ -251,7 +251,7 @@ multicast_option : T_IPV6_ADDR T_IP multicast_option : T_IPV4_IFACE T_IP { if (!inet_aton($2, &conf.mcast.ifa)) { - fprintf(stderr, "%s is not a valid IPv4 address\n"); + fprintf(stderr, "%s is not a valid IPv4 address\n", $2); break; } -- cgit v1.2.3 From 82290b2b0bd2ebb5539b61b98e993ae807c2e8d7 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Tue, 15 Jan 2008 14:00:14 +0000 Subject: Max Kellermann : Fix tons of gcc warnings --- ChangeLog | 3 ++- extensions/libct_proto_icmp.c | 2 +- extensions/libct_proto_tcp.c | 2 +- extensions/libct_proto_udp.c | 4 +--- include/cache.h | 2 +- include/conntrack.h | 8 ++++---- include/conntrackd.h | 4 ++++ include/debug.h | 4 ++-- include/linux_list.h | 2 +- include/log.h | 6 +++--- include/network.h | 2 +- src/alarm.c | 3 ++- src/buffer.c | 1 + src/cache.c | 28 ++++++++++++++------------- src/cache_iterators.c | 5 +++-- src/cache_lifetime.c | 2 ++ src/cache_timer.c | 2 +- src/cache_wt.c | 2 +- src/conntrack.c | 44 ++++++++++++++++++++++++++----------------- src/hash.c | 8 ++------ src/ignore_pool.c | 10 +++++++--- src/local.c | 2 +- src/log.c | 9 +++++---- src/main.c | 12 +++++++++--- src/mcast.c | 10 ++++++---- src/network.c | 5 ++--- src/read_config_yy.y | 2 +- src/run.c | 17 +++++++++++++---- src/stats-mode.c | 6 ++---- src/sync-alarm.c | 2 ++ src/sync-ftfw.c | 9 +++++---- src/sync-mode.c | 2 +- src/traffic_stats.c | 4 ++-- 33 files changed, 131 insertions(+), 93 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 6543aaf..f42234a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -42,7 +42,6 @@ o wake up the daemon iff there are real events to handle instead of polling o add support for tagged vlan interfaces in the config file, e.g. eth0.1 o improve alarm framework based on suggestions from Max Kellerman o constify queue_iterate() -o use timeradd() since manipulating tv_sec directly Max Kellermann : @@ -63,6 +62,8 @@ o merge several *_alarm() functions into init_alarm() o use add_alarm() in mod_alarm() to avoid code duplication o import tcp_state_helper only once o add missing printf arguments +o use timeradd() since manipulating tv_sec directly +o fix lots of gcc warnings version 0.9.5 (2007/07/29) ------------------------------ diff --git a/extensions/libct_proto_icmp.c b/extensions/libct_proto_icmp.c index 09fd8da..7c59072 100644 --- a/extensions/libct_proto_icmp.c +++ b/extensions/libct_proto_icmp.c @@ -51,7 +51,7 @@ static char icmp_commands_v_options[NUMBER_OF_CMD][ICMP_NUMBER_OF_OPT] = /*EXP_EVENT*/ {0,0,0}, }; -static void help() +static void help(void) { fprintf(stdout, " --icmp-type\t\t\ticmp type\n"); fprintf(stdout, " --icmp-code\t\t\ticmp code\n"); diff --git a/extensions/libct_proto_tcp.c b/extensions/libct_proto_tcp.c index 1f630b3..a3b1826 100644 --- a/extensions/libct_proto_tcp.c +++ b/extensions/libct_proto_tcp.c @@ -73,7 +73,7 @@ static const char *states[] = { "LISTEN" }; -static void help() +static void help(void) { fprintf(stdout, " --orig-port-src\t\toriginal source port\n"); fprintf(stdout, " --orig-port-dst\t\toriginal destination port\n"); diff --git a/extensions/libct_proto_udp.c b/extensions/libct_proto_udp.c index 2216b71..267e3d6 100644 --- a/extensions/libct_proto_udp.c +++ b/extensions/libct_proto_udp.c @@ -38,7 +38,7 @@ static const char *udp_optflags[UDP_NUMBER_OF_OPT] = { "mask-port-dst", "tuple-port-src", "tuple-port-dst" }; -static void help() +static void help(void) { fprintf(stdout, " --orig-port-src\t\toriginal source port\n"); fprintf(stdout, " --orig-port-dst\t\toriginal destination port\n"); @@ -166,8 +166,6 @@ static void final_check(unsigned int flags, unsigned int cmd, struct nf_conntrack *ct) { - int ret = 0; - if ((flags & (UDP_ORIG_SPORT|UDP_ORIG_DPORT)) && !(flags & (UDP_REPL_SPORT|UDP_REPL_DPORT))) { nfct_set_attr_u16(ct, diff --git a/include/cache.h b/include/cache.h index 5ca6ce4..e4fb945 100644 --- a/include/cache.h +++ b/include/cache.h @@ -75,7 +75,7 @@ struct cache_extra { struct nf_conntrack; -struct cache *cache_create(char *name, unsigned int features, u_int8_t proto, struct cache_extra *extra); +struct cache *cache_create(const char *name, unsigned int features, u_int8_t proto, struct cache_extra *extra); void cache_destroy(struct cache *e); struct us_conntrack *cache_add(struct cache *c, struct nf_conntrack *ct); diff --git a/include/conntrack.h b/include/conntrack.h index 1b2581e..8f2b6a2 100644 --- a/include/conntrack.h +++ b/include/conntrack.h @@ -148,9 +148,9 @@ enum { struct ctproto_handler { struct list_head head; - char *name; + const char *name; u_int16_t protonum; - char *version; + const char *version; enum ctattr_protoinfo protoinfo_attr; @@ -164,7 +164,7 @@ struct ctproto_handler { unsigned int command, struct nf_conntrack *ct); - void (*help)(); + void (*help)(void); struct option *opts; @@ -181,7 +181,7 @@ void generic_opt_check(int options, int nops, char *optset, const char *optflg[]); -void exit_error(enum exittype status, char *msg, ...); +void exit_error(enum exittype status, const char *msg, ...); extern void register_proto(struct ctproto_handler *h); diff --git a/include/conntrackd.h b/include/conntrackd.h index 33732a4..d3f66ba 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -181,4 +181,8 @@ void local_handler(int fd, void *data); int init(void); void run(void); +/* from read_config_yy.c */ +int +init_config(char *filename); + #endif diff --git a/include/debug.h b/include/debug.h index 1ffd9ac..f205983 100644 --- a/include/debug.h +++ b/include/debug.h @@ -14,8 +14,8 @@ }) #define debug printf #else -#define debug_ct(ct, msg) -#define debug +#define debug_ct(ct, msg) do {} while (0) +#define debug(...) do {} while (0) #endif #endif diff --git a/include/linux_list.h b/include/linux_list.h index 57b56d7..b84b1c4 100644 --- a/include/linux_list.h +++ b/include/linux_list.h @@ -13,7 +13,7 @@ * */ #define container_of(ptr, type, member) ({ \ - const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );}) /* diff --git a/include/log.h b/include/log.h index b5bbddb..64bf1ce 100644 --- a/include/log.h +++ b/include/log.h @@ -6,10 +6,10 @@ struct buffer; struct nf_conntrack; -int init_log(); -void dlog(FILE *fd, int priority, char *format, ...); +int init_log(void); +void dlog(FILE *fd, int priority, const char *format, ...); void dlog_buffered_ct(FILE *fd, struct buffer *b, struct nf_conntrack *ct); void dlog_buffered_ct_flush(void *buffer_data, void *data); -void close_log(); +void close_log(void); #endif diff --git a/include/network.h b/include/network.h index 88ff43b..d0b639b 100644 --- a/include/network.h +++ b/include/network.h @@ -60,7 +60,7 @@ int mcast_track_seq(u_int32_t seq, u_int32_t *exp_seq); struct mcast_conf; int mcast_buffered_init(struct mcast_conf *conf); -void mcast_buffered_destroy(); +void mcast_buffered_destroy(void); int mcast_buffered_send_netmsg(struct mcast_sock *m, void *data, int len); int mcast_buffered_pending_netmsg(struct mcast_sock *m); diff --git a/src/alarm.c b/src/alarm.c index 3467e7b..25075ef 100644 --- a/src/alarm.c +++ b/src/alarm.c @@ -36,7 +36,8 @@ void init_alarm(struct alarm_list *t, t->function = fcn; } -void __add_alarm(struct alarm_list *alarm) +static void +__add_alarm(struct alarm_list *alarm) { struct alarm_list *t; diff --git a/src/buffer.c b/src/buffer.c index 4f60123..79266a7 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -50,6 +50,7 @@ int buffer_add(struct buffer *b, void *data, unsigned int size) memcpy(b->data + b->cur_size, data, size); b->cur_size += size; + return 0; } void buffer_flush(struct buffer *b, diff --git a/src/cache.c b/src/cache.c index a0950d5..c5afb00 100644 --- a/src/cache.c +++ b/src/cache.c @@ -23,6 +23,7 @@ #include #include "us-conntrack.h" #include "cache.h" +#include static u_int32_t hash(const void *data, struct hashtable *table) { @@ -120,7 +121,7 @@ struct cache_feature *cache_feature[CACHE_MAX_FEATURE] = { [WRITE_THROUGH_FEATURE] = &writethrough_feature, }; -struct cache *cache_create(char *name, +struct cache *cache_create(const char *name, unsigned int features, u_int8_t proto, struct cache_extra *extra) @@ -209,7 +210,7 @@ void cache_destroy(struct cache *c) static struct us_conntrack *__add(struct cache *c, struct nf_conntrack *ct) { - int i; + unsigned i; size_t size = c->h->datasize; char buf[size]; struct us_conntrack *u = (struct us_conntrack *) buf; @@ -226,7 +227,7 @@ static struct us_conntrack *__add(struct cache *c, struct nf_conntrack *ct) u = hashtable_add(c->h, u); if (u) { - void *data = u->data; + char *data = u->data; for (i = 0; i < c->num_features; i++) { c->features[i]->add(u, data); @@ -234,7 +235,7 @@ static struct us_conntrack *__add(struct cache *c, struct nf_conntrack *ct) } if (c->extra && c->extra->add) - c->extra->add(u, ((void *) u) + c->extra_offset); + c->extra->add(u, ((char *) u) + c->extra_offset); return u; } @@ -268,8 +269,8 @@ static struct us_conntrack *__update(struct cache *c, struct nf_conntrack *ct) u = (struct us_conntrack *) hashtable_test(c->h, u); if (u) { - int i; - void *data = u->data; + unsigned i; + char *data = u->data; if (nfct_attr_is_set(ct, ATTR_STATUS)) nfct_set_attr_u32(u->ct, ATTR_STATUS, @@ -287,14 +288,15 @@ static struct us_conntrack *__update(struct cache *c, struct nf_conntrack *ct) } if (c->extra && c->extra->update) - c->extra->update(u, ((void *) u) + c->extra_offset); + c->extra->update(u, ((char *) u) + c->extra_offset); return u; } return NULL; } -struct us_conntrack *__cache_update(struct cache *c, struct nf_conntrack *ct) +static struct us_conntrack * +__cache_update(struct cache *c, struct nf_conntrack *ct) { struct us_conntrack *u; @@ -358,8 +360,8 @@ static int __del(struct cache *c, struct nf_conntrack *ct) u = (struct us_conntrack *) hashtable_test(c->h, u); if (u) { - int i; - void *data = u->data; + unsigned i; + char *data = u->data; struct nf_conntrack *p = u->ct; for (i = 0; i < c->num_features; i++) { @@ -368,7 +370,7 @@ static int __del(struct cache *c, struct nf_conntrack *ct) } if (c->extra && c->extra->destroy) - c->extra->destroy(u, ((void *) u) + c->extra_offset); + c->extra->destroy(u, ((char *) u) + c->extra_offset); hashtable_del(c->h, u); free(p); @@ -390,12 +392,12 @@ int cache_del(struct cache *c, struct nf_conntrack *ct) struct us_conntrack *cache_get_conntrack(struct cache *c, void *data) { - return data - c->extra_offset; + return (struct us_conntrack *)((char*)data - c->extra_offset); } void *cache_get_extra(struct cache *c, void *data) { - return data + c->extra_offset; + return (char*)data + c->extra_offset; } void cache_stats(const struct cache *c, int fd) diff --git a/src/cache_iterators.c b/src/cache_iterators.c index d43ae6f..4fdb920 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -19,6 +19,7 @@ #include "cache.h" #include "jhash.h" #include "hash.h" +#include "log.h" #include "conntrackd.h" #include "netlink.h" #include @@ -36,8 +37,8 @@ static int do_dump(void *data1, void *data2) int size; struct __dump_container *container = data1; struct us_conntrack *u = data2; - void *data = u->data; - int i; + char *data = u->data; + unsigned i; memset(buf, 0, sizeof(buf)); size = nfct_snprintf(buf, diff --git a/src/cache_lifetime.c b/src/cache_lifetime.c index ae54df2..26496d2 100644 --- a/src/cache_lifetime.c +++ b/src/cache_lifetime.c @@ -21,6 +21,8 @@ #include "us-conntrack.h" #include "cache.h" #include "alarm.h" +#include +#include static void lifetime_add(struct us_conntrack *u, void *data) { diff --git a/src/cache_timer.c b/src/cache_timer.c index 8b4e4ea..53ed703 100644 --- a/src/cache_timer.c +++ b/src/cache_timer.c @@ -62,7 +62,7 @@ static int timer_dump(struct us_conntrack *u, void *data, char *buf, int type) gettimeofday(&tv, NULL); timersub(&tv, &alarm->tv, &tmp); - return sprintf(buf, " [expires in %ds]", tmp.tv_sec); + return sprintf(buf, " [expires in %lds]", tmp.tv_sec); } struct cache_feature timer_feature = { diff --git a/src/cache_wt.c b/src/cache_wt.c index fee17e2..9d0af0b 100644 --- a/src/cache_wt.c +++ b/src/cache_wt.c @@ -25,7 +25,7 @@ static void add_update(struct us_conntrack *u) { char __ct[nfct_maxsize()]; - struct nf_conntrack *ct = (struct nf_conntrack *) __ct; + struct nf_conntrack *ct = (struct nf_conntrack *)(void*) __ct; memcpy(ct, u->ct, nfct_maxsize()); diff --git a/src/conntrack.c b/src/conntrack.c index 28340c1..f301a82 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -45,6 +45,8 @@ #include #include #include +#include +#include #ifdef HAVE_ARPA_INET_H #include #endif @@ -175,14 +177,15 @@ static struct ctproto_handler *findproto(char *name) return handler; } -void extension_help(struct ctproto_handler *h) +static void +extension_help(struct ctproto_handler *h) { fprintf(stdout, "\n"); fprintf(stdout, "Proto `%s' help:\n", h->name); h->help(); } -void +static void __attribute__((noreturn)) exit_tryhelp(int status) { fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n", @@ -190,7 +193,8 @@ exit_tryhelp(int status) exit(status); } -void exit_error(enum exittype status, char *msg, ...) +void __attribute__((noreturn)) +exit_error(enum exittype status, const char *msg, ...) { va_list args; @@ -281,7 +285,7 @@ merge_options(struct option *oldopts, const struct option *newopts, #define ENOTSUPP 524 /* Operation is not supported */ /* Translates errno numbers into more human-readable form than strerror. */ -const char * +static const char * err2str(int err, enum action command) { unsigned int i; @@ -318,7 +322,7 @@ err2str(int err, enum action command) #define PARSE_MAX 3 static struct parse_parameter { - char *parameter[6]; + const char *parameter[6]; size_t size; unsigned int value[6]; } parse_array[PARSE_MAX] = { @@ -336,7 +340,8 @@ static int do_parse_parameter(const char *str, size_t str_length, unsigned int *value, int parse_type) { - int i, ret = 0; + size_t i; + int ret = 0; struct parse_parameter *p = &parse_array[parse_type]; if (strncasecmp(str, "SRC_NAT", str_length) == 0) { @@ -384,7 +389,8 @@ add_command(unsigned int *cmd, const int newcmd, const int othercmds) *cmd |= newcmd; } -unsigned int check_type(int argc, char *argv[]) +static unsigned int +check_type(int argc, char *argv[]) { char *table = NULL; @@ -424,7 +430,8 @@ struct addr_parse { unsigned int family; }; -int parse_inetaddr(const char *cp, struct addr_parse *parse) +static int +parse_inetaddr(const char *cp, struct addr_parse *parse) { if (inet_aton(cp, &parse->addr)) return AF_INET; @@ -441,7 +448,8 @@ union ct_address { u_int32_t v6[4]; }; -int parse_addr(const char *cp, union ct_address *address) +static int +parse_addr(const char *cp, union ct_address *address) { struct addr_parse parse; int ret; @@ -458,7 +466,7 @@ int parse_addr(const char *cp, union ct_address *address) static void nat_parse(char *arg, int portok, struct nf_conntrack *obj, int type) { - char *colon, *dash, *error; + char *colon, *error; union ct_address parse; colon = strchr(arg, ':'); @@ -495,7 +503,8 @@ nat_parse(char *arg, int portok, struct nf_conntrack *obj, int type) nfct_set_attr_u32(obj, ATTR_DNAT_IPV4, parse.v4); } -static void event_sighandler(int s) +static void __attribute__((noreturn)) +event_sighandler(int s) { fprintf(stdout, "Now closing conntrack event dumping...\n"); nfct_close(cth); @@ -524,7 +533,6 @@ static const char usage_conntrack_parameters[] = " -e, --event-mask eventmask\t\tEvent mask, eg. NEW,DESTROY\n" " -z, --zero \t\t\t\tZero counters while listing\n" " -o, --output type[,...]\t\tOutput format, eg. xml\n"; - ; static const char usage_expectation_parameters[] = "Expectation parameters and options:\n" @@ -546,7 +554,9 @@ static const char usage_parameters[] = ; -void usage(char *prog) { +static void +usage(char *prog) +{ fprintf(stdout, "Command line interface for the connection " "tracking system. Version %s\n", VERSION); fprintf(stdout, "Usage: %s [commands] [options]\n", prog); @@ -662,11 +672,11 @@ int main(int argc, char *argv[]) char __obj[nfct_maxsize()]; char __exptuple[nfct_maxsize()]; char __mask[nfct_maxsize()]; - struct nf_conntrack *obj = (struct nf_conntrack *) __obj; - struct nf_conntrack *exptuple = (struct nf_conntrack *) __exptuple; - struct nf_conntrack *mask = (struct nf_conntrack *) __mask; + struct nf_conntrack *obj = (struct nf_conntrack *)(void*) __obj; + struct nf_conntrack *exptuple = (struct nf_conntrack *)(void*) __exptuple; + struct nf_conntrack *mask = (struct nf_conntrack *)(void*) __mask; char __exp[nfexp_maxsize()]; - struct nf_expect *exp = (struct nf_expect *) __exp; + struct nf_expect *exp = (struct nf_expect *)(void*) __exp; int l3protonum; union ct_address ad; unsigned int command; diff --git a/src/hash.c b/src/hash.c index 3ed6ad2..553dd1d 100644 --- a/src/hash.c +++ b/src/hash.c @@ -53,7 +53,6 @@ hashtable_create(int hashsize, int limit, int datasize, { int i; struct hashtable *h; - struct hashtype *t; int size = sizeof(struct hashtable) + hashsize * sizeof(struct slist_head); @@ -87,7 +86,6 @@ void *hashtable_add(struct hashtable *table, void *data) struct slist_head *e; struct hashtable_node *n; u_int32_t id; - int i; /* hash table is full */ if (table->count >= table->limit) { @@ -122,7 +120,6 @@ void *hashtable_test(struct hashtable *table, const void *data) struct slist_head *e; u_int32_t id; struct hashtable_node *n; - int i; id = table->hash(data, table); @@ -141,7 +138,6 @@ int hashtable_del(struct hashtable *table, void *data) struct slist_head *e, *next, *prev; u_int32_t id; struct hashtable_node *n; - int i; id = table->hash(data, table); @@ -160,7 +156,7 @@ int hashtable_del(struct hashtable *table, void *data) int hashtable_flush(struct hashtable *table) { - int i; + u_int32_t i; struct slist_head *e, *next, *prev; struct hashtable_node *n; @@ -179,7 +175,7 @@ int hashtable_flush(struct hashtable *table) int hashtable_iterate(struct hashtable *table, void *data, int (*iterate)(void *data1, void *data2)) { - int i; + u_int32_t i; struct slist_head *e, *next, *prev; struct hashtable_node *n; diff --git a/src/ignore_pool.c b/src/ignore_pool.c index ee457ba..82afa93 100644 --- a/src/ignore_pool.c +++ b/src/ignore_pool.c @@ -20,8 +20,11 @@ #include "hash.h" #include "conntrackd.h" #include "ignore.h" +#include "log.h" #include +#include + /* XXX: These should be configurable */ #define IGNORE_POOL_SIZE 128 #define IGNORE_POOL_LIMIT INT_MAX @@ -53,7 +56,6 @@ static int compare6(const void *data1, const void *data2) struct ignore_pool *ignore_pool_create(u_int8_t proto) { - int i, j = 0; struct ignore_pool *ip; ip = malloc(sizeof(struct ignore_pool)); @@ -100,7 +102,8 @@ int ignore_pool_add(struct ignore_pool *ip, void *data) return 1; } -int __ignore_pool_test_ipv4(struct ignore_pool *ip, struct nf_conntrack *ct) +static int +__ignore_pool_test_ipv4(struct ignore_pool *ip, struct nf_conntrack *ct) { return (hashtable_test(ip->h, nfct_get_attr(ct, ATTR_ORIG_IPV4_SRC)) || hashtable_test(ip->h, nfct_get_attr(ct, ATTR_ORIG_IPV4_DST)) || @@ -108,7 +111,8 @@ int __ignore_pool_test_ipv4(struct ignore_pool *ip, struct nf_conntrack *ct) hashtable_test(ip->h, nfct_get_attr(ct, ATTR_REPL_IPV4_DST))); } -int __ignore_pool_test_ipv6(struct ignore_pool *ip, struct nf_conntrack *ct) +static int +__ignore_pool_test_ipv6(struct ignore_pool *ip, struct nf_conntrack *ct) { return (hashtable_test(ip->h, nfct_get_attr(ct, ATTR_ORIG_IPV6_SRC)) || hashtable_test(ip->h, nfct_get_attr(ct, ATTR_ORIG_IPV6_DST)) || diff --git a/src/local.c b/src/local.c index be51b9e..9ff5f82 100644 --- a/src/local.c +++ b/src/local.c @@ -68,7 +68,7 @@ int do_local_server_step(int fd, void *data, { int rfd; struct sockaddr_un local; - size_t sin_size = sizeof(struct sockaddr_un); + socklen_t sin_size = sizeof(struct sockaddr_un); if ((rfd = accept(fd, (struct sockaddr *)&local, &sin_size)) == -1) return -1; diff --git a/src/log.c b/src/log.c index 51109b6..b42e049 100644 --- a/src/log.c +++ b/src/log.c @@ -18,7 +18,7 @@ * Description: Logging support for the conntrack daemon */ -#include +#include "log.h" #include #include #include @@ -26,6 +26,7 @@ #include #include #include +#include #include "buffer.h" #include "conntrackd.h" @@ -78,11 +79,11 @@ int init_log(void) return 0; } -void dlog(FILE *fd, int priority, char *format, ...) +void dlog(FILE *fd, int priority, const char *format, ...) { time_t t; char *buf; - char *prio; + const char *prio; va_list args; if (fd) { @@ -125,7 +126,7 @@ void dlog_buffered_ct_flush(void *buffer_data, void *data) { FILE *fd = data; - fprintf(fd, "%s", buffer_data); + fprintf(fd, "%s", (const char*)buffer_data); fflush(fd); } diff --git a/src/main.c b/src/main.c index 2497a7f..11974ff 100644 --- a/src/main.c +++ b/src/main.c @@ -28,6 +28,9 @@ #include "hash.h" #include "jhash.h" +#undef _POSIX_SOURCE +#include + struct ct_general_state st; union ct_state state; @@ -52,7 +55,8 @@ static const char usage_options[] = "Options:\n" " -C [configfile], configuration file path\n"; -void show_usage(char *progname) +static void +show_usage(char *progname) { fprintf(stdout, "Connection tracking userspace daemon v%s\n", VERSION); fprintf(stdout, "Usage: %s [commands] [options]\n\n", progname); @@ -61,7 +65,8 @@ void show_usage(char *progname) fprintf(stdout, "%s\n", usage_options); } -void set_operation_mode(int *current, int want, char *argv[]) +static void +set_operation_mode(int *current, int want, char *argv[]) { if (*current == NOT_SET) { *current = want; @@ -109,7 +114,7 @@ static int check_capabilities(void) int main(int argc, char *argv[]) { - int ret, i, config_set = 0, action; + int ret, i, config_set = 0, action = -1; char config_file[PATH_MAX]; int type = 0; struct utsname u; @@ -305,4 +310,5 @@ int main(int argc, char *argv[]) * run main process */ run(); + return 0; } diff --git a/src/mcast.c b/src/mcast.c index cdaed5f..cf03593 100644 --- a/src/mcast.c +++ b/src/mcast.c @@ -192,7 +192,6 @@ __mcast_client_create_ipv6(struct mcast_sock *m, struct mcast_conf *conf) struct mcast_sock *mcast_client_create(struct mcast_conf *conf) { int ret = 0; - struct sockaddr_in addr; struct mcast_sock *m; m = (struct mcast_sock *) malloc(sizeof(struct mcast_sock)); @@ -300,9 +299,12 @@ void mcast_dump_stats(int fd, struct mcast_sock *s, struct mcast_sock *r) "%20llu Pckts recv\n" "%20llu Error send " "%20llu Error recv\n\n", - s->stats.bytes, r->stats.bytes, - s->stats.messages, r->stats.messages, - s->stats.error, r->stats.error); + (unsigned long long)s->stats.bytes, + (unsigned long long)r->stats.bytes, + (unsigned long long)s->stats.messages, + (unsigned long long)r->stats.messages, + (unsigned long long)s->stats.error, + (unsigned long long)r->stats.error); send(fd, buf, size, 0); } diff --git a/src/network.c b/src/network.c index e7ffbac..9d6e6e1 100644 --- a/src/network.c +++ b/src/network.c @@ -22,6 +22,8 @@ #include "sync.h" #include "log.h" +#include + static unsigned int seq_set, cur_seq; static int __do_send(struct mcast_sock *m, void *data, int len) @@ -65,8 +67,6 @@ static int __do_prepare(struct mcast_sock *m, void *data, int len) static int __prepare_ctl(struct mcast_sock *m, void *data) { - struct nethdr_ack *nack = (struct nethdr_ack *) data; - return __do_prepare(m, data, NETHDR_ACK_SIZ); } @@ -172,7 +172,6 @@ void build_netmsg(struct nf_conntrack *ct, int query, struct nethdr *net) int handle_netmsg(struct nethdr *net) { - int ret; struct netpld *pld = NETHDR_DATA(net); /* message too small: no room for the header */ diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 8f8759f..82131d7 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -639,7 +639,7 @@ buffer_size: T_STAT_BUFFER_SIZE T_NUMBER %% -int +int __attribute__((noreturn)) yyerror(char *msg) { fprintf(stderr, "Error parsing config file: "); diff --git a/src/run.c b/src/run.c index 7fbeaf5..3fd98cd 100644 --- a/src/run.c +++ b/src/run.c @@ -20,12 +20,19 @@ #include "conntrackd.h" #include "netlink.h" +#include "ignore.h" +#include "log.h" +#include "alarm.h" #include #include #include "us-conntrack.h" #include #include #include +#include +#include +#include +#include void killer(int foo) { @@ -84,7 +91,8 @@ void local_handler(int fd, void *data) dlog(STATE(log), LOG_WARNING, "unknown local request %d", type); } -int init(void) +int +init(void) { if (CONFIG(flags) & CTD_STATS_MODE) STATE(mode) = &stats_mode; @@ -164,11 +172,11 @@ static int __run(struct timeval *next_alarm) if (ret == -1) { /* interrupted syscall, retry */ if (errno == EINTR) - return; + return 0; dlog(STATE(log), LOG_WARNING, "select failed: %s", strerror(errno)); - return; + return 0; } /* timeout expired, run the alarm list */ @@ -223,7 +231,8 @@ static int __run(struct timeval *next_alarm) return 0; } -void run(void) +void __attribute__((noreturn)) +run(void) { struct timeval next_alarm; struct timeval *next = &next_alarm; diff --git a/src/stats-mode.c b/src/stats-mode.c index 0983b97..563e1f6 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -31,8 +31,6 @@ static int init_stats(void) { - int ret; - state.stats = malloc(sizeof(struct ct_stats_state)); if (!state.stats) { dlog(STATE(log), LOG_ERR, "can't allocate memory for stats"); @@ -59,7 +57,7 @@ static int init_stats(void) return 0; } -static void kill_stats() +static void kill_stats(void) { cache_destroy(STATE_STATS(cache)); /* flush the buffer before exiting */ @@ -130,7 +128,7 @@ static int overrun_cb(enum nf_conntrack_msg_type type, return NFCT_CB_CONTINUE; } -static void overrun_stats() +static void overrun_stats(void) { int ret; struct nfct_handle *h; diff --git a/src/sync-alarm.c b/src/sync-alarm.c index d9a8267..05ddf81 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -22,6 +22,8 @@ #include "us-conntrack.h" #include "alarm.h" +#include + static void refresher(struct alarm_list *a, void *data) { int len; diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 63fd4b2..d881298 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -25,13 +25,14 @@ #include "debug.h" #include "network.h" #include "alarm.h" +#include "log.h" #include #include #if 0 #define dp printf #else -#define dp +#define dp(...) #endif static LIST_HEAD(rs_list); @@ -92,7 +93,7 @@ static void do_alive_alarm(struct alarm_list *a, void *data) add_alarm(&alive_alarm); } -static int ftfw_init() +static int ftfw_init(void) { tx_queue = queue_create(CONFIG(resend_queue_size)); if (tx_queue == NULL) { @@ -117,7 +118,7 @@ static int ftfw_init() return 0; } -static void ftfw_kill() +static void ftfw_kill(void) { queue_destroy(rs_queue); queue_destroy(tx_queue); @@ -330,7 +331,7 @@ static int tx_list_xmit(struct list_head *i, struct us_conntrack *u) return ret; } -static void ftfw_run() +static void ftfw_run(void) { struct cache_ftfw *cn, *tmp; diff --git a/src/sync-mode.c b/src/sync-mode.c index 8be8c18..f2bfc9f 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -38,7 +38,7 @@ static void do_mcast_handler_step(struct nethdr *net) int query; struct netpld *pld = NETHDR_DATA(net); char __ct[nfct_maxsize()]; - struct nf_conntrack *ct = (struct nf_conntrack *) __ct; + struct nf_conntrack *ct = (struct nf_conntrack *)(void*) __ct; struct us_conntrack *u = NULL; if (STATE_SYNC(sync)->recv(net)) diff --git a/src/traffic_stats.c b/src/traffic_stats.c index b2cdaae..b6fa030 100644 --- a/src/traffic_stats.c +++ b/src/traffic_stats.c @@ -48,8 +48,8 @@ void dump_traffic_stats(int fd) STATE(packets)[NFCT_DIR_REPLY]; size = sprintf(buf, "traffic processed:\n"); - size += sprintf(buf+size, "%20llu Bytes ", bytes); - size += sprintf(buf+size, "%20llu Pckts\n\n", packets); + size += sprintf(buf+size, "%20llu Bytes ", (unsigned long long)bytes); + size += sprintf(buf+size, "%20llu Pckts\n\n", (unsigned long long)packets); send(fd, buf, size, 0); } -- cgit v1.2.3 From 83bcf7f49c07e952868099b5027199c8f7ea3c1a Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Tue, 15 Jan 2008 14:10:36 +0000 Subject: minor constification fixes update libnfnetlink dependencies --- configure.in | 2 +- include/queue.h | 2 +- src/queue.c | 2 +- src/sync-ftfw.c | 10 +++++----- 4 files changed, 8 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/configure.in b/configure.in index 75c6898..6a9d882 100644 --- a/configure.in +++ b/configure.in @@ -17,7 +17,7 @@ case $target in esac dnl Dependencies -LIBNFNETLINK_REQUIRED=0.0.25 +LIBNFNETLINK_REQUIRED=0.0.32 LIBNETFILTER_CONNTRACK_REQUIRED=0.0.88 PKG_CHECK_MODULES(LIBNFNETLINK, libnfnetlink >= $LIBNFNETLINK_REQUIRED,, diff --git a/include/queue.h b/include/queue.h index 2e08e56..ab04d62 100644 --- a/include/queue.h +++ b/include/queue.h @@ -26,6 +26,6 @@ int queue_add(struct queue *b, const void *data, size_t size); void queue_del(struct queue *b, void *data); void queue_iterate(struct queue *b, const void *data, - int (*iterate)(void *data1, void *data2)); + int (*iterate)(void *data1, const void *data2)); #endif diff --git a/src/queue.c b/src/queue.c index 1c31157..80b3342 100644 --- a/src/queue.c +++ b/src/queue.c @@ -110,7 +110,7 @@ void queue_del(struct queue *b, void *data) void queue_iterate(struct queue *b, const void *data, - int (*iterate)(void *data1, void *data2)) + int (*iterate)(void *data1, const void *data2)) { struct list_head *i, *tmp; struct queue_node *n; diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index d881298..2d79293 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -157,7 +157,7 @@ static int ftfw_local(int fd, int type, void *data) return ret; } -static int rs_queue_to_tx(void *data1, void *data2) +static int rs_queue_to_tx(void *data1, const void *data2) { struct nethdr *net = data1; const struct nethdr_ack *nack = data2; @@ -170,7 +170,7 @@ static int rs_queue_to_tx(void *data1, void *data2) return 0; } -static int rs_queue_empty(void *data1, void *data2) +static int rs_queue_empty(void *data1, const void *data2) { struct nethdr *net = data1; const struct nethdr_ack *h = data2; @@ -237,7 +237,7 @@ static int ftfw_recv(const struct nethdr *net) } if (IS_NACK(net)) { - struct nethdr_ack *nack = (struct nethdr_ack *) net; + const struct nethdr_ack *nack = (const struct nethdr_ack *) net; dp("NACK: from seq=%u to seq=%u\n", nack->from, nack->to); rs_list_to_tx(STATE_SYNC(internal), nack->from, nack->to); @@ -248,7 +248,7 @@ static int ftfw_recv(const struct nethdr *net) cache_iterate(STATE_SYNC(internal), NULL, do_cache_to_tx); return 1; } else if (IS_ACK(net)) { - struct nethdr_ack *h = (struct nethdr_ack *) net; + const struct nethdr_ack *h = (const struct nethdr_ack *) net; dp("ACK: from seq=%u to seq=%u\n", h->from, h->to); rs_list_empty(STATE_SYNC(internal), h->from, h->to); @@ -289,7 +289,7 @@ insert: } } -static int tx_queue_xmit(void *data1, void *data2) +static int tx_queue_xmit(void *data1, const void *data2) { struct nethdr *net = data1; int len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); -- cgit v1.2.3 From c60b7e984e8907f15439d07e88dad8a23c86cf2b Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Tue, 15 Jan 2008 14:35:06 +0000 Subject: use list_del_init() and list_empty() to check if a node is in the list --- ChangeLog | 1 + src/sync-ftfw.c | 15 +++++++-------- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index f42234a..ec32db9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -42,6 +42,7 @@ o wake up the daemon iff there are real events to handle instead of polling o add support for tagged vlan interfaces in the config file, e.g. eth0.1 o improve alarm framework based on suggestions from Max Kellerman o constify queue_iterate() +o use list_del_init() and list_empty() to check if a node is in the list Max Kellermann : diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 2d79293..ce58466 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -50,6 +50,7 @@ struct cache_ftfw { static void cache_ftfw_add(struct us_conntrack *u, void *data) { struct cache_ftfw *cn = data; + /* These nodes are not inserted in the list */ INIT_LIST_HEAD(&cn->rs_list); INIT_LIST_HEAD(&cn->tx_list); } @@ -58,10 +59,11 @@ static void cache_ftfw_del(struct us_conntrack *u, void *data) { struct cache_ftfw *cn = data; - if (cn->rs_list.next == &cn->rs_list && - cn->rs_list.prev == &cn->rs_list) + /* this node is already out of the list */ + if (list_empty(&cn->rs_list)) return; + /* no need for list_del_init since the entry is destroyed */ list_del(&cn->rs_list); } @@ -208,8 +210,7 @@ static void rs_list_empty(struct cache *c, unsigned int from, unsigned int to) u = cache_get_conntrack(STATE_SYNC(internal), cn); if (between(cn->seq, from, to)) { dp("queue: deleting from queue (seq=%u)\n", cn->seq); - list_del(&cn->rs_list); - INIT_LIST_HEAD(&cn->rs_list); + list_del_init(&cn->rs_list); } } } @@ -277,8 +278,7 @@ static void ftfw_send(struct nethdr *net, struct us_conntrack *u) cn->rs_list.prev == &cn->rs_list) goto insert; - list_del(&cn->rs_list); - INIT_LIST_HEAD(&cn->rs_list); + list_del_init(&cn->rs_list); insert: cn->seq = net->seq; list_add(&cn->rs_list, &rs_list); @@ -320,8 +320,7 @@ static int tx_list_xmit(struct list_head *i, struct us_conntrack *u) ntohl(net->seq), ntohs(net->flags), ntohs(net->len)); - list_del(i); - INIT_LIST_HEAD(i); + list_del_init(i); tx_list_len--; ret = mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); -- cgit v1.2.3 From e8c9c3c477d68e10719d829ede6f4cb3087f0efd Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Tue, 15 Jan 2008 14:49:12 +0000 Subject: more list_empty() use instead of directly check the header --- src/alarm.c | 8 ++++++-- src/sync-ftfw.c | 7 ++----- 2 files changed, 8 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/alarm.c b/src/alarm.c index 25075ef..0fe80ee 100644 --- a/src/alarm.c +++ b/src/alarm.c @@ -31,6 +31,8 @@ void init_alarm(struct alarm_list *t, void *data, void (*fcn)(struct alarm_list *a, void *data)) { + /* initialize the head to check whether a node is inserted */ + INIT_LIST_HEAD(&t->head); timerclear(&t->tv); t->data = data; t->function = fcn; @@ -61,12 +63,14 @@ void add_alarm(struct alarm_list *alarm) void del_alarm(struct alarm_list *alarm) { - list_del(&alarm->head); + /* don't remove a non-inserted node */ + if (!list_empty(&alarm->head)) + list_del_init(&alarm->head); } void mod_alarm(struct alarm_list *alarm, unsigned long sc, unsigned long usc) { - list_del(&alarm->head); + list_del_init(&alarm->head); set_alarm_expiration(alarm, sc, usc); add_alarm(alarm); } diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index ce58466..11febed 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -274,12 +274,9 @@ static void ftfw_send(struct nethdr *net, struct us_conntrack *u) cn = (struct cache_ftfw *) cache_get_extra(STATE_SYNC(internal), u); - if (cn->rs_list.next == &cn->rs_list && - cn->rs_list.prev == &cn->rs_list) - goto insert; + if (!list_empty(&cn->rs_list) + list_del(&cn->rs_list); - list_del_init(&cn->rs_list); -insert: cn->seq = net->seq; list_add(&cn->rs_list, &rs_list); break; -- cgit v1.2.3 From 4058f37c5bd53ace781d1d3b5c722474148f0365 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Tue, 15 Jan 2008 14:55:00 +0000 Subject: Max Kellermann : don't call INIT_LIST_HEAD on list item when unneeded --- ChangeLog | 1 + src/queue.c | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index ec32db9..6256ee6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -65,6 +65,7 @@ o import tcp_state_helper only once o add missing printf arguments o use timeradd() since manipulating tv_sec directly o fix lots of gcc warnings +o don't call INIT_LIST_HEAD on list item when unneeded version 0.9.5 (2007/07/29) ------------------------------ diff --git a/src/queue.c b/src/queue.c index 80b3342..a721760 100644 --- a/src/queue.c +++ b/src/queue.c @@ -55,7 +55,6 @@ static struct queue_node *queue_node_create(const void *data, size_t size) if (n == NULL) return NULL; - INIT_LIST_HEAD(&n->head); n->size = size; memcpy(n->data, data, size); -- cgit v1.2.3 From e7fe750ed1ba9db1c98e27b9721b49f78c39a15c Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Tue, 15 Jan 2008 14:55:31 +0000 Subject: fix missing bracket --- src/sync-ftfw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 11febed..0943e68 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -274,7 +274,7 @@ static void ftfw_send(struct nethdr *net, struct us_conntrack *u) cn = (struct cache_ftfw *) cache_get_extra(STATE_SYNC(internal), u); - if (!list_empty(&cn->rs_list) + if (!list_empty(&cn->rs_list)) list_del(&cn->rs_list); cn->seq = net->seq; -- cgit v1.2.3 From 588abed2a7df4fa1723475e41399876f3ee34250 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Tue, 15 Jan 2008 15:12:39 +0000 Subject: remove unrequired list_del_init in alarm.c --- src/alarm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/alarm.c b/src/alarm.c index 0fe80ee..d00e281 100644 --- a/src/alarm.c +++ b/src/alarm.c @@ -70,7 +70,7 @@ void del_alarm(struct alarm_list *alarm) void mod_alarm(struct alarm_list *alarm, unsigned long sc, unsigned long usc) { - list_del_init(&alarm->head); + list_del(&alarm->head); set_alarm_expiration(alarm, sc, usc); add_alarm(alarm); } -- cgit v1.2.3 From 5b4129a89e9fa3ea3b5d57fc362f682aa85abfc7 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Tue, 15 Jan 2008 15:41:13 +0000 Subject: remove unix socket file on exit --- ChangeLog | 1 + include/local.h | 2 +- src/local.c | 6 +++++- src/run.c | 2 +- 4 files changed, 8 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 6256ee6..75ead6b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -43,6 +43,7 @@ o add support for tagged vlan interfaces in the config file, e.g. eth0.1 o improve alarm framework based on suggestions from Max Kellerman o constify queue_iterate() o use list_del_init() and list_empty() to check if a node is in the list +o remove unix socket file on exit Max Kellermann : diff --git a/include/local.h b/include/local.h index 350b8bf..aae73a7 100644 --- a/include/local.h +++ b/include/local.h @@ -15,7 +15,7 @@ struct local_conf { /* local server */ int local_server_create(struct local_conf *conf); -void local_server_destroy(int fd); +void local_server_destroy(int fd, const char *); int do_local_server_step(int fd, void *data, void (*process)(int fd, void *data)); diff --git a/src/local.c b/src/local.c index 9ff5f82..d861e12 100644 --- a/src/local.c +++ b/src/local.c @@ -37,6 +37,7 @@ int local_server_create(struct local_conf *conf) if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &conf->reuseaddr, sizeof(conf->reuseaddr)) == -1) { close(fd); + unlink(conf->path); return -1; } @@ -47,19 +48,22 @@ int local_server_create(struct local_conf *conf) if (bind(fd, (struct sockaddr *) &local, len) == -1) { close(fd); + unlink(conf->path); return -1; } if (listen(fd, conf->backlog) == -1) { close(fd); + unlink(conf->path); return -1; } return fd; } -void local_server_destroy(int fd) +void local_server_destroy(int fd, const char *path) { + unlink(path); close(fd); } diff --git a/src/run.c b/src/run.c index 3fd98cd..cb5116d 100644 --- a/src/run.c +++ b/src/run.c @@ -43,7 +43,7 @@ void killer(int foo) nfct_close(STATE(dump)); ignore_pool_destroy(STATE(ignore_pool)); - local_server_destroy(STATE(local)); + local_server_destroy(STATE(local), CONFIG(local).path); STATE(mode)->kill(); unlink(CONFIG(lockfile)); dlog(STATE(log), LOG_NOTICE, "---- shutdown received ----"); -- cgit v1.2.3 From 192004bf643733b63ea0a364ff8dde47cf368144 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Tue, 15 Jan 2008 15:50:53 +0000 Subject: use umask() to set up file permissions --- ChangeLog | 1 + src/log.c | 24 ++---------------------- src/main.c | 5 ++++- 3 files changed, 7 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 75ead6b..63179e7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -44,6 +44,7 @@ o improve alarm framework based on suggestions from Max Kellerman o constify queue_iterate() o use list_del_init() and list_empty() to check if a node is in the list o remove unix socket file on exit +o use umask() to set up file permissions Max Kellermann : diff --git a/src/log.c b/src/log.c index b42e049..35ae0c3 100644 --- a/src/log.c +++ b/src/log.c @@ -33,17 +33,7 @@ int init_log(void) { if (CONFIG(logfile)[0]) { - int fd; - - fd = open(CONFIG(logfile), O_CREAT | O_RDWR, 0600); - if (fd == -1) { - fprintf(stderr, "ERROR: can't open logfile `%s'." - "Reason: %s\n", CONFIG(logfile), - strerror(errno)); - return -1; - } - - STATE(log) = fdopen(fd, "a+"); + STATE(log) = fopen(CONFIG(logfile), "a+"); if (STATE(log) == NULL) { fprintf(stderr, "ERROR: can't open logfile `%s'." "Reason: %s\n", CONFIG(logfile), @@ -53,17 +43,7 @@ int init_log(void) } if (CONFIG(stats).logfile[0]) { - int fd; - - fd = open(CONFIG(stats).logfile, O_CREAT | O_RDWR, 0600); - if (fd == -1) { - fprintf(stderr, "ERROR: can't open logfile `%s'." - "Reason: %s\n", CONFIG(stats).logfile, - strerror(errno)); - return -1; - } - - STATE(stats_log) = fdopen(fd, "a+"); + STATE(stats_log) = fopen(CONFIG(stats).logfile, "a+"); if (STATE(stats_log) == NULL) { fprintf(stderr, "ERROR: can't open logfile `%s'." "Reason: %s\n", CONFIG(stats).logfile, diff --git a/src/main.c b/src/main.c index 11974ff..a4ee307 100644 --- a/src/main.c +++ b/src/main.c @@ -239,6 +239,8 @@ int main(int argc, char *argv[]) if (config_set == 0) strcpy(config_file, DEFAULT_CONFIGFILE); + umask(0177); + if ((ret = init_config(config_file)) == -1) { fprintf(stderr, "can't open config file `%s'\n", config_file); exit(EXIT_FAILURE); @@ -262,7 +264,8 @@ int main(int argc, char *argv[]) /* * lock file */ - if ((ret = open(CONFIG(lockfile), O_CREAT | O_EXCL | O_TRUNC)) == -1) { + ret = open(CONFIG(lockfile), O_CREAT | O_EXCL | O_TRUNC, 0600); + if (ret == -1) { fprintf(stderr, "lockfile `%s' exists, perhaps conntrackd " "already running?\n", CONFIG(lockfile)); exit(EXIT_FAILURE); -- cgit v1.2.3 From 88413547acdce9d818a237c72482d89f6032e9ae Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Wed, 16 Jan 2008 17:26:07 +0000 Subject: fix missing command initialization (breakage introduced in r7208) --- src/conntrack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index f301a82..9d268c5 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -679,7 +679,7 @@ int main(int argc, char *argv[]) struct nf_expect *exp = (struct nf_expect *)(void*) __exp; int l3protonum; union ct_address ad; - unsigned int command; + unsigned int command = 0; memset(__obj, 0, sizeof(__obj)); memset(__exptuple, 0, sizeof(__exptuple)); -- cgit v1.2.3 From a8f06005be7e61f0562d8c36d953f688922edf01 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Thu, 17 Jan 2008 16:56:50 +0000 Subject: Max Kellermann : use C99 integers (uint32_t instead of u_int32_t) --- ChangeLog | 1 + include/cache.h | 5 +++-- include/conntrack.h | 3 ++- include/conntrackd.h | 21 +++++++++++---------- include/hash.h | 17 +++++++++-------- include/ignore.h | 4 +++- include/mcast.h | 7 ++++--- include/network.h | 34 +++++++++++++++++----------------- include/state_helper.h | 4 +++- src/build.c | 30 +++++++++++++++--------------- src/cache.c | 18 +++++++++--------- src/conntrack.c | 6 +++--- src/hash.c | 12 ++++++------ src/ignore_pool.c | 20 ++++++++++---------- src/mcast.c | 4 ++-- src/netlink.c | 4 ++-- src/network.c | 2 +- src/parse.c | 6 +++--- src/state_helper.c | 2 +- src/state_helper_tcp.c | 2 +- src/sync-ftfw.c | 4 ++-- src/traffic_stats.c | 4 ++-- 22 files changed, 110 insertions(+), 100 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index d6bfbf9..6425e32 100644 --- a/ChangeLog +++ b/ChangeLog @@ -51,6 +51,7 @@ Max Kellermann : o fix shadow warnings by renaming variables or making them local o remove "-g" from Makefile.am, this should be specified by the user o enable C99 mode +o use C99 integers (uint32_t instead of u_int32_t) = conntrackd = o resolve global variable "alarm" conflict with alarm() function in unistd.h. diff --git a/include/cache.h b/include/cache.h index e4fb945..0743d3f 100644 --- a/include/cache.h +++ b/include/cache.h @@ -1,7 +1,8 @@ #ifndef _CACHE_H_ #define _CACHE_H_ -#include +#include +#include #include /* cache features */ @@ -75,7 +76,7 @@ struct cache_extra { struct nf_conntrack; -struct cache *cache_create(const char *name, unsigned int features, u_int8_t proto, struct cache_extra *extra); +struct cache *cache_create(const char *name, unsigned int features, uint8_t proto, struct cache_extra *extra); void cache_destroy(struct cache *e); struct us_conntrack *cache_add(struct cache *c, struct nf_conntrack *ct); diff --git a/include/conntrack.h b/include/conntrack.h index 8f2b6a2..d6b6150 100644 --- a/include/conntrack.h +++ b/include/conntrack.h @@ -3,6 +3,7 @@ #include "linux_list.h" #include +#include #include #define PROGNAME "conntrack" @@ -149,7 +150,7 @@ struct ctproto_handler { struct list_head head; const char *name; - u_int16_t protonum; + uint16_t protonum; const char *version; enum ctattr_protoinfo protoinfo_attr; diff --git a/include/conntrackd.h b/include/conntrackd.h index d3f66ba..418f4b7 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -4,6 +4,7 @@ #include "mcast.h" #include "local.h" +#include #include #include #include "cache.h" @@ -63,9 +64,9 @@ enum { #endif union inet_address { - u_int32_t ipv4; - u_int32_t ipv6[4]; - u_int32_t all[4]; + uint32_t ipv4; + uint32_t ipv6[4]; + uint32_t all[4]; }; #define CONFIG(x) conf.x @@ -112,9 +113,9 @@ struct ct_general_state { struct nfct_handle *dump; /* dump handler */ /* statistics */ - u_int64_t malformed; - u_int64_t bytes[NFCT_DIR_MAX]; - u_int64_t packets[NFCT_DIR_MAX]; + uint64_t malformed; + uint64_t bytes[NFCT_DIR_MAX]; + uint64_t packets[NFCT_DIR_MAX]; }; #define STATE_SYNC(x) state.sync->x @@ -128,10 +129,10 @@ struct ct_sync_state { struct sync_mode *sync; /* sync mode */ - u_int32_t last_seq_sent; /* last sequence number sent */ - u_int32_t last_seq_recv; /* last sequence number recv */ - u_int64_t packets_replayed; /* number of replayed packets */ - u_int64_t packets_lost; /* lost packets: sequence tracking */ + uint32_t last_seq_sent; /* last sequence number sent */ + uint32_t last_seq_recv; /* last sequence number recv */ + uint64_t packets_replayed; /* number of replayed packets */ + uint64_t packets_lost; /* lost packets: sequence tracking */ }; #define STATE_STATS(x) state.stats->x diff --git a/include/hash.h b/include/hash.h index c9460fa..caad412 100644 --- a/include/hash.h +++ b/include/hash.h @@ -2,21 +2,22 @@ #define _NF_SET_HASH_H_ #include -#include #include "slist.h" #include "linux_list.h" +#include + struct hashtable; struct hashtable_node; struct hashtable { - u_int32_t hashsize; - u_int32_t limit; - u_int32_t count; - u_int32_t initval; - u_int32_t datasize; + uint32_t hashsize; + uint32_t limit; + uint32_t count; + uint32_t initval; + uint32_t datasize; - u_int32_t (*hash)(const void *data, struct hashtable *table); + uint32_t (*hash)(const void *data, struct hashtable *table); int (*compare)(const void *data1, const void *data2); struct slist_head members[0]; @@ -32,7 +33,7 @@ void hashtable_destroy_node(struct hashtable_node *h); struct hashtable * hashtable_create(int hashsize, int limit, int datasize, - u_int32_t (*hash)(const void *data, struct hashtable *table), + uint32_t (*hash)(const void *data, struct hashtable *table), int (*compare)(const void *data1, const void *data2)); void hashtable_destroy(struct hashtable *h); diff --git a/include/ignore.h b/include/ignore.h index 96deb93..f1c2846 100644 --- a/include/ignore.h +++ b/include/ignore.h @@ -1,11 +1,13 @@ #ifndef _IGNORE_H_ #define _IGNORE_H_ +#include + struct ignore_pool { struct hashtable *h; }; -struct ignore_pool *ignore_pool_create(u_int8_t family); +struct ignore_pool *ignore_pool_create(uint8_t family); void ignore_pool_destroy(struct ignore_pool *ip); int ignore_pool_add(struct ignore_pool *ip, void *data); int ignore_pool_test(struct ignore_pool *ip, struct nf_conntrack *ct); diff --git a/include/mcast.h b/include/mcast.h index d4fd335..e3cdb38 100644 --- a/include/mcast.h +++ b/include/mcast.h @@ -1,6 +1,7 @@ #ifndef _MCAST_H_ #define _MCAST_H_ +#include #include #include @@ -22,9 +23,9 @@ struct mcast_conf { }; struct mcast_stats { - u_int64_t bytes; - u_int64_t messages; - u_int64_t error; + uint64_t bytes; + uint64_t messages; + uint64_t error; }; struct mcast_sock { diff --git a/include/network.h b/include/network.h index d0b639b..f9976dd 100644 --- a/include/network.h +++ b/include/network.h @@ -1,12 +1,12 @@ #ifndef _NETWORK_H_ #define _NETWORK_H_ -#include +#include struct nethdr { - u_int16_t flags; - u_int16_t len; - u_int32_t seq; + uint16_t flags; + uint16_t len; + uint32_t seq; }; #define NETHDR_SIZ sizeof(struct nethdr) @@ -14,11 +14,11 @@ struct nethdr { (struct netpld *)(((char *)x) + sizeof(struct nethdr)) struct nethdr_ack { - u_int16_t flags; - u_int16_t len; - u_int32_t seq; - u_int32_t from; - u_int32_t to; + uint16_t flags; + uint16_t len; + uint32_t seq; + uint32_t from; + uint32_t to; }; #define NETHDR_ACK_SIZ sizeof(struct nethdr_ack) @@ -55,7 +55,7 @@ int prepare_send_netmsg(struct mcast_sock *m, void *data); int mcast_send_netmsg(struct mcast_sock *m, void *data); int mcast_recv_netmsg(struct mcast_sock *m, void *data, int len); int handle_netmsg(struct nethdr *net); -int mcast_track_seq(u_int32_t seq, u_int32_t *exp_seq); +int mcast_track_seq(uint32_t seq, uint32_t *exp_seq); struct mcast_conf; @@ -103,21 +103,21 @@ int mcast_buffered_pending_netmsg(struct mcast_sock *m); * and worry about wraparound (automatic with unsigned arithmetic). */ -static inline int before(__u32 seq1, __u32 seq2) +static inline int before(uint32_t seq1, uint32_t seq2) { - return (__s32)(seq1-seq2) < 0; + return (int32_t)(seq1-seq2) < 0; } #define after(seq2, seq1) before(seq1, seq2) /* is s2<=s1<=s3 ? */ -static inline int between(__u32 seq1, __u32 seq2, __u32 seq3) +static inline int between(uint32_t seq1, uint32_t seq2, uint32_t seq3) { return seq3 - seq2 >= seq1 - seq2; } struct netpld { - u_int16_t len; - u_int16_t query; + uint16_t len; + uint16_t query; }; #define NETPLD_SIZ sizeof(struct netpld) @@ -134,8 +134,8 @@ struct netpld { }) struct netattr { - u_int16_t nta_len; - u_int16_t nta_attr; + uint16_t nta_len; + uint16_t nta_attr; }; #define ATTR_NETWORK2HOST(x) \ diff --git a/include/state_helper.h b/include/state_helper.h index 1ed0b79..0015890 100644 --- a/include/state_helper.h +++ b/include/state_helper.h @@ -1,13 +1,15 @@ #ifndef _STATE_HELPER_H_ #define _STATE_HELPER_H_ +#include + enum { ST_H_SKIP, ST_H_REPLICATE }; struct state_replication_helper { - u_int8_t proto; + uint8_t proto; unsigned int state; int (*verdict)(const struct state_replication_helper *h, diff --git a/src/build.c b/src/build.c index 5fdc83f..c99990b 100644 --- a/src/build.c +++ b/src/build.c @@ -36,38 +36,38 @@ static void __build_u8(const struct nf_conntrack *ct, struct netpld *pld, int attr) { - u_int8_t data = nfct_get_attr_u8(ct, attr); - addattr(pld, attr, &data, sizeof(u_int8_t)); + uint8_t data = nfct_get_attr_u8(ct, attr); + addattr(pld, attr, &data, sizeof(uint8_t)); } static void __build_u16(const struct nf_conntrack *ct, struct netpld *pld, int attr) { - u_int16_t data = nfct_get_attr_u16(ct, attr); + uint16_t data = nfct_get_attr_u16(ct, attr); data = htons(data); - addattr(pld, attr, &data, sizeof(u_int16_t)); + addattr(pld, attr, &data, sizeof(uint16_t)); } static void __build_u32(const struct nf_conntrack *ct, struct netpld *pld, int attr) { - u_int32_t data = nfct_get_attr_u32(ct, attr); + uint32_t data = nfct_get_attr_u32(ct, attr); data = htonl(data); - addattr(pld, attr, &data, sizeof(u_int32_t)); + addattr(pld, attr, &data, sizeof(uint32_t)); } -static void __nat_build_u32(u_int32_t data, struct netpld *pld, int attr) +static void __nat_build_u32(uint32_t data, struct netpld *pld, int attr) { data = htonl(data); - addattr(pld, attr, &data, sizeof(u_int32_t)); + addattr(pld, attr, &data, sizeof(uint32_t)); } -static void __nat_build_u16(u_int16_t data, struct netpld *pld, int attr) +static void __nat_build_u16(uint16_t data, struct netpld *pld, int attr) { data = htons(data); - addattr(pld, attr, &data, sizeof(u_int16_t)); + addattr(pld, attr, &data, sizeof(uint16_t)); } /* XXX: IPv6 and ICMP not supported */ @@ -84,7 +84,7 @@ void build_netpld(struct nf_conntrack *ct, struct netpld *pld, int query) if (nfct_attr_is_set(ct, ATTR_PORT_DST)) __build_u16(ct, pld, ATTR_PORT_DST); if (nfct_attr_is_set(ct, ATTR_L4PROTO)) { - u_int8_t proto; + uint8_t proto; __build_u8(ct, pld, ATTR_L4PROTO); proto = nfct_get_attr_u8(ct, ATTR_L4PROTO); @@ -118,19 +118,19 @@ void build_netpld(struct nf_conntrack *ct, struct netpld *pld, int query) /* NAT */ if (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) { - u_int32_t data = nfct_get_attr_u32(ct, ATTR_REPL_IPV4_DST); + uint32_t data = nfct_get_attr_u32(ct, ATTR_REPL_IPV4_DST); __nat_build_u32(data, pld, ATTR_SNAT_IPV4); } if (nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) { - u_int32_t data = nfct_get_attr_u32(ct, ATTR_REPL_IPV4_SRC); + uint32_t data = nfct_get_attr_u32(ct, ATTR_REPL_IPV4_SRC); __nat_build_u32(data, pld, ATTR_DNAT_IPV4); } if (nfct_getobjopt(ct, NFCT_GOPT_IS_SPAT)) { - u_int16_t data = nfct_get_attr_u16(ct, ATTR_REPL_PORT_DST); + uint16_t data = nfct_get_attr_u16(ct, ATTR_REPL_PORT_DST); __nat_build_u16(data, pld, ATTR_SNAT_PORT); } if (nfct_getobjopt(ct, NFCT_GOPT_IS_DPAT)) { - u_int16_t data = nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC); + uint16_t data = nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC); __nat_build_u16(data, pld, ATTR_DNAT_PORT); } diff --git a/src/cache.c b/src/cache.c index c5afb00..dcb0123 100644 --- a/src/cache.c +++ b/src/cache.c @@ -25,17 +25,17 @@ #include "cache.h" #include -static u_int32_t hash(const void *data, struct hashtable *table) +static uint32_t hash(const void *data, struct hashtable *table) { unsigned int a, b; const struct us_conntrack *u = data; struct nf_conntrack *ct = u->ct; - a = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV4_SRC), sizeof(u_int32_t), + a = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV4_SRC), sizeof(uint32_t), ((nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO) << 16) | (nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO)))); - b = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV4_DST), sizeof(u_int32_t), + b = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV4_DST), sizeof(uint32_t), ((nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC) << 16) | (nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST)))); @@ -46,24 +46,24 @@ static u_int32_t hash(const void *data, struct hashtable *table) * but using a multiply, less expensive than a divide. See: * http://www.mail-archive.com/netdev@vger.kernel.org/msg56623.html */ - return ((u_int64_t)jhash_2words(a, b, 0) * table->hashsize) >> 32; + return ((uint64_t)jhash_2words(a, b, 0) * table->hashsize) >> 32; } -static u_int32_t hash6(const void *data, struct hashtable *table) +static uint32_t hash6(const void *data, struct hashtable *table) { unsigned int a, b; const struct us_conntrack *u = data; struct nf_conntrack *ct = u->ct; - a = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV6_SRC), sizeof(u_int32_t)*4, + a = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV6_SRC), sizeof(uint32_t)*4, ((nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO) << 16) | (nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO)))); - b = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV6_DST), sizeof(u_int32_t)*4, + b = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV6_DST), sizeof(uint32_t)*4, ((nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC) << 16) | (nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST)))); - return ((u_int64_t)jhash_2words(a, b, 0) * table->hashsize) >> 32; + return ((uint64_t)jhash_2words(a, b, 0) * table->hashsize) >> 32; } static int __compare(const struct nf_conntrack *ct1, @@ -123,7 +123,7 @@ struct cache_feature *cache_feature[CACHE_MAX_FEATURE] = { struct cache *cache_create(const char *name, unsigned int features, - u_int8_t proto, + uint8_t proto, struct cache_extra *extra) { size_t size = sizeof(struct us_conntrack); diff --git a/src/conntrack.c b/src/conntrack.c index 9d268c5..b8843d4 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -444,8 +444,8 @@ parse_inetaddr(const char *cp, struct addr_parse *parse) } union ct_address { - u_int32_t v4; - u_int32_t v6[4]; + uint32_t v4; + uint32_t v6[4]; }; static int @@ -472,7 +472,7 @@ nat_parse(char *arg, int portok, struct nf_conntrack *obj, int type) colon = strchr(arg, ':'); if (colon) { - u_int16_t port; + uint16_t port; if (!portok) exit_error(PARAMETER_PROBLEM, diff --git a/src/hash.c b/src/hash.c index 553dd1d..d7724c8 100644 --- a/src/hash.c +++ b/src/hash.c @@ -48,7 +48,7 @@ void hashtable_destroy_node(struct hashtable_node *h) struct hashtable * hashtable_create(int hashsize, int limit, int datasize, - u_int32_t (*hash)(const void *data, struct hashtable *table), + uint32_t (*hash)(const void *data, struct hashtable *table), int (*compare)(const void *data1, const void *data2)) { int i; @@ -85,7 +85,7 @@ void *hashtable_add(struct hashtable *table, void *data) { struct slist_head *e; struct hashtable_node *n; - u_int32_t id; + uint32_t id; /* hash table is full */ if (table->count >= table->limit) { @@ -118,7 +118,7 @@ void *hashtable_add(struct hashtable *table, void *data) void *hashtable_test(struct hashtable *table, const void *data) { struct slist_head *e; - u_int32_t id; + uint32_t id; struct hashtable_node *n; id = table->hash(data, table); @@ -136,7 +136,7 @@ void *hashtable_test(struct hashtable *table, const void *data) int hashtable_del(struct hashtable *table, void *data) { struct slist_head *e, *next, *prev; - u_int32_t id; + uint32_t id; struct hashtable_node *n; id = table->hash(data, table); @@ -156,7 +156,7 @@ int hashtable_del(struct hashtable *table, void *data) int hashtable_flush(struct hashtable *table) { - u_int32_t i; + uint32_t i; struct slist_head *e, *next, *prev; struct hashtable_node *n; @@ -175,7 +175,7 @@ int hashtable_flush(struct hashtable *table) int hashtable_iterate(struct hashtable *table, void *data, int (*iterate)(void *data1, void *data2)) { - u_int32_t i; + uint32_t i; struct slist_head *e, *next, *prev; struct hashtable_node *n; diff --git a/src/ignore_pool.c b/src/ignore_pool.c index 82afa93..5889398 100644 --- a/src/ignore_pool.c +++ b/src/ignore_pool.c @@ -29,32 +29,32 @@ #define IGNORE_POOL_SIZE 128 #define IGNORE_POOL_LIMIT INT_MAX -static u_int32_t hash(const void *data, struct hashtable *table) +static uint32_t hash(const void *data, struct hashtable *table) { - const u_int32_t *ip = data; + const uint32_t *ip = data; return jhash_1word(*ip, 0) % table->hashsize; } -static u_int32_t hash6(const void *data, struct hashtable *table) +static uint32_t hash6(const void *data, struct hashtable *table) { - return jhash(data, sizeof(u_int32_t)*4, 0) % table->hashsize; + return jhash(data, sizeof(uint32_t)*4, 0) % table->hashsize; } static int compare(const void *data1, const void *data2) { - const u_int32_t *ip1 = data1; - const u_int32_t *ip2 = data2; + const uint32_t *ip1 = data1; + const uint32_t *ip2 = data2; return *ip1 == *ip2; } static int compare6(const void *data1, const void *data2) { - return memcmp(data1, data2, sizeof(u_int32_t)*4) == 0; + return memcmp(data1, data2, sizeof(uint32_t)*4) == 0; } -struct ignore_pool *ignore_pool_create(u_int8_t proto) +struct ignore_pool *ignore_pool_create(uint8_t proto) { struct ignore_pool *ip; @@ -67,14 +67,14 @@ struct ignore_pool *ignore_pool_create(u_int8_t proto) case AF_INET: ip->h = hashtable_create(IGNORE_POOL_SIZE, IGNORE_POOL_LIMIT, - sizeof(u_int32_t), + sizeof(uint32_t), hash, compare); break; case AF_INET6: ip->h = hashtable_create(IGNORE_POOL_SIZE, IGNORE_POOL_LIMIT, - sizeof(u_int32_t)*4, + sizeof(uint32_t)*4, hash6, compare6); break; diff --git a/src/mcast.c b/src/mcast.c index cf03593..185a7e2 100644 --- a/src/mcast.c +++ b/src/mcast.c @@ -57,9 +57,9 @@ struct mcast_sock *mcast_server_create(struct mcast_conf *conf) case AF_INET6: memcpy(&mreq.ipv6.ipv6mr_multiaddr, &conf->in.inet_addr6, - sizeof(u_int32_t) * 4); + sizeof(uint32_t) * 4); memcpy(&mreq.ipv6.ipv6mr_interface, &conf->ifa.interface_addr6, - sizeof(u_int32_t) * 4); + sizeof(uint32_t) * 4); m->addr.ipv6.sin6_family = AF_INET6; m->addr.ipv6.sin6_port = htons(conf->port); diff --git a/src/netlink.c b/src/netlink.c index 7800b10..388407a 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -202,11 +202,11 @@ int nl_dump_conntrack_table(void) /* This function modifies the conntrack passed as argument! */ int nl_create_conntrack(struct nf_conntrack *ct) { - u_int8_t flags; + uint8_t flags; /* XXX: related connections */ if (nfct_attr_is_set(ct, ATTR_STATUS)) { - u_int32_t status = nfct_get_attr_u32(ct, ATTR_STATUS); + uint32_t status = nfct_get_attr_u32(ct, ATTR_STATUS); status &= ~IPS_EXPECTED; nfct_set_attr_u32(ct, ATTR_STATUS, status); } diff --git a/src/network.c b/src/network.c index 9d6e6e1..939e94b 100644 --- a/src/network.c +++ b/src/network.c @@ -197,7 +197,7 @@ int handle_netmsg(struct nethdr *net) return 0; } -int mcast_track_seq(u_int32_t seq, u_int32_t *exp_seq) +int mcast_track_seq(uint32_t seq, uint32_t *exp_seq) { static int local_seq_set = 0; int ret = 1; diff --git a/src/parse.c b/src/parse.c index c8a9704..a248b47 100644 --- a/src/parse.c +++ b/src/parse.c @@ -22,19 +22,19 @@ static void parse_u8(struct nf_conntrack *ct, int attr, void *data) { - u_int8_t *value = (u_int8_t *) data; + uint8_t *value = (uint8_t *) data; nfct_set_attr_u8(ct, attr, *value); } static void parse_u16(struct nf_conntrack *ct, int attr, void *data) { - u_int16_t *value = (u_int16_t *) data; + uint16_t *value = (uint16_t *) data; nfct_set_attr_u16(ct, attr, ntohs(*value)); } static void parse_u32(struct nf_conntrack *ct, int attr, void *data) { - u_int32_t *value = (u_int32_t *) data; + uint32_t *value = (uint32_t *) data; nfct_set_attr_u32(ct, attr, ntohl(*value)); } diff --git a/src/state_helper.c b/src/state_helper.c index de4cf48..9034864 100644 --- a/src/state_helper.c +++ b/src/state_helper.c @@ -23,7 +23,7 @@ static struct state_replication_helper *helper[IPPROTO_MAX]; int state_helper_verdict(int type, struct nf_conntrack *ct) { - u_int8_t l4proto; + uint8_t l4proto; if (type == NFCT_Q_DESTROY) return ST_H_REPLICATE; diff --git a/src/state_helper_tcp.c b/src/state_helper_tcp.c index e0a51ee..88af35e 100644 --- a/src/state_helper_tcp.c +++ b/src/state_helper_tcp.c @@ -22,7 +22,7 @@ static int tcp_verdict(const struct state_replication_helper *h, const struct nf_conntrack *ct) { - u_int8_t t_state = nfct_get_attr_u8(ct, ATTR_TCP_STATE); + uint8_t t_state = nfct_get_attr_u8(ct, ATTR_TCP_STATE); if (h->state & (1 << t_state)) return ST_H_REPLICATE; diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 0943e68..f0b3262 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -44,7 +44,7 @@ static struct queue *tx_queue; struct cache_ftfw { struct list_head rs_list; struct list_head tx_list; - u_int32_t seq; + uint32_t seq; }; static void cache_ftfw_add(struct us_conntrack *u, void *data) @@ -73,7 +73,7 @@ static struct cache_extra cache_ftfw_extra = { .destroy = cache_ftfw_del }; -static void tx_queue_add_ctlmsg(u_int32_t flags, u_int32_t from, u_int32_t to) +static void tx_queue_add_ctlmsg(uint32_t flags, uint32_t from, uint32_t to) { struct nethdr_ack ack = { .flags = flags, diff --git a/src/traffic_stats.c b/src/traffic_stats.c index b6fa030..93511ce 100644 --- a/src/traffic_stats.c +++ b/src/traffic_stats.c @@ -42,9 +42,9 @@ void dump_traffic_stats(int fd) { char buf[512]; int size; - u_int64_t bytes = STATE(bytes)[NFCT_DIR_ORIGINAL] + + uint64_t bytes = STATE(bytes)[NFCT_DIR_ORIGINAL] + STATE(bytes)[NFCT_DIR_REPLY]; - u_int64_t packets = STATE(packets)[NFCT_DIR_ORIGINAL] + + uint64_t packets = STATE(packets)[NFCT_DIR_ORIGINAL] + STATE(packets)[NFCT_DIR_REPLY]; size = sprintf(buf, "traffic processed:\n"); -- cgit v1.2.3 From a156e55302d7ce35234b6075124d2b5ed4037c89 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Thu, 17 Jan 2008 17:10:40 +0000 Subject: Max Kellerman : o always close stdin - even in non-daemon mode, it is of no use o chdir("/") to release the cwd inode o ignore setsid() failure, because there is only one possible and o fix harmless error condition --- ChangeLog | 4 ++++ src/main.c | 13 +++++-------- 2 files changed, 9 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 6425e32..9fbfa71 100644 --- a/ChangeLog +++ b/ChangeLog @@ -71,6 +71,10 @@ o add missing printf arguments o use timeradd() since manipulating tv_sec directly o fix lots of gcc warnings o don't call INIT_LIST_HEAD on list item when unneeded +o always close stdin - even in non-daemon mode, it is of no use +o chdir("/") to release the cwd inode +o ignore setsid() failure, because there is only one possible and +o fix harmless error condition version 0.9.5 (2007/07/29) ------------------------------ diff --git a/src/main.c b/src/main.c index a4ee307..b860982 100644 --- a/src/main.c +++ b/src/main.c @@ -284,9 +284,12 @@ int main(int argc, char *argv[]) exit(EXIT_FAILURE); } + chdir("/"); + close(STDIN_FILENO); + /* Daemonize conntrackd */ if (type == DAEMON) { - pid_t pid, sid; + pid_t pid; if ((pid = fork()) == -1) { perror("fork has failed: "); @@ -294,14 +297,8 @@ int main(int argc, char *argv[]) } else if (pid) exit(EXIT_SUCCESS); - sid = setsid(); - - if (sid < 0) { - perror("setsid has failed: "); - exit(EXIT_FAILURE); - } + setsid(); - close(STDIN_FILENO); close(STDOUT_FILENO); close(STDERR_FILENO); -- cgit v1.2.3 From ab4f7c0abd2d42f20b8675b3bc552a88204ce4ad Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Thu, 17 Jan 2008 17:12:49 +0000 Subject: Max Kellermann : add buffer_destroy() to buffer.c --- ChangeLog | 1 + include/buffer.h | 2 ++ src/buffer.c | 6 ++++++ 3 files changed, 9 insertions(+) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 9fbfa71..3d53d51 100644 --- a/ChangeLog +++ b/ChangeLog @@ -75,6 +75,7 @@ o always close stdin - even in non-daemon mode, it is of no use o chdir("/") to release the cwd inode o ignore setsid() failure, because there is only one possible and o fix harmless error condition +o add buffer_destroy() to buffer.c version 0.9.5 (2007/07/29) ------------------------------ diff --git a/include/buffer.h b/include/buffer.h index aa753b4..0d52e72 100644 --- a/include/buffer.h +++ b/include/buffer.h @@ -8,6 +8,8 @@ struct buffer { }; struct buffer *buffer_create(unsigned int size); +void buffer_destroy(struct buffer *b); + int buffer_add(struct buffer *b, void *data, unsigned int size); void buffer_flush(struct buffer *b, void (*cb)(void *buffer_data, diff --git a/src/buffer.c b/src/buffer.c index 79266a7..adde81c 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -41,6 +41,12 @@ struct buffer *buffer_create(unsigned int size) return b; } +void buffer_destroy(struct buffer *b) +{ + free(b->data); + free(b); +} + int buffer_add(struct buffer *b, void *data, unsigned int size) { if (b->size - b->cur_size < size) { -- cgit v1.2.3 From 5c7db5abef470bc6a0f2e3858a5fc75731c9f3bd Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Thu, 17 Jan 2008 17:16:54 +0000 Subject: Max Kellermann : fix memory leaks in several error output paths --- ChangeLog | 1 + src/mcast.c | 4 ++++ src/stats-mode.c | 3 +++ src/sync-mode.c | 3 +++ 4 files changed, 11 insertions(+) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 3d53d51..e9a6b5f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -76,6 +76,7 @@ o chdir("/") to release the cwd inode o ignore setsid() failure, because there is only one possible and o fix harmless error condition o add buffer_destroy() to buffer.c +o fix memory leaks in several error output paths version 0.9.5 (2007/07/29) ------------------------------ diff --git a/src/mcast.c b/src/mcast.c index 185a7e2..9684b61 100644 --- a/src/mcast.c +++ b/src/mcast.c @@ -80,6 +80,8 @@ struct mcast_sock *mcast_server_create(struct mcast_conf *conf) if (ioctl(m->fd, SIOCGIFMTU, &ifr) == -1) { debug("ioctl"); + close(m->fd); + free(m); return NULL; } conf->mtu = ifr.ifr_mtu; @@ -201,6 +203,7 @@ struct mcast_sock *mcast_client_create(struct mcast_conf *conf) if ((m->fd = socket(conf->ipproto, SOCK_DGRAM, 0)) == -1) { debug("mcast_sock_client_create:socket"); + free(m); return NULL; } @@ -224,6 +227,7 @@ struct mcast_sock *mcast_client_create(struct mcast_conf *conf) } if (ret == -1) { + close(m->fd); free(m); m = NULL; } diff --git a/src/stats-mode.c b/src/stats-mode.c index 563e1f6..0c42d95 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -41,6 +41,7 @@ static int init_stats(void) STATE_STATS(buffer_log) = buffer_create(CONFIG(stats).buffer_size); if (!STATE_STATS(buffer_log)) { dlog(STATE(log), LOG_ERR, "can't allocate stats buffer"); + free(state.stats); return -1; } @@ -51,6 +52,8 @@ static int init_stats(void) if (!STATE_STATS(cache)) { dlog(STATE(log), LOG_ERR, "can't allocate memory for the " "external cache"); + free(state.stats); + buffer_destroy(STATE_STATS(buffer_log)); return -1; } diff --git a/src/sync-mode.c b/src/sync-mode.c index f2bfc9f..1632019 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -180,11 +180,14 @@ static int init_sync(void) STATE_SYNC(mcast_client) = mcast_client_create(&CONFIG(mcast)); if (STATE_SYNC(mcast_client) == NULL) { dlog(STATE(log), LOG_ERR, "can't open client multicast socket"); + mcast_server_destroy(STATE_SYNC(mcast_server)); return -1; } if (mcast_buffered_init(&CONFIG(mcast)) == -1) { dlog(STATE(log), LOG_ERR, "can't init tx buffer!"); + mcast_server_destroy(STATE_SYNC(mcast_server)); + mcast_client_destroy(STATE_SYNC(mcast_client)); return -1; } -- cgit v1.2.3 From a5cf250034b1f4c3fbd0b2081a756db9b20d9c7e Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Thu, 17 Jan 2008 17:20:25 +0000 Subject: Max Kellermann : check for malloc() failure in merge_opts --- ChangeLog | 3 +++ src/conntrack.c | 5 +++++ 2 files changed, 8 insertions(+) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index e9a6b5f..6754908 100644 --- a/ChangeLog +++ b/ChangeLog @@ -53,6 +53,9 @@ o remove "-g" from Makefile.am, this should be specified by the user o enable C99 mode o use C99 integers (uint32_t instead of u_int32_t) += conntrack = +o check for malloc() failure in merge_opts + = conntrackd = o resolve global variable "alarm" conflict with alarm() function in unistd.h. o enable gcc warnings, including -Werror diff --git a/src/conntrack.c b/src/conntrack.c index b8843d4..7918b3f 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -271,6 +271,9 @@ merge_options(struct option *oldopts, const struct option *newopts, *option_offset = global_option_offset; merge = malloc(sizeof(struct option) * (num_new + num_old + 1)); + if (merge == NULL) + return NULL; + memcpy(merge, oldopts, num_old * sizeof(struct option)); for (i = 0; i < num_new; i++) { merge[num_old + i] = newopts[i]; @@ -838,6 +841,8 @@ int main(int argc, char *argv[]) ATTR_ORIG_L4PROTO, h->protonum); opts = merge_options(opts, h->opts, &h->option_offset); + if (opts == NULL) + exit_error(EXIT_FAILURE, "out of memory\n"); break; case 't': options |= CT_OPT_TIMEOUT; -- cgit v1.2.3 From bdbacf04ce2e2d7ddfc7027d08e1290e7d3dc788 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Thu, 17 Jan 2008 17:34:56 +0000 Subject: Max Kellermann : use size_t for buffer sizes --- ChangeLog | 1 + include/buffer.h | 12 +++++++----- include/conntrackd.h | 2 +- src/buffer.c | 6 +++--- 4 files changed, 12 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 6754908..e0a0da7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -80,6 +80,7 @@ o ignore setsid() failure, because there is only one possible and o fix harmless error condition o add buffer_destroy() to buffer.c o fix memory leaks in several error output paths +o use size_t for buffer sizes version 0.9.5 (2007/07/29) ------------------------------ diff --git a/include/buffer.h b/include/buffer.h index 0d52e72..ab1ccd3 100644 --- a/include/buffer.h +++ b/include/buffer.h @@ -1,20 +1,22 @@ #ifndef _BUFFER_H_ #define _BUFFER_H_ +#include + struct buffer { unsigned char *data; - unsigned int size; - unsigned int cur_size; + size_t size; + size_t cur_size; }; -struct buffer *buffer_create(unsigned int size); +struct buffer *buffer_create(size_t size); void buffer_destroy(struct buffer *b); -int buffer_add(struct buffer *b, void *data, unsigned int size); +int buffer_add(struct buffer *b, void *data, size_t size); void buffer_flush(struct buffer *b, void (*cb)(void *buffer_data, void *data), void *data); -unsigned int buffer_size(const struct buffer *b); +size_t buffer_size(const struct buffer *b); #endif diff --git a/include/conntrackd.h b/include/conntrackd.h index 418f4b7..bb4b183 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -95,7 +95,7 @@ struct ct_conf { struct { char logfile[FILENAME_MAXLEN]; int syslog_facility; - unsigned int buffer_size; + size_t buffer_size; } stats; }; diff --git a/src/buffer.c b/src/buffer.c index adde81c..389dd38 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -20,7 +20,7 @@ #include #include "buffer.h" -struct buffer *buffer_create(unsigned int size) +struct buffer *buffer_create(size_t size) { struct buffer *b; @@ -47,7 +47,7 @@ void buffer_destroy(struct buffer *b) free(b); } -int buffer_add(struct buffer *b, void *data, unsigned int size) +int buffer_add(struct buffer *b, void *data, size_t size) { if (b->size - b->cur_size < size) { errno = ENOSPC; @@ -68,7 +68,7 @@ void buffer_flush(struct buffer *b, memset(b->data, 0, b->size); } -unsigned int buffer_size(const struct buffer *b) +size_t buffer_size(const struct buffer *b) { return b->size; } -- cgit v1.2.3 From 001805d9998229534264758432c06295614f8e2a Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Thu, 17 Jan 2008 17:36:32 +0000 Subject: Max Kellermann : import only required C headers and put local headers on top to check --- ChangeLog | 1 + extensions/libct_proto_icmp.c | 4 +++- extensions/libct_proto_udp.c | 1 - include/alarm.h | 2 ++ include/cache.h | 1 - include/conntrack.h | 1 - include/conntrackd.h | 9 +-------- include/ignore.h | 2 ++ include/linux_list.h | 2 ++ include/local.h | 2 -- include/network.h | 2 ++ include/queue.h | 3 --- src/alarm.c | 7 ------- src/buffer.c | 4 +++- src/cache.c | 6 ++++-- src/cache_iterators.c | 5 +++-- src/cache_lifetime.c | 2 -- src/cache_timer.c | 7 ++++--- src/cache_wt.c | 6 +++--- src/conntrack.c | 12 +++--------- src/hash.c | 8 +++----- src/ignore_pool.c | 5 +++-- src/local.c | 7 ++++--- src/log.c | 8 +++----- src/main.c | 8 ++++---- src/mcast.c | 10 ++++------ src/netlink.c | 8 +------- src/network.c | 5 +++-- src/parse.c | 4 ++-- src/queue.c | 4 ++++ src/read_config_lex.l | 1 - src/read_config_yy.y | 1 + src/run.c | 7 ++----- src/stats-mode.c | 11 +++++------ src/sync-alarm.c | 3 +++ src/sync-ftfw.c | 7 +++---- src/sync-mode.c | 14 +++++++------- src/traffic_stats.c | 7 ------- 38 files changed, 85 insertions(+), 112 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index e0a0da7..f84f7aa 100644 --- a/ChangeLog +++ b/ChangeLog @@ -81,6 +81,7 @@ o fix harmless error condition o add buffer_destroy() to buffer.c o fix memory leaks in several error output paths o use size_t for buffer sizes +o import only required C headers and put local headers on top to check version 0.9.5 (2007/07/29) ------------------------------ diff --git a/extensions/libct_proto_icmp.c b/extensions/libct_proto_icmp.c index 7c59072..f81c3b4 100644 --- a/extensions/libct_proto_icmp.c +++ b/extensions/libct_proto_icmp.c @@ -8,6 +8,9 @@ * (at your option) any later version. * */ + +#include "conntrack.h" + #include #include #include @@ -15,7 +18,6 @@ #include #include #include -#include "conntrack.h" static struct option opts[] = { {"icmp-type", 1, 0, '1'}, diff --git a/extensions/libct_proto_udp.c b/extensions/libct_proto_udp.c index 267e3d6..a72f9cf 100644 --- a/extensions/libct_proto_udp.c +++ b/extensions/libct_proto_udp.c @@ -10,7 +10,6 @@ #include #include #include -#include #include /* For htons */ #include #include diff --git a/include/alarm.h b/include/alarm.h index 338968a..532084a 100644 --- a/include/alarm.h +++ b/include/alarm.h @@ -3,6 +3,8 @@ #include "linux_list.h" +#include + struct alarm_list { struct list_head head; struct timeval tv; diff --git a/include/cache.h b/include/cache.h index 0743d3f..a2b2005 100644 --- a/include/cache.h +++ b/include/cache.h @@ -3,7 +3,6 @@ #include #include -#include /* cache features */ enum { diff --git a/include/conntrack.h b/include/conntrack.h index d6b6150..63facf4 100644 --- a/include/conntrack.h +++ b/include/conntrack.h @@ -2,7 +2,6 @@ #define _CONNTRACK_H #include "linux_list.h" -#include #include #include diff --git a/include/conntrackd.h b/include/conntrackd.h index bb4b183..c16d3d7 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -6,14 +6,7 @@ #include #include -#include -#include "cache.h" -#include "buffer.h" -#include "debug.h" -#include -#include "state_helper.h" -#include "linux_list.h" -#include +#include #include /* UNIX facilities */ diff --git a/include/ignore.h b/include/ignore.h index f1c2846..efb375d 100644 --- a/include/ignore.h +++ b/include/ignore.h @@ -3,6 +3,8 @@ #include +struct nf_conntrack; + struct ignore_pool { struct hashtable *h; }; diff --git a/include/linux_list.h b/include/linux_list.h index b84b1c4..de182a4 100644 --- a/include/linux_list.h +++ b/include/linux_list.h @@ -1,6 +1,8 @@ #ifndef _LINUX_LIST_H #define _LINUX_LIST_H +#include + #undef offsetof #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) diff --git a/include/local.h b/include/local.h index aae73a7..be77d35 100644 --- a/include/local.h +++ b/include/local.h @@ -1,8 +1,6 @@ #ifndef _LOCAL_SOCKET_H_ #define _LOCAL_SOCKET_H_ -#include - #ifndef UNIX_PATH_MAX #define UNIX_PATH_MAX 108 #endif diff --git a/include/network.h b/include/network.h index f9976dd..6dfd79d 100644 --- a/include/network.h +++ b/include/network.h @@ -3,6 +3,8 @@ #include +struct nf_conntrack; + struct nethdr { uint16_t flags; uint16_t len; diff --git a/include/queue.h b/include/queue.h index ab04d62..9a5d7b8 100644 --- a/include/queue.h +++ b/include/queue.h @@ -1,9 +1,6 @@ #ifndef _QUEUE_H_ #define _QUEUE_H_ -#include -#include -#include #include "linux_list.h" struct queue { diff --git a/src/alarm.c b/src/alarm.c index d00e281..576839a 100644 --- a/src/alarm.c +++ b/src/alarm.c @@ -16,14 +16,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include -#include -#include "linux_list.h" -#include "conntrackd.h" #include "alarm.h" -#include "jhash.h" -#include -#include static LIST_HEAD(alarm_list); diff --git a/src/buffer.c b/src/buffer.c index 389dd38..739174a 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -15,10 +15,12 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "buffer.h" + #include #include #include -#include "buffer.h" struct buffer *buffer_create(size_t size) { diff --git a/src/cache.c b/src/cache.c index dcb0123..2f0e57a 100644 --- a/src/cache.c +++ b/src/cache.c @@ -16,14 +16,16 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "cache.h" #include "jhash.h" #include "hash.h" +#include "us-conntrack.h" #include "conntrackd.h" + #include #include -#include "us-conntrack.h" -#include "cache.h" #include +#include static uint32_t hash(const void *data, struct hashtable *table) { diff --git a/src/cache_iterators.c b/src/cache_iterators.c index 4fdb920..bf70dd1 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -17,14 +17,15 @@ */ #include "cache.h" -#include "jhash.h" #include "hash.h" #include "log.h" #include "conntrackd.h" #include "netlink.h" +#include "us-conntrack.h" + #include #include -#include "us-conntrack.h" +#include struct __dump_container { int fd; diff --git a/src/cache_lifetime.c b/src/cache_lifetime.c index 26496d2..ad3416a 100644 --- a/src/cache_lifetime.c +++ b/src/cache_lifetime.c @@ -17,10 +17,8 @@ */ #include -#include "conntrackd.h" #include "us-conntrack.h" #include "cache.h" -#include "alarm.h" #include #include diff --git a/src/cache_timer.c b/src/cache_timer.c index 53ed703..0fbba14 100644 --- a/src/cache_timer.c +++ b/src/cache_timer.c @@ -16,12 +16,13 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include -#include +#include "cache.h" #include "conntrackd.h" #include "us-conntrack.h" -#include "cache.h" #include "alarm.h" +#include "debug.h" + +#include static void timeout(struct alarm_list *a, void *data) { diff --git a/src/cache_wt.c b/src/cache_wt.c index 9d0af0b..8ff8fae 100644 --- a/src/cache_wt.c +++ b/src/cache_wt.c @@ -16,11 +16,11 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "cache.h" #include "netlink.h" -#include -#include "conntrackd.h" #include "us-conntrack.h" -#include "cache.h" + +#include static void add_update(struct us_conntrack *u) { diff --git a/src/conntrack.c b/src/conntrack.c index 7918b3f..5f0cb1a 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -33,9 +33,10 @@ * Ported to the new libnetfilter_conntrack API * */ + +#include "conntrack.h" + #include -#include -#include #include #include #include @@ -43,22 +44,15 @@ #include #include #include -#include #include #include #include #ifdef HAVE_ARPA_INET_H #include #endif -#include -#include #include #include -#include "linux_list.h" -#include "conntrack.h" #include -#include -#include static const char cmdflags[NUMBER_OF_CMD] = {'L','I','U','D','G','F','E','V','h','L','I','D','G','F','E'}; diff --git a/src/hash.c b/src/hash.c index d7724c8..cf64df4 100644 --- a/src/hash.c +++ b/src/hash.c @@ -18,14 +18,12 @@ * Description: generic hash table implementation */ -#include +#include "hash.h" +#include "slist.h" + #include #include -#include #include -#include "slist.h" -#include "hash.h" - struct hashtable_node *hashtable_alloc_node(int datasize, void *data) { diff --git a/src/ignore_pool.c b/src/ignore_pool.c index 5889398..c77a55b 100644 --- a/src/ignore_pool.c +++ b/src/ignore_pool.c @@ -16,14 +16,15 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "ignore.h" #include "jhash.h" #include "hash.h" #include "conntrackd.h" -#include "ignore.h" #include "log.h" -#include +#include #include +#include /* XXX: These should be configurable */ #define IGNORE_POOL_SIZE 128 diff --git a/src/local.c b/src/local.c index d861e12..f0aba1c 100644 --- a/src/local.c +++ b/src/local.c @@ -18,12 +18,13 @@ * Description: UNIX sockets library */ +#include "local.h" + #include #include +#include #include -#include - -#include "local.h" +#include int local_server_create(struct local_conf *conf) { diff --git a/src/log.c b/src/log.c index 35ae0c3..a2d48a4 100644 --- a/src/log.c +++ b/src/log.c @@ -19,16 +19,14 @@ */ #include "log.h" -#include -#include -#include +#include "buffer.h" +#include "conntrackd.h" + #include #include #include #include #include -#include "buffer.h" -#include "conntrackd.h" int init_log(void) { diff --git a/src/main.c b/src/main.c index b860982..3d8cfe9 100644 --- a/src/main.c +++ b/src/main.c @@ -16,17 +16,17 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include "conntrackd.h" #include "log.h" + #include #include #include #include #include -#include -#include "hash.h" -#include "jhash.h" +#include +#include +#include #undef _POSIX_SOURCE #include diff --git a/src/mcast.c b/src/mcast.c index 9684b61..77aa35c 100644 --- a/src/mcast.c +++ b/src/mcast.c @@ -17,19 +17,17 @@ * * Description: multicast socket library */ + +#include "mcast.h" +#include "debug.h" + #include #include -#include #include -#include -#include -#include #include #include #include #include -#include "mcast.h" -#include "debug.h" struct mcast_sock *mcast_server_create(struct mcast_conf *conf) { diff --git a/src/netlink.c b/src/netlink.c index 388407a..0457e8a 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -21,13 +21,7 @@ #include "traffic_stats.h" #include "ignore.h" #include "log.h" -#include -#include -#include -#include "us-conntrack.h" -#include -#include -#include "network.h" +#include "debug.h" int ignore_conntrack(struct nf_conntrack *ct) { diff --git a/src/network.c b/src/network.c index 939e94b..7c7a08a 100644 --- a/src/network.c +++ b/src/network.c @@ -18,11 +18,12 @@ #include "conntrackd.h" #include "network.h" -#include "us-conntrack.h" -#include "sync.h" #include "log.h" +#include "debug.h" #include +#include +#include static unsigned int seq_set, cur_seq; diff --git a/src/parse.c b/src/parse.c index a248b47..5bc71ef 100644 --- a/src/parse.c +++ b/src/parse.c @@ -16,10 +16,10 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include -#include #include "network.h" +#include + static void parse_u8(struct nf_conntrack *ct, int attr, void *data) { uint8_t *value = (uint8_t *) data; diff --git a/src/queue.c b/src/queue.c index a721760..7b20e83 100644 --- a/src/queue.c +++ b/src/queue.c @@ -18,6 +18,10 @@ #include "queue.h" +#include +#include +#include + struct queue *queue_create(size_t max_size) { struct queue *b; diff --git a/src/read_config_lex.l b/src/read_config_lex.l index 6211fee..65df1e7 100644 --- a/src/read_config_lex.l +++ b/src/read_config_lex.l @@ -20,7 +20,6 @@ */ #include "read_config_yy.h" -#include "conntrackd.h" %} %option yylineno diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 82131d7..531b1fe 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -26,6 +26,7 @@ #include "conntrackd.h" #include "ignore.h" #include +#include extern struct state_replication_helper tcp_state_helper; diff --git a/src/run.c b/src/run.c index cb5116d..9076028 100644 --- a/src/run.c +++ b/src/run.c @@ -23,16 +23,13 @@ #include "ignore.h" #include "log.h" #include "alarm.h" -#include + #include -#include "us-conntrack.h" #include #include #include -#include #include -#include -#include +#include void killer(int foo) { diff --git a/src/stats-mode.c b/src/stats-mode.c index 0c42d95..0ecb2b0 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -18,16 +18,15 @@ #include "netlink.h" #include "traffic_stats.h" -#include +#include "buffer.h" +#include "debug.h" #include "cache.h" #include "log.h" #include "conntrackd.h" -#include -#include + #include -#include "us-conntrack.h" -#include -#include +#include +#include static int init_stats(void) { diff --git a/src/sync-alarm.c b/src/sync-alarm.c index 05ddf81..6ee306e 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -21,8 +21,11 @@ #include "network.h" #include "us-conntrack.h" #include "alarm.h" +#include "cache.h" +#include "debug.h" #include +#include static void refresher(struct alarm_list *a, void *data) { diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index f0b3262..f6d2ed3 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -16,18 +16,17 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include "conntrackd.h" #include "sync.h" -#include "linux_list.h" #include "us-conntrack.h" #include "queue.h" #include "debug.h" #include "network.h" #include "alarm.h" #include "log.h" -#include -#include +#include "cache.h" + +#include #if 0 #define dp printf diff --git a/src/sync-mode.c b/src/sync-mode.c index 1632019..0a0fcc2 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -16,22 +16,22 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "sync.h" #include "netlink.h" #include "traffic_stats.h" #include "log.h" -#include +#include "state_helper.h" #include "cache.h" #include "conntrackd.h" -#include -#include -#include #include "us-conntrack.h" -#include -#include -#include "sync.h" #include "network.h" #include "debug.h" + +#include #include +#include +#include +#include static void do_mcast_handler_step(struct nethdr *net) { diff --git a/src/traffic_stats.c b/src/traffic_stats.c index 93511ce..9e40d53 100644 --- a/src/traffic_stats.c +++ b/src/traffic_stats.c @@ -17,14 +17,7 @@ */ #include "traffic_stats.h" -#include "cache.h" -#include "hash.h" #include "conntrackd.h" -#include -#include -#include -#include "us-conntrack.h" -#include void update_traffic_stats(struct nf_conntrack *ct) { -- cgit v1.2.3 From 1f2483506ca384e87158d44fa2d9db53daeb11c9 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Thu, 17 Jan 2008 17:37:27 +0000 Subject: Max Kellermann : remove superfluous initialization --- ChangeLog | 1 + src/conntrack.c | 2 +- src/mcast.c | 3 ++- src/sync-mode.c | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index f84f7aa..5ba7041 100644 --- a/ChangeLog +++ b/ChangeLog @@ -82,6 +82,7 @@ o add buffer_destroy() to buffer.c o fix memory leaks in several error output paths o use size_t for buffer sizes o import only required C headers and put local headers on top to check +o remove superfluous initialization version 0.9.5 (2007/07/29) ------------------------------ diff --git a/src/conntrack.c b/src/conntrack.c index 5f0cb1a..f170bed 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -156,7 +156,7 @@ void register_proto(struct ctproto_handler *h) static struct ctproto_handler *findproto(char *name) { - struct ctproto_handler *cur = NULL, *handler = NULL; + struct ctproto_handler *cur, *handler = NULL; if (!name) return handler; diff --git a/src/mcast.c b/src/mcast.c index 77aa35c..414f031 100644 --- a/src/mcast.c +++ b/src/mcast.c @@ -191,7 +191,7 @@ __mcast_client_create_ipv6(struct mcast_sock *m, struct mcast_conf *conf) struct mcast_sock *mcast_client_create(struct mcast_conf *conf) { - int ret = 0; + int ret; struct mcast_sock *m; m = (struct mcast_sock *) malloc(sizeof(struct mcast_sock)); @@ -221,6 +221,7 @@ struct mcast_sock *mcast_client_create(struct mcast_conf *conf) ret = __mcast_client_create_ipv6(m, conf); break; default: + ret = 0; break; } diff --git a/src/sync-mode.c b/src/sync-mode.c index 0a0fcc2..dc8e782 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -39,7 +39,7 @@ static void do_mcast_handler_step(struct nethdr *net) struct netpld *pld = NETHDR_DATA(net); char __ct[nfct_maxsize()]; struct nf_conntrack *ct = (struct nf_conntrack *)(void*) __ct; - struct us_conntrack *u = NULL; + struct us_conntrack *u; if (STATE_SYNC(sync)->recv(net)) return; -- cgit v1.2.3 From f77677c542c1b42d6a76cd114ae8f2ea6b07641e Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Thu, 17 Jan 2008 17:43:38 +0000 Subject: Max Kellermann : eliminate local variable by returning from the loop --- ChangeLog | 1 + src/conntrack.c | 12 +++++------- 2 files changed, 6 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 5ba7041..01dcc05 100644 --- a/ChangeLog +++ b/ChangeLog @@ -55,6 +55,7 @@ o use C99 integers (uint32_t instead of u_int32_t) = conntrack = o check for malloc() failure in merge_opts +o eliminate local variable by returning from the loop = conntrackd = o resolve global variable "alarm" conflict with alarm() function in unistd.h. diff --git a/src/conntrack.c b/src/conntrack.c index f170bed..4d0642c 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -156,19 +156,17 @@ void register_proto(struct ctproto_handler *h) static struct ctproto_handler *findproto(char *name) { - struct ctproto_handler *cur, *handler = NULL; + struct ctproto_handler *cur; if (!name) - return handler; + return NULL; list_for_each_entry(cur, &proto_list, head) { - if (strcmp(cur->name, name) == 0) { - handler = cur; - break; - } + if (strcmp(cur->name, name) == 0) + return cur; } - return handler; + return NULL; } static void -- cgit v1.2.3 From 287c0f46e3499404d8e3bc35f7ae53f8fb678a1f Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Thu, 17 Jan 2008 17:45:25 +0000 Subject: Max Kellermann : fix double free() bug in the error output path of mcast_create() --- ChangeLog | 1 + src/mcast.c | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 01dcc05..2d6cc3e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -84,6 +84,7 @@ o fix memory leaks in several error output paths o use size_t for buffer sizes o import only required C headers and put local headers on top to check o remove superfluous initialization +o fix double free() bug in the error output path of mcast_create() version 0.9.5 (2007/07/29) ------------------------------ diff --git a/src/mcast.c b/src/mcast.c index 414f031..e977c0b 100644 --- a/src/mcast.c +++ b/src/mcast.c @@ -152,7 +152,6 @@ __mcast_client_create_ipv4(struct mcast_sock *m, struct mcast_conf *conf) sizeof(struct in_addr)) == -1) { debug("mcast_sock_client_create:setsockopt3"); close(m->fd); - free(m); return -1; } @@ -182,7 +181,6 @@ __mcast_client_create_ipv6(struct mcast_sock *m, struct mcast_conf *conf) sizeof(struct in_addr)) == -1) { debug("mcast_sock_client_create:setsockopt3"); close(m->fd); - free(m); return -1; } -- cgit v1.2.3 From 7f8a8c370aec18f421159bfc2f8c5002cff48d9d Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Thu, 17 Jan 2008 17:49:28 +0000 Subject: Max Kellermann : explicitly cast in nat_parse() Previous commit was an error --- src/conntrack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index 4d0642c..82ff544 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -473,7 +473,7 @@ nat_parse(char *arg, int portok, struct nf_conntrack *obj, int type) exit_error(PARAMETER_PROBLEM, "Need TCP or UDP with port specification"); - port = atoi(colon+1); + port = (uint16_t)atoi(colon+1); if (port == 0) exit_error(PARAMETER_PROBLEM, "Port `%s' not valid\n", colon+1); -- cgit v1.2.3 From 10ff3f6d075a3ef000f87912d2c400e8a8818206 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Fri, 18 Jan 2008 12:37:28 +0000 Subject: Max Kellermann : there is no need to check capabilities - the socket() call will fail a few lines later anyway, producing an error message which is good enough. --- ChangeLog | 1 + src/main.c | 52 ---------------------------------------------------- 2 files changed, 1 insertion(+), 52 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 02f6668..661ebe3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -87,6 +87,7 @@ o use size_t for buffer sizes o import only required C headers and put local headers on top to check o fix double free() bug in the error output path of mcast_create() o eliminate unsed cache_get_conntrack() in rs_list_to_tx() +o remove capability code and rely on the error returned by the syscall version 0.9.5 (2007/07/29) ------------------------------ diff --git a/src/main.c b/src/main.c index 3d8cfe9..0aa5317 100644 --- a/src/main.c +++ b/src/main.c @@ -23,14 +23,10 @@ #include #include #include -#include #include #include #include -#undef _POSIX_SOURCE -#include - struct ct_general_state st; union ct_state state; @@ -79,39 +75,6 @@ set_operation_mode(int *current, int want, char *argv[]) } } -static int check_capabilities(void) -{ - int ret; - cap_user_header_t hcap; - cap_user_data_t dcap; - - hcap = malloc(sizeof(cap_user_header_t)); - if (!hcap) - return -1; - - hcap->version = _LINUX_CAPABILITY_VERSION; - hcap->pid = getpid(); - - dcap = malloc(sizeof(cap_user_data_t)); - if (!dcap) { - free(hcap); - return -1; - } - - if (capget(hcap, dcap) == -1) { - free(hcap); - free(dcap); - return -1; - } - - ret = dcap->permitted & (1 << CAP_NET_ADMIN); - - free(hcap); - free(dcap); - - return ret; -} - int main(int argc, char *argv[]) { int ret, i, config_set = 0, action = -1; @@ -136,21 +99,6 @@ int main(int argc, char *argv[]) exit(EXIT_FAILURE); } - ret = check_capabilities(); - switch (ret) { - case -1: - fprintf(stderr, "Can't get capabilities\n"); - exit(EXIT_FAILURE); - break; - case 0: - fprintf(stderr, "You require CAP_NET_ADMIN in order " - "to run conntrackd\n"); - exit(EXIT_FAILURE); - break; - default: - break; - } - for (i=1; i Date: Fri, 18 Jan 2008 12:38:27 +0000 Subject: Max Kellermann : Use fputs() instead of fprintf() --- ChangeLog | 1 + src/log.c | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 661ebe3..a9dfd8b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -88,6 +88,7 @@ o import only required C headers and put local headers on top to check o fix double free() bug in the error output path of mcast_create() o eliminate unsed cache_get_conntrack() in rs_list_to_tx() o remove capability code and rely on the error returned by the syscall +o use fputs() instead of fprintf() in log.c version 0.9.5 (2007/07/29) ------------------------------ diff --git a/src/log.c b/src/log.c index a2d48a4..41b2057 100644 --- a/src/log.c +++ b/src/log.c @@ -104,7 +104,7 @@ void dlog_buffered_ct_flush(void *buffer_data, void *data) { FILE *fd = data; - fprintf(fd, "%s", (const char*)buffer_data); + fputs((const char*)buffer_data, fd); fflush(fd); } @@ -124,7 +124,7 @@ void dlog_buffered_ct(FILE *fd, struct buffer *b, struct nf_conntrack *ct) snprintf(buf+strlen(buf), 1024-strlen(buf), "\n"); /* zero size buffer: force fflush */ if (buffer_size(b) == 0) { - fprintf(fd, "%s", buf); + fputs(buf, fd); fflush(fd); } @@ -132,7 +132,7 @@ void dlog_buffered_ct(FILE *fd, struct buffer *b, struct nf_conntrack *ct) buffer_flush(b, dlog_buffered_ct_flush, fd); if (buffer_add(b, buf, strlen(buf)) == -1) { /* buffer too small, catacrocket! */ - fprintf(fd, "%s", buf); + fputs(buf, fd); fflush(fd); } } -- cgit v1.2.3 From 91d431dacd79d93d671ace690e2e9c7fbb0f2877 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Fri, 18 Jan 2008 13:09:49 +0000 Subject: Max Kellermann : Simplify logging infrastructure --- ChangeLog | 4 +-- doc/stats/conntrackd.conf | 10 ------- include/Makefile.am | 2 +- include/buffer.h | 22 -------------- include/conntrackd.h | 1 - include/log.h | 6 ++-- src/Makefile.am | 2 +- src/buffer.c | 76 ----------------------------------------------- src/cache_iterators.c | 10 +++---- src/ignore_pool.c | 2 +- src/log.c | 34 ++++++--------------- src/main.c | 4 +-- src/netlink.c | 28 ++++++++--------- src/network.c | 2 +- src/read_config_yy.y | 2 +- src/run.c | 24 +++++++-------- src/stats-mode.c | 30 +++++-------------- src/sync-ftfw.c | 8 ++--- src/sync-mode.c | 32 ++++++++++---------- 19 files changed, 78 insertions(+), 221 deletions(-) delete mode 100644 include/buffer.h delete mode 100644 src/buffer.c (limited to 'src') diff --git a/ChangeLog b/ChangeLog index a9dfd8b..25c8c38 100644 --- a/ChangeLog +++ b/ChangeLog @@ -31,7 +31,6 @@ o add support for related conntracks (requires Linux kernel >= 2.6.22) o show error and warning messages to stderr o hash lookup speedups based on comments from netdev's discussions o add support for connection logging to the statistics mode via Logfile -o implement buffered connection logging to improve performance o minor irrelevant fixes for uncommon error paths and fix several typos o detach daemon from its terminal (Ben Lenitz ) o obsolete `-S' option: Use information provided by the config file @@ -81,13 +80,12 @@ o always close stdin - even in non-daemon mode, it is of no use o chdir("/") to release the cwd inode o ignore setsid() failure, because there is only one possible and o fix harmless error condition -o add buffer_destroy() to buffer.c o fix memory leaks in several error output paths -o use size_t for buffer sizes o import only required C headers and put local headers on top to check o fix double free() bug in the error output path of mcast_create() o eliminate unsed cache_get_conntrack() in rs_list_to_tx() o remove capability code and rely on the error returned by the syscall +o major simplification of the logging infrastructure o use fputs() instead of fprintf() in log.c version 0.9.5 (2007/07/29) diff --git a/doc/stats/conntrackd.conf b/doc/stats/conntrackd.conf index 8f899b4..4bc5642 100644 --- a/doc/stats/conntrackd.conf +++ b/doc/stats/conntrackd.conf @@ -58,16 +58,6 @@ Stats { # LogFile on - # - # Set Logfile buffer size. Default is 0. - # You can set the size of the connection logging buffer size. This - # value determines how often the logging information is written to - # the harddisk. High values improves performances. If your firewall - # is very busy and you need connection logging, use a big buffer. - # Default buffer size is 0 that means direct write through. - # - #LogFileBufferSize 4096 - # # Enable connection logging via Syslog. Default is off. # Syslog: on, off or a facility name (daemon (default) or local0..7) diff --git a/include/Makefile.am b/include/Makefile.am index ff8611f..e8e7f81 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -1,7 +1,7 @@ noinst_HEADERS = alarm.h jhash.h slist.h cache.h linux_list.h \ sync.h conntrackd.h local.h us-conntrack.h \ - debug.h log.h hash.h mcast.h buffer.h conntrack.h \ + debug.h log.h hash.h mcast.h conntrack.h \ state_helper.h network.h ignore.h queue.h \ traffic_stats.h netlink.h diff --git a/include/buffer.h b/include/buffer.h deleted file mode 100644 index ab1ccd3..0000000 --- a/include/buffer.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef _BUFFER_H_ -#define _BUFFER_H_ - -#include - -struct buffer { - unsigned char *data; - size_t size; - size_t cur_size; -}; - -struct buffer *buffer_create(size_t size); -void buffer_destroy(struct buffer *b); - -int buffer_add(struct buffer *b, void *data, size_t size); -void buffer_flush(struct buffer *b, - void (*cb)(void *buffer_data, - void *data), - void *data); -size_t buffer_size(const struct buffer *b); - -#endif diff --git a/include/conntrackd.h b/include/conntrackd.h index c16d3d7..b223a17 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -132,7 +132,6 @@ struct ct_sync_state { struct ct_stats_state { struct cache *cache; /* internal events cache (netlink) */ - struct buffer *buffer_log; }; union ct_state { diff --git a/include/log.h b/include/log.h index 64bf1ce..b258633 100644 --- a/include/log.h +++ b/include/log.h @@ -3,13 +3,11 @@ #include -struct buffer; struct nf_conntrack; int init_log(void); -void dlog(FILE *fd, int priority, const char *format, ...); -void dlog_buffered_ct(FILE *fd, struct buffer *b, struct nf_conntrack *ct); -void dlog_buffered_ct_flush(void *buffer_data, void *data); +void dlog(int priority, const char *format, ...); +void dlog_ct(struct nf_conntrack *ct); void close_log(void); #endif diff --git a/src/Makefile.am b/src/Makefile.am index fafb5ff..15628b7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -10,7 +10,7 @@ conntrack_SOURCES = conntrack.c conntrack_LDADD = ../extensions/libct_proto_tcp.la ../extensions/libct_proto_udp.la ../extensions/libct_proto_icmp.la conntrack_LDFLAGS = $(all_libraries) @LIBNETFILTER_CONNTRACK_LIBS@ -conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c buffer.c \ +conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c \ local.c log.c mcast.c netlink.c \ ignore_pool.c \ cache.c cache_iterators.c \ diff --git a/src/buffer.c b/src/buffer.c deleted file mode 100644 index 739174a..0000000 --- a/src/buffer.c +++ /dev/null @@ -1,76 +0,0 @@ -/* - * (C) 2006-2008 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "buffer.h" - -#include -#include -#include - -struct buffer *buffer_create(size_t size) -{ - struct buffer *b; - - b = malloc(sizeof(struct buffer)); - if (b == NULL) - return NULL; - memset(b, 0, sizeof(struct buffer)); - - b->size = size; - - b->data = malloc(size); - if (b->data == NULL) { - free(b); - return NULL; - } - memset(b->data, 0, size); - - return b; -} - -void buffer_destroy(struct buffer *b) -{ - free(b->data); - free(b); -} - -int buffer_add(struct buffer *b, void *data, size_t size) -{ - if (b->size - b->cur_size < size) { - errno = ENOSPC; - return -1; - } - - memcpy(b->data + b->cur_size, data, size); - b->cur_size += size; - return 0; -} - -void buffer_flush(struct buffer *b, - void (*cb)(void *buffer_data, void *data), - void *data) -{ - cb(b->data, data); - b->cur_size = 0; - memset(b->data, 0, b->size); -} - -size_t buffer_size(const struct buffer *b) -{ - return b->size; -} diff --git a/src/cache_iterators.c b/src/cache_iterators.c index bf70dd1..92b7b7f 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -123,14 +123,14 @@ void cache_commit(struct cache *c) commit_exist = c->commit_exist - commit_exist; /* log results */ - dlog(STATE(log), LOG_NOTICE, "Committed %u new entries", commit_ok); + dlog(LOG_NOTICE, "Committed %u new entries", commit_ok); if (commit_exist) - dlog(STATE(log), LOG_NOTICE, "%u entries ignored, " - "already exist", commit_exist); + dlog(LOG_NOTICE, "%u entries ignored, " + "already exist", commit_exist); if (commit_fail) - dlog(STATE(log), LOG_NOTICE, "%u entries can't be " - "committed", commit_fail); + dlog(LOG_NOTICE, "%u entries can't be " + "committed", commit_fail); } static int do_flush(void *data1, void *data2) diff --git a/src/ignore_pool.c b/src/ignore_pool.c index c77a55b..2d898d1 100644 --- a/src/ignore_pool.c +++ b/src/ignore_pool.c @@ -133,7 +133,7 @@ int ignore_pool_test(struct ignore_pool *ip, struct nf_conntrack *ct) ret = __ignore_pool_test_ipv6(ip, ct); break; default: - dlog(STATE(log), LOG_WARNING, "unknown layer 3 protocol?"); + dlog(LOG_WARNING, "unknown layer 3 protocol?"); break; } diff --git a/src/log.c b/src/log.c index 41b2057..51e757f 100644 --- a/src/log.c +++ b/src/log.c @@ -19,7 +19,6 @@ */ #include "log.h" -#include "buffer.h" #include "conntrackd.h" #include @@ -38,6 +37,8 @@ int init_log(void) strerror(errno)); return -1; } + + setlinebuf(STATE(log)); } if (CONFIG(stats).logfile[0]) { @@ -48,6 +49,8 @@ int init_log(void) strerror(errno)); return -1; } + + setlinebuf(STATE(stats_log)); } if (CONFIG(syslog_facility) != -1 || @@ -57,8 +60,9 @@ int init_log(void) return 0; } -void dlog(FILE *fd, int priority, const char *format, ...) +void dlog(int priority, const char *format, ...) { + FILE *fd = STATE(log); time_t t; char *buf; const char *prio; @@ -100,16 +104,9 @@ void dlog(FILE *fd, int priority, const char *format, ...) } } -void dlog_buffered_ct_flush(void *buffer_data, void *data) -{ - FILE *fd = data; - - fputs((const char*)buffer_data, fd); - fflush(fd); -} - -void dlog_buffered_ct(FILE *fd, struct buffer *b, struct nf_conntrack *ct) +void dlog_ct(struct nf_conntrack *ct) { + FILE *fd = STATE(stats_log); time_t t; char buf[1024]; char *tmp; @@ -122,20 +119,7 @@ void dlog_buffered_ct(FILE *fd, struct buffer *b, struct nf_conntrack *ct) if (fd) { snprintf(buf+strlen(buf), 1024-strlen(buf), "\n"); - /* zero size buffer: force fflush */ - if (buffer_size(b) == 0) { - fputs(buf, fd); - fflush(fd); - } - - if (buffer_add(b, buf, strlen(buf)) == -1) { - buffer_flush(b, dlog_buffered_ct_flush, fd); - if (buffer_add(b, buf, strlen(buf)) == -1) { - /* buffer too small, catacrocket! */ - fputs(buf, fd); - fflush(fd); - } - } + fputs(buf, fd); } if (CONFIG(stats).syslog_facility != -1) diff --git a/src/main.c b/src/main.c index 0aa5317..8221564 100644 --- a/src/main.c +++ b/src/main.c @@ -250,9 +250,9 @@ int main(int argc, char *argv[]) close(STDOUT_FILENO); close(STDERR_FILENO); - dlog(STATE(log), LOG_NOTICE, "-- starting in daemon mode --"); + dlog(LOG_NOTICE, "-- starting in daemon mode --"); } else - dlog(STATE(log), LOG_NOTICE, "-- starting in console mode --"); + dlog(LOG_NOTICE, "-- starting in console mode --"); /* * run main process diff --git a/src/netlink.c b/src/netlink.c index 0457e8a..bb94001 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -73,7 +73,7 @@ static int event_handler(enum nf_conntrack_msg_type type, update_traffic_stats(ct); break; default: - dlog(STATE(log), LOG_WARNING, "unknown msg from ctnetlink\n"); + dlog(LOG_WARNING, "unknown msg from ctnetlink\n"); break; } @@ -134,7 +134,7 @@ static int dump_handler(enum nf_conntrack_msg_type type, STATE(mode)->dump(ct); break; default: - dlog(STATE(log), LOG_WARNING, "unknown msg from ctnetlink"); + dlog(LOG_WARNING, "unknown msg from ctnetlink"); break; } return NFCT_CB_CONTINUE; @@ -167,15 +167,15 @@ void nl_resize_socket_buffer(struct nfct_handle *h) return; if (s > CONFIG(netlink_buffer_size_max_grown)) { - dlog(STATE(log), LOG_WARNING, - "maximum netlink socket buffer " - "size has been reached. We are likely to " - "be losing events, this may lead to " - "unsynchronized replicas. Please, consider " - "increasing netlink socket buffer size via " - "SocketBufferSize and " - "SocketBufferSizeMaxGrown clauses in " - "conntrackd.conf"); + dlog(LOG_WARNING, + "maximum netlink socket buffer " + "size has been reached. We are likely to " + "be losing events, this may lead to " + "unsynchronized replicas. Please, consider " + "increasing netlink socket buffer size via " + "SocketBufferSize and " + "SocketBufferSizeMaxGrown clauses in " + "conntrackd.conf"); s = CONFIG(netlink_buffer_size_max_grown); warned = 1; } @@ -183,9 +183,9 @@ void nl_resize_socket_buffer(struct nfct_handle *h) CONFIG(netlink_buffer_size) = nfnl_rcvbufsiz(nfct_nfnlh(h), s); /* notify the sysadmin */ - dlog(STATE(log), LOG_NOTICE, "netlink socket buffer size " - "has been set to %u bytes", - CONFIG(netlink_buffer_size)); + dlog(LOG_NOTICE, "netlink socket buffer size " + "has been set to %u bytes", + CONFIG(netlink_buffer_size)); } int nl_dump_conntrack_table(void) diff --git a/src/network.c b/src/network.c index 7c7a08a..da26545 100644 --- a/src/network.c +++ b/src/network.c @@ -222,7 +222,7 @@ int mcast_track_seq(uint32_t seq, uint32_t *exp_seq) /* out of sequence: replayed/delayed packet? */ if (before(seq, STATE_SYNC(last_seq_recv)+1)) - dlog(STATE(log), LOG_WARNING, "delayed packet? exp=%u rcv=%u", + dlog(LOG_WARNING, "delayed packet? exp=%u rcv=%u", STATE_SYNC(last_seq_recv)+1, seq); out: diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 531b1fe..0ba5331 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -635,7 +635,7 @@ stat_syslog_facility : T_SYSLOG T_STRING buffer_size: T_STAT_BUFFER_SIZE T_NUMBER { - conf.stats.buffer_size = $2; + fprintf(stderr, "WARNING: LogFileBufferSize is deprecated.\n"); }; %% diff --git a/src/run.c b/src/run.c index 9076028..a5b6a79 100644 --- a/src/run.c +++ b/src/run.c @@ -43,7 +43,7 @@ void killer(int foo) local_server_destroy(STATE(local), CONFIG(local).path); STATE(mode)->kill(); unlink(CONFIG(lockfile)); - dlog(STATE(log), LOG_NOTICE, "---- shutdown received ----"); + dlog(LOG_NOTICE, "---- shutdown received ----"); close_log(); sigprocmask(SIG_UNBLOCK, &STATE(block), NULL); @@ -63,7 +63,7 @@ void local_handler(int fd, void *data) ret = read(fd, &type, sizeof(type)); if (ret == -1) { - dlog(STATE(log), LOG_ERR, "can't read from unix socket"); + dlog(LOG_ERR, "can't read from unix socket"); return; } if (ret == 0) @@ -71,7 +71,7 @@ void local_handler(int fd, void *data) switch(type) { case FLUSH_MASTER: - dlog(STATE(log), LOG_WARNING, "`conntrackd -F' is deprecated. " + dlog(LOG_WARNING, "`conntrackd -F' is deprecated. " "Use conntrack -F instead."); if (fork() == 0) { execlp("conntrack", "conntrack", "-F", NULL); @@ -79,13 +79,13 @@ void local_handler(int fd, void *data) } return; case RESYNC_MASTER: - dlog(STATE(log), LOG_NOTICE, "resync with master table"); + dlog(LOG_NOTICE, "resync with master table"); nl_dump_conntrack_table(); return; } if (!STATE(mode)->local(fd, type, data)) - dlog(STATE(log), LOG_WARNING, "unknown local request %d", type); + dlog(LOG_WARNING, "unknown local request %d", type); } int @@ -104,25 +104,25 @@ init(void) /* Initialization */ if (STATE(mode)->init() == -1) { - dlog(STATE(log), LOG_ERR, "initialization failed"); + dlog(LOG_ERR, "initialization failed"); return -1; } /* local UNIX socket */ STATE(local) = local_server_create(&CONFIG(local)); if (!STATE(local)) { - dlog(STATE(log), LOG_ERR, "can't open unix socket!"); + dlog(LOG_ERR, "can't open unix socket!"); return -1; } if (nl_init_event_handler() == -1) { - dlog(STATE(log), LOG_ERR, "can't open netlink handler! " + dlog(LOG_ERR, "can't open netlink handler! " "no ctnetlink kernel support?"); return -1; } if (nl_init_dump_handler() == -1) { - dlog(STATE(log), LOG_ERR, "can't open netlink handler! " + dlog(LOG_ERR, "can't open netlink handler! " "no ctnetlink kernel support?"); return -1; } @@ -146,7 +146,7 @@ init(void) if (signal(SIGCHLD, child) == SIG_ERR) return -1; - dlog(STATE(log), LOG_NOTICE, "initialization completed"); + dlog(LOG_NOTICE, "initialization completed"); return 0; } @@ -171,7 +171,7 @@ static int __run(struct timeval *next_alarm) if (errno == EINTR) return 0; - dlog(STATE(log), LOG_WARNING, + dlog(LOG_WARNING, "select failed: %s", strerror(errno)); return 0; } @@ -213,7 +213,7 @@ static int __run(struct timeval *next_alarm) case EAGAIN: break; default: - dlog(STATE(log), LOG_WARNING, + dlog(LOG_WARNING, "event catch says: %s", strerror(errno)); break; } diff --git a/src/stats-mode.c b/src/stats-mode.c index 0ecb2b0..9e6089c 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -18,7 +18,6 @@ #include "netlink.h" #include "traffic_stats.h" -#include "buffer.h" #include "debug.h" #include "cache.h" #include "log.h" @@ -32,27 +31,19 @@ static int init_stats(void) { state.stats = malloc(sizeof(struct ct_stats_state)); if (!state.stats) { - dlog(STATE(log), LOG_ERR, "can't allocate memory for stats"); + dlog(LOG_ERR, "can't allocate memory for stats"); return -1; } memset(state.stats, 0, sizeof(struct ct_stats_state)); - STATE_STATS(buffer_log) = buffer_create(CONFIG(stats).buffer_size); - if (!STATE_STATS(buffer_log)) { - dlog(STATE(log), LOG_ERR, "can't allocate stats buffer"); - free(state.stats); - return -1; - } - STATE_STATS(cache) = cache_create("stats", LIFETIME, CONFIG(family), NULL); if (!STATE_STATS(cache)) { - dlog(STATE(log), LOG_ERR, "can't allocate memory for the " - "external cache"); + dlog(LOG_ERR, "can't allocate memory for the " + "external cache"); free(state.stats); - buffer_destroy(STATE_STATS(buffer_log)); return -1; } @@ -62,11 +53,6 @@ static int init_stats(void) static void kill_stats(void) { cache_destroy(STATE_STATS(cache)); - /* flush the buffer before exiting */ - if (STATE(stats_log) != NULL) - buffer_flush(STATE_STATS(buffer_log), - dlog_buffered_ct_flush, - STATE(stats_log)); } /* handler for requests coming via UNIX socket */ @@ -82,7 +68,7 @@ static int local_handler_stats(int fd, int type, void *data) cache_dump(STATE_STATS(cache), fd, NFCT_O_XML); break; case FLUSH_CACHE: - dlog(STATE(log), LOG_NOTICE, "flushing caches"); + dlog(LOG_NOTICE, "flushing caches"); cache_flush(STATE_STATS(cache)); break; case KILL: @@ -138,7 +124,7 @@ static void overrun_stats(void) h = nfct_open(CONNTRACK, 0); if (!h) { - dlog(STATE(log), LOG_ERR, "can't open overrun handler"); + dlog(LOG_ERR, "can't open overrun handler"); return; } @@ -148,7 +134,7 @@ static void overrun_stats(void) ret = nfct_query(h, NFCT_Q_DUMP, &family); if (ret == -1) - dlog(STATE(log), LOG_ERR, + dlog(LOG_ERR, "overrun query error %s", strerror(errno)); nfct_close(h); @@ -162,7 +148,7 @@ static void event_new_stats(struct nf_conntrack *ct) debug_ct(ct, "cache new"); } else { if (errno != EEXIST) { - dlog(STATE(log), LOG_ERR, + dlog(LOG_ERR, "can't add to cache cache: %s\n", strerror(errno)); debug_ct(ct, "can't add"); } @@ -186,7 +172,7 @@ static int event_destroy_stats(struct nf_conntrack *ct) if (cache_del(STATE_STATS(cache), ct)) { debug_ct(ct, "cache destroy"); - dlog_buffered_ct(STATE(stats_log), STATE_STATS(buffer_log), ct); + dlog_ct(ct); return 1; } else { debug_ct(ct, "can't destroy!"); diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index f6d2ed3..94df5f9 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -98,13 +98,13 @@ static int ftfw_init(void) { tx_queue = queue_create(CONFIG(resend_queue_size)); if (tx_queue == NULL) { - dlog(STATE(log), LOG_ERR, "cannot create tx queue"); + dlog(LOG_ERR, "cannot create tx queue"); return -1; } rs_queue = queue_create(CONFIG(resend_queue_size)); if (rs_queue == NULL) { - dlog(STATE(log), LOG_ERR, "cannot create rs queue"); + dlog(LOG_ERR, "cannot create rs queue"); return -1; } @@ -143,11 +143,11 @@ static int ftfw_local(int fd, int type, void *data) switch(type) { case REQUEST_DUMP: - dlog(STATE(log), LOG_NOTICE, "request resync"); + dlog(LOG_NOTICE, "request resync"); tx_queue_add_ctlmsg(NET_F_RESYNC, 0, 0); break; case SEND_BULK: - dlog(STATE(log), LOG_NOTICE, "sending bulk update"); + dlog(LOG_NOTICE, "sending bulk update"); cache_iterate(STATE_SYNC(internal), NULL, do_cache_to_tx); break; default: diff --git a/src/sync-mode.c b/src/sync-mode.c index dc8e782..4b2fad7 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -80,7 +80,7 @@ retry: debug_ct(ct, "can't destroy"); break; default: - dlog(STATE(log), LOG_ERR, "mcast unknown query %d\n", query); + dlog(LOG_ERR, "mcast unknown query %d\n", query); break; } } @@ -100,7 +100,7 @@ static void mcast_handler(void) struct nethdr *net = (struct nethdr *) ptr; if (ntohs(net->len) > remain) { - dlog(STATE(log), LOG_ERR, "fragmented messages"); + dlog(LOG_ERR, "fragmented messages"); break; } @@ -122,7 +122,7 @@ static int init_sync(void) { state.sync = malloc(sizeof(struct ct_sync_state)); if (!state.sync) { - dlog(STATE(log), LOG_ERR, "can't allocate memory for sync"); + dlog(LOG_ERR, "can't allocate memory for sync"); return -1; } memset(state.sync, 0, sizeof(struct ct_sync_state)); @@ -148,8 +148,8 @@ static int init_sync(void) STATE_SYNC(sync)->internal_cache_extra); if (!STATE_SYNC(internal)) { - dlog(STATE(log), LOG_ERR, "can't allocate memory for " - "the internal cache"); + dlog(LOG_ERR, "can't allocate memory for " + "the internal cache"); return -1; } @@ -164,28 +164,28 @@ static int init_sync(void) NULL); if (!STATE_SYNC(external)) { - dlog(STATE(log), LOG_ERR, "can't allocate memory for the " - "external cache"); + dlog(LOG_ERR, "can't allocate memory for the " + "external cache"); return -1; } /* multicast server to receive events from the wire */ STATE_SYNC(mcast_server) = mcast_server_create(&CONFIG(mcast)); if (STATE_SYNC(mcast_server) == NULL) { - dlog(STATE(log), LOG_ERR, "can't open multicast server!"); + dlog(LOG_ERR, "can't open multicast server!"); return -1; } /* multicast client to send events on the wire */ STATE_SYNC(mcast_client) = mcast_client_create(&CONFIG(mcast)); if (STATE_SYNC(mcast_client) == NULL) { - dlog(STATE(log), LOG_ERR, "can't open client multicast socket"); + dlog(LOG_ERR, "can't open client multicast socket"); mcast_server_destroy(STATE_SYNC(mcast_server)); return -1; } if (mcast_buffered_init(&CONFIG(mcast)) == -1) { - dlog(STATE(log), LOG_ERR, "can't init tx buffer!"); + dlog(LOG_ERR, "can't init tx buffer!"); mcast_server_destroy(STATE_SYNC(mcast_server)); mcast_client_destroy(STATE_SYNC(mcast_client)); return -1; @@ -282,14 +282,14 @@ static int local_handler_sync(int fd, int type, void *data) case COMMIT: ret = fork(); if (ret == 0) { - dlog(STATE(log), LOG_NOTICE, + dlog(LOG_NOTICE, "committing external cache"); cache_commit(STATE_SYNC(external)); exit(EXIT_SUCCESS); } break; case FLUSH_CACHE: - dlog(STATE(log), LOG_NOTICE, "flushing caches"); + dlog(LOG_NOTICE, "flushing caches"); cache_flush(STATE_SYNC(internal)); cache_flush(STATE_SYNC(external)); break; @@ -416,7 +416,7 @@ static void overrun_sync(void) h = nfct_open(CONNTRACK, 0); if (!h) { - dlog(STATE(log), LOG_ERR, "can't open overrun handler"); + dlog(LOG_ERR, "can't open overrun handler"); return; } @@ -424,7 +424,7 @@ static void overrun_sync(void) ret = nfct_query(h, NFCT_Q_DUMP, &family); if (ret == -1) - dlog(STATE(log), LOG_ERR, + dlog(LOG_ERR, "overrun query error %s", strerror(errno)); nfct_callback_unregister(h); @@ -457,8 +457,8 @@ retry: goto retry; } - dlog(STATE(log), LOG_ERR, "can't add to internal cache: " - "%s\n", strerror(errno)); + dlog(LOG_ERR, "can't add to internal cache: " + "%s\n", strerror(errno)); debug_ct(ct, "can't add"); } } -- cgit v1.2.3 From 4f72a4d0a9501f6b60aeb561fa55f3fcf5de9f96 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Fri, 18 Jan 2008 13:35:26 +0000 Subject: Max Kellermann : improve error message if netlink initialization fails --- ChangeLog | 1 + src/run.c | 10 ++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 25c8c38..815da0d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -87,6 +87,7 @@ o eliminate unsed cache_get_conntrack() in rs_list_to_tx() o remove capability code and rely on the error returned by the syscall o major simplification of the logging infrastructure o use fputs() instead of fprintf() in log.c +o improve error message if netlink initialization fails version 0.9.5 (2007/07/29) ------------------------------ diff --git a/src/run.c b/src/run.c index a5b6a79..3b50ac8 100644 --- a/src/run.c +++ b/src/run.c @@ -116,14 +116,16 @@ init(void) } if (nl_init_event_handler() == -1) { - dlog(LOG_ERR, "can't open netlink handler! " - "no ctnetlink kernel support?"); + dlog(STATE(log), LOG_ERR, "can't open netlink handler: %s", + strerror(errno)); + dlog(STATE(log), LOG_ERR, "no ctnetlink kernel support?"); return -1; } if (nl_init_dump_handler() == -1) { - dlog(LOG_ERR, "can't open netlink handler! " - "no ctnetlink kernel support?"); + dlog(STATE(log), LOG_ERR, "can't open netlink handler: %s", + strerror(errno)); + dlog(STATE(log), LOG_ERR, "no ctnetlink kernel support?"); return -1; } -- cgit v1.2.3 From 58624f1dfc9a6fc6fec14b3ce77ac2fa0fc95401 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Fri, 18 Jan 2008 13:38:04 +0000 Subject: Fix wrong dlog call --- src/run.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/run.c b/src/run.c index 3b50ac8..6ae8b9d 100644 --- a/src/run.c +++ b/src/run.c @@ -116,16 +116,15 @@ init(void) } if (nl_init_event_handler() == -1) { - dlog(STATE(log), LOG_ERR, "can't open netlink handler: %s", - strerror(errno)); - dlog(STATE(log), LOG_ERR, "no ctnetlink kernel support?"); + dlog(LOG_ERR, "can't open netlink handler: %s", strerror(errno)); + dlog(LOG_ERR, "no ctnetlink kernel support?"); return -1; } if (nl_init_dump_handler() == -1) { - dlog(STATE(log), LOG_ERR, "can't open netlink handler: %s", + dlog(LOG_ERR, "can't open netlink handler: %s", strerror(errno)); - dlog(STATE(log), LOG_ERR, "no ctnetlink kernel support?"); + dlog(LOG_ERR, "no ctnetlink kernel support?"); return -1; } -- cgit v1.2.3 From 00ad2e9e1c6cf9e14c76660f2b748247c1f4bd83 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Fri, 18 Jan 2008 13:46:30 +0000 Subject: yet another rework of the alarm scheduler --- include/alarm.h | 8 +++- src/alarm.c | 140 +++++++++++++++++++++++++++++++++++++++++++++++-------- src/run.c | 42 +++++++++++------ src/sync-alarm.c | 4 +- src/sync-ftfw.c | 2 - 5 files changed, 157 insertions(+), 39 deletions(-) (limited to 'src') diff --git a/include/alarm.h b/include/alarm.h index 532084a..2f78885 100644 --- a/include/alarm.h +++ b/include/alarm.h @@ -5,6 +5,8 @@ #include +extern int alarm_counter; + struct alarm_list { struct list_head head; struct timeval tv; @@ -19,6 +21,10 @@ set_alarm_expiration(struct alarm_list *t, long tv_sec, long tv_usec) t->tv.tv_usec = tv_usec; } +int init_alarm_hash(void); + +void destroy_alarm_hash(void); + void init_alarm(struct alarm_list *t, void *data, void (*fcn)(struct alarm_list *a, void *data)); @@ -29,7 +35,7 @@ void del_alarm(struct alarm_list *alarm); void mod_alarm(struct alarm_list *alarm, unsigned long sc, unsigned long usc); -int get_next_alarm(struct timeval *tv, struct timeval *next_alarm); +int get_next_alarm_run(struct timeval *next_alarm); int do_alarm_run(struct timeval *next_alarm); diff --git a/src/alarm.c b/src/alarm.c index 576839a..13a790e 100644 --- a/src/alarm.c +++ b/src/alarm.c @@ -17,8 +17,14 @@ */ #include "alarm.h" +#include "jhash.h" +#include +#include -static LIST_HEAD(alarm_list); +#define ALARM_HASH_SIZE 2048 + +static struct list_head *alarm_hash; +int alarm_counter; void init_alarm(struct alarm_list *t, void *data, @@ -35,14 +41,15 @@ static void __add_alarm(struct alarm_list *alarm) { struct alarm_list *t; + int i = jhash(alarm, sizeof(alarm), 0) % ALARM_HASH_SIZE; - list_for_each_entry(t, &alarm_list, head) { + list_for_each_entry(t, &alarm_hash[i], head) { if (timercmp(&alarm->tv, &t->tv, <)) { list_add_tail(&alarm->head, &t->head); return; } } - list_add_tail(&alarm->head, &alarm_list); + list_add_tail(&alarm->head, &alarm_hash[i]); } void add_alarm(struct alarm_list *alarm) @@ -52,50 +59,143 @@ void add_alarm(struct alarm_list *alarm) gettimeofday(&tv, NULL); timeradd(&alarm->tv, &tv, &alarm->tv); __add_alarm(alarm); + alarm_counter++; } void del_alarm(struct alarm_list *alarm) { /* don't remove a non-inserted node */ - if (!list_empty(&alarm->head)) + if (!list_empty(&alarm->head)) { list_del_init(&alarm->head); + alarm_counter--; + } } void mod_alarm(struct alarm_list *alarm, unsigned long sc, unsigned long usc) { - list_del(&alarm->head); + struct timeval tv; + set_alarm_expiration(alarm, sc, usc); - add_alarm(alarm); + gettimeofday(&tv, NULL); + timeradd(&alarm->tv, &tv, &alarm->tv); + list_del(&alarm->head); + __add_alarm(alarm); } -int get_next_alarm(struct timeval *tv, struct timeval *next_alarm) +static int +calculate_next_run(struct timeval *cand, + struct timeval *tv, + struct timeval *next_run) { + if (cand->tv_sec != LONG_MAX) { + if (timercmp(cand, tv, >)) + timersub(cand, tv, next_run); + else { + /* loop again inmediately */ + next_run->tv_sec = 0; + next_run->tv_usec = 0; + } + return 1; + } + return 0; +} + +int get_next_alarm_run(struct timeval *next_run) +{ + int i; struct alarm_list *t; + struct timeval tv; + struct timeval cand = { + .tv_sec = LONG_MAX, + .tv_usec = LONG_MAX + }; + + gettimeofday(&tv, NULL); - list_for_each_entry(t, &alarm_list, head) { - timersub(&t->tv, tv, next_alarm); + for (i=0; itv, &cand, <)) { + cand.tv_sec = t->tv.tv_sec; + cand.tv_usec = t->tv.tv_usec; + } + } + } + + return calculate_next_run(&cand, &tv, next_run); +} + +static inline int +tv_compare(struct alarm_list *a, struct timeval *cur, struct timeval *cand) +{ + if (timercmp(&a->tv, cur, >)) { + /* select the next alarm candidate */ + if (timercmp(&a->tv, cand, <)) { + cand->tv_sec = a->tv.tv_sec; + cand->tv_usec = a->tv.tv_usec; + } return 1; } return 0; } -int do_alarm_run(struct timeval *next_alarm) +int do_alarm_run(struct timeval *next_run) { - struct alarm_list *t, *tmp; + int i; + struct alarm_list *t, *next, *prev; struct timeval tv; + struct timeval cand = { + .tv_sec = LONG_MAX, + .tv_usec = LONG_MAX + }; gettimeofday(&tv, NULL); - list_for_each_entry_safe(t, tmp, &alarm_list, head) { - if (timercmp(&t->tv, &tv, >)) { - timersub(&t->tv, &tv, next_alarm); - return 1; + for (i=0; ihead.prev, + struct alarm_list, + head); + + del_alarm(t); + t->function(t, t->data); + + /* Special case: One deleted node is inserted + * again in the same place */ + if (next->head.prev == &prev->head) { + t = list_entry(next->head.prev, + struct alarm_list, + head); + if (tv_compare(t, &tv, &cand)) + break; + } } - - del_alarm(t); - t->function(t, t->data); } - /* check for refreshed alarms to get the next one */ - return get_next_alarm(&tv, next_alarm); + return calculate_next_run(&cand, &tv, next_run); +} + +int init_alarm_hash(void) +{ + int i; + + alarm_hash = malloc(sizeof(struct list_head) * ALARM_HASH_SIZE); + if (alarm_hash == NULL) + return -1; + + for (i=0; ikill(); + destroy_alarm_hash(); unlink(CONFIG(lockfile)); dlog(LOG_NOTICE, "---- shutdown received ----"); close_log(); @@ -102,6 +103,11 @@ init(void) STATE(mode) = &stats_mode; } + if (init_alarm_hash() == -1) { + dlog(LOG_ERR, "can't initialize alarm hash"); + return -1; + } + /* Initialization */ if (STATE(mode)->init() == -1) { dlog(LOG_ERR, "initialization failed"); @@ -152,10 +158,15 @@ init(void) return 0; } -static int __run(struct timeval *next_alarm) +static int __run(struct timeval *next_alarm, int *timeout) { int max, ret; fd_set readfds; + struct timeval *tmp = next_alarm; + + /* No alarms, select must block */ + if (*timeout == 0) + tmp = NULL; FD_ZERO(&readfds); FD_SET(STATE(local), &readfds); @@ -166,7 +177,7 @@ static int __run(struct timeval *next_alarm) if (STATE(mode)->add_fds_to_set) max = MAX(max, STATE(mode)->add_fds_to_set(&readfds)); - ret = select(max+1, &readfds, NULL, NULL, next_alarm); + ret = select(max+1, &readfds, NULL, NULL, tmp); if (ret == -1) { /* interrupted syscall, retry */ if (errno == EINTR) @@ -178,7 +189,7 @@ static int __run(struct timeval *next_alarm) } /* timeout expired, run the alarm list */ - if (ret == 0) + if (tmp != NULL && !timerisset(tmp)) return 1; /* signals are racy */ @@ -224,6 +235,14 @@ static int __run(struct timeval *next_alarm) if (STATE(mode)->run) STATE(mode)->run(&readfds); + /* check if we have introduced any new alarms */ + if (*timeout == 0 && alarm_counter > 0) { + *timeout = 1; + if (!get_next_alarm_run(next_alarm)) + dlog(LOG_ERR, "Bug in alarm?"); + return 0; + } + sigprocmask(SIG_UNBLOCK, &STATE(block), NULL); return 0; @@ -232,21 +251,16 @@ static int __run(struct timeval *next_alarm) void __attribute__((noreturn)) run(void) { - struct timeval next_alarm; - struct timeval *next = &next_alarm; - struct timeval tv; + int timeout; + struct timeval next_alarm; - /* initialization: get the first alarm available */ - gettimeofday(&tv, NULL); - if (!get_next_alarm(&tv, next)) - next = NULL; + /* initialization: get the next alarm available */ + timeout = get_next_alarm_run(&next_alarm); while(1) { - if (__run(next)) { + if (__run(&next_alarm, &timeout)) { sigprocmask(SIG_BLOCK, &STATE(block), NULL); - next = &next_alarm; - if (!do_alarm_run(next)) - next = NULL; /* no next alarms */ + timeout = do_alarm_run(&next_alarm); sigprocmask(SIG_UNBLOCK, &STATE(block), NULL); } } diff --git a/src/sync-alarm.c b/src/sync-alarm.c index 6ee306e..9ab9d96 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -38,7 +38,7 @@ static void refresher(struct alarm_list *a, void *data) init_alarm(a, u, refresher); set_alarm_expiration(a, random() % CONFIG(refresh) + 1, - random() % 999999 + 1); + ((random() % 5 + 1) * 200000) - 1); add_alarm(a); @@ -54,7 +54,7 @@ static void cache_alarm_add(struct us_conntrack *u, void *data) init_alarm(alarm, u, refresher); set_alarm_expiration(alarm, random() % CONFIG(refresh) + 1, - random() % 999999 + 1); + ((random() % 5 + 1) * 200000) - 1); add_alarm(alarm); } diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 94df5f9..004dd21 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -340,8 +340,6 @@ static void ftfw_run(void) u = cache_get_conntrack(STATE_SYNC(internal), cn); tx_list_xmit(&cn->tx_list, u); } - - mod_alarm(&alive_alarm, 1, 0); } struct sync_mode sync_ftfw = { -- cgit v1.2.3 From bcae271764d18e570a5fca382eeea748add4af62 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Sun, 20 Jan 2008 23:51:23 +0000 Subject: Based on patch from Max Kellermann : merge mod_alarm() into add_alarm(), remove alarm_set_expiration() --- ChangeLog | 1 + include/alarm.h | 11 +---------- src/alarm.c | 16 ++++------------ src/cache_timer.c | 5 ++--- src/sync-alarm.c | 17 +++++++---------- src/sync-ftfw.c | 6 ++---- 6 files changed, 17 insertions(+), 39 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 815da0d..2dad662 100644 --- a/ChangeLog +++ b/ChangeLog @@ -88,6 +88,7 @@ o remove capability code and rely on the error returned by the syscall o major simplification of the logging infrastructure o use fputs() instead of fprintf() in log.c o improve error message if netlink initialization fails +o merge mod_alarm() into add_alarm(), remove alarm_set_expiration() version 0.9.5 (2007/07/29) ------------------------------ diff --git a/include/alarm.h b/include/alarm.h index 2f78885..f0bbb95 100644 --- a/include/alarm.h +++ b/include/alarm.h @@ -14,13 +14,6 @@ struct alarm_list { void (*function)(struct alarm_list *a, void *data); }; -static inline void -set_alarm_expiration(struct alarm_list *t, long tv_sec, long tv_usec) -{ - t->tv.tv_sec = tv_sec; - t->tv.tv_usec = tv_usec; -} - int init_alarm_hash(void); void destroy_alarm_hash(void); @@ -29,12 +22,10 @@ void init_alarm(struct alarm_list *t, void *data, void (*fcn)(struct alarm_list *a, void *data)); -void add_alarm(struct alarm_list *alarm); +void add_alarm(struct alarm_list *alarm, unsigned long sc, unsigned long usc); void del_alarm(struct alarm_list *alarm); -void mod_alarm(struct alarm_list *alarm, unsigned long sc, unsigned long usc); - int get_next_alarm_run(struct timeval *next_alarm); int do_alarm_run(struct timeval *next_alarm); diff --git a/src/alarm.c b/src/alarm.c index 13a790e..2190bb6 100644 --- a/src/alarm.c +++ b/src/alarm.c @@ -52,10 +52,13 @@ __add_alarm(struct alarm_list *alarm) list_add_tail(&alarm->head, &alarm_hash[i]); } -void add_alarm(struct alarm_list *alarm) +void add_alarm(struct alarm_list *alarm, unsigned long sc, unsigned long usc) { struct timeval tv; + del_alarm(alarm); + alarm->tv.tv_sec = sc; + alarm->tv.tv_usec = usc; gettimeofday(&tv, NULL); timeradd(&alarm->tv, &tv, &alarm->tv); __add_alarm(alarm); @@ -71,17 +74,6 @@ void del_alarm(struct alarm_list *alarm) } } -void mod_alarm(struct alarm_list *alarm, unsigned long sc, unsigned long usc) -{ - struct timeval tv; - - set_alarm_expiration(alarm, sc, usc); - gettimeofday(&tv, NULL); - timeradd(&alarm->tv, &tv, &alarm->tv); - list_del(&alarm->head); - __add_alarm(alarm); -} - static int calculate_next_run(struct timeval *cand, struct timeval *tv, diff --git a/src/cache_timer.c b/src/cache_timer.c index 0fbba14..86bb8fc 100644 --- a/src/cache_timer.c +++ b/src/cache_timer.c @@ -37,14 +37,13 @@ static void timer_add(struct us_conntrack *u, void *data) struct alarm_list *alarm = data; init_alarm(alarm, u, timeout); - set_alarm_expiration(alarm, CONFIG(cache_timeout), 0); - add_alarm(alarm); + add_alarm(alarm, CONFIG(cache_timeout), 0); } static void timer_update(struct us_conntrack *u, void *data) { struct alarm_list *alarm = data; - mod_alarm(alarm, CONFIG(cache_timeout), 0); + add_alarm(alarm, CONFIG(cache_timeout), 0); } static void timer_destroy(struct us_conntrack *u, void *data) diff --git a/src/sync-alarm.c b/src/sync-alarm.c index 9ab9d96..1f164b2 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -36,11 +36,9 @@ static void refresher(struct alarm_list *a, void *data) debug_ct(u->ct, "persistence update"); init_alarm(a, u, refresher); - set_alarm_expiration(a, - random() % CONFIG(refresh) + 1, - ((random() % 5 + 1) * 200000) - 1); - - add_alarm(a); + add_alarm(a, + random() % CONFIG(refresh) + 1, + ((random() % 5 + 1) * 200000) - 1); net = BUILD_NETMSG(u->ct, NFCT_Q_UPDATE); len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); @@ -52,16 +50,15 @@ static void cache_alarm_add(struct us_conntrack *u, void *data) struct alarm_list *alarm = data; init_alarm(alarm, u, refresher); - set_alarm_expiration(alarm, - random() % CONFIG(refresh) + 1, - ((random() % 5 + 1) * 200000) - 1); - add_alarm(alarm); + add_alarm(alarm, + random() % CONFIG(refresh) + 1, + ((random() % 5 + 1) * 200000) - 1); } static void cache_alarm_update(struct us_conntrack *u, void *data) { struct alarm_list *alarm = data; - mod_alarm(alarm, random() % CONFIG(refresh) + 1, random() % 999999 + 1); + add_alarm(alarm, random() % CONFIG(refresh) + 1, random() % 999999 + 1); } static void cache_alarm_destroy(struct us_conntrack *u, void *data) diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 004dd21..dc3bf44 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -90,8 +90,7 @@ static void do_alive_alarm(struct alarm_list *a, void *data) tx_queue_add_ctlmsg(NET_F_ALIVE, 0, 0); init_alarm(&alive_alarm, NULL, do_alive_alarm); - set_alarm_expiration(&alive_alarm, 1, 0); - add_alarm(&alive_alarm); + add_alarm(&alive_alarm, 1, 0); } static int ftfw_init(void) @@ -113,8 +112,7 @@ static int ftfw_init(void) /* XXX: alive message expiration configurable */ init_alarm(&alive_alarm, NULL, do_alive_alarm); - set_alarm_expiration(&alive_alarm, 1, 0); - add_alarm(&alive_alarm); + add_alarm(&alive_alarm, 1, 0); return 0; } -- cgit v1.2.3 From d6f29c81c1452db525d12110d5f15f7f39df9b86 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Sun, 20 Jan 2008 23:56:55 +0000 Subject: Max Kellermann : remove init_alarm() before add_alarm() --- ChangeLog | 1 + src/sync-alarm.c | 1 - src/sync-ftfw.c | 1 - 3 files changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 2dad662..3ca5746 100644 --- a/ChangeLog +++ b/ChangeLog @@ -89,6 +89,7 @@ o major simplification of the logging infrastructure o use fputs() instead of fprintf() in log.c o improve error message if netlink initialization fails o merge mod_alarm() into add_alarm(), remove alarm_set_expiration() +o remove init_alarm() before add_alarm() version 0.9.5 (2007/07/29) ------------------------------ diff --git a/src/sync-alarm.c b/src/sync-alarm.c index 1f164b2..f7a1536 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -35,7 +35,6 @@ static void refresher(struct alarm_list *a, void *data) debug_ct(u->ct, "persistence update"); - init_alarm(a, u, refresher); add_alarm(a, random() % CONFIG(refresh) + 1, ((random() % 5 + 1) * 200000) - 1); diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index dc3bf44..1d12002 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -89,7 +89,6 @@ static void do_alive_alarm(struct alarm_list *a, void *data) { tx_queue_add_ctlmsg(NET_F_ALIVE, 0, 0); - init_alarm(&alive_alarm, NULL, do_alive_alarm); add_alarm(&alive_alarm, 1, 0); } -- cgit v1.2.3 From 6174e60abbcdc5b62a52fc03c373cee0b77ebcbf Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Tue, 22 Jan 2008 01:25:34 +0000 Subject: Max Kellermann : - Pass next_alarm to __run() only if there is an alarm - Eliminate the "timeout" parameter - the alarm functions get_next_alarm_run() and do_alarm_run() return an timeval pointer instead of a boolean --- include/alarm.h | 6 ++++-- src/alarm.c | 12 +++++++----- src/run.c | 44 ++++++++++++++------------------------------ 3 files changed, 25 insertions(+), 37 deletions(-) (limited to 'src') diff --git a/include/alarm.h b/include/alarm.h index f0bbb95..3569025 100644 --- a/include/alarm.h +++ b/include/alarm.h @@ -26,8 +26,10 @@ void add_alarm(struct alarm_list *alarm, unsigned long sc, unsigned long usc); void del_alarm(struct alarm_list *alarm); -int get_next_alarm_run(struct timeval *next_alarm); +struct timeval * +get_next_alarm_run(struct timeval *next_alarm); -int do_alarm_run(struct timeval *next_alarm); +struct timeval * +do_alarm_run(struct timeval *next_alarm); #endif diff --git a/src/alarm.c b/src/alarm.c index 2190bb6..883a42c 100644 --- a/src/alarm.c +++ b/src/alarm.c @@ -74,7 +74,7 @@ void del_alarm(struct alarm_list *alarm) } } -static int +static struct timeval * calculate_next_run(struct timeval *cand, struct timeval *tv, struct timeval *next_run) @@ -87,12 +87,13 @@ calculate_next_run(struct timeval *cand, next_run->tv_sec = 0; next_run->tv_usec = 0; } - return 1; + return next_run; } - return 0; + return NULL; } -int get_next_alarm_run(struct timeval *next_run) +struct timeval * +get_next_alarm_run(struct timeval *next_run) { int i; struct alarm_list *t; @@ -133,7 +134,8 @@ tv_compare(struct alarm_list *a, struct timeval *cur, struct timeval *cand) return 0; } -int do_alarm_run(struct timeval *next_run) +struct timeval * +do_alarm_run(struct timeval *next_run) { int i; struct alarm_list *t, *next, *prev; diff --git a/src/run.c b/src/run.c index efeda5a..bf2798d 100644 --- a/src/run.c +++ b/src/run.c @@ -158,15 +158,10 @@ init(void) return 0; } -static int __run(struct timeval *next_alarm, int *timeout) +static void __run(struct timeval *next_alarm) { int max, ret; fd_set readfds; - struct timeval *tmp = next_alarm; - - /* No alarms, select must block */ - if (*timeout == 0) - tmp = NULL; FD_ZERO(&readfds); FD_SET(STATE(local), &readfds); @@ -177,21 +172,17 @@ static int __run(struct timeval *next_alarm, int *timeout) if (STATE(mode)->add_fds_to_set) max = MAX(max, STATE(mode)->add_fds_to_set(&readfds)); - ret = select(max+1, &readfds, NULL, NULL, tmp); + ret = select(max+1, &readfds, NULL, NULL, next_alarm); if (ret == -1) { /* interrupted syscall, retry */ if (errno == EINTR) - return 0; + return; dlog(LOG_WARNING, "select failed: %s", strerror(errno)); - return 0; + return; } - /* timeout expired, run the alarm list */ - if (tmp != NULL && !timerisset(tmp)) - return 1; - /* signals are racy */ sigprocmask(SIG_BLOCK, &STATE(block), NULL); @@ -235,33 +226,26 @@ static int __run(struct timeval *next_alarm, int *timeout) if (STATE(mode)->run) STATE(mode)->run(&readfds); - /* check if we have introduced any new alarms */ - if (*timeout == 0 && alarm_counter > 0) { - *timeout = 1; - if (!get_next_alarm_run(next_alarm)) - dlog(LOG_ERR, "Bug in alarm?"); - return 0; - } - sigprocmask(SIG_UNBLOCK, &STATE(block), NULL); - - return 0; } void __attribute__((noreturn)) run(void) { - int timeout; struct timeval next_alarm; + struct timeval *next; /* initialization: get the next alarm available */ - timeout = get_next_alarm_run(&next_alarm); + next = get_next_alarm_run(&next_alarm); while(1) { - if (__run(&next_alarm, &timeout)) { - sigprocmask(SIG_BLOCK, &STATE(block), NULL); - timeout = do_alarm_run(&next_alarm); - sigprocmask(SIG_UNBLOCK, &STATE(block), NULL); - } + __run(next); + + sigprocmask(SIG_BLOCK, &STATE(block), NULL); + if (next != NULL && !timerisset(next)) + next = do_alarm_run(&next_alarm); + else + next = get_next_alarm_run(&next_alarm); + sigprocmask(SIG_UNBLOCK, &STATE(block), NULL); } } -- cgit v1.2.3 From 02ff145c51439873db3cdc192b48e47e2272b0b9 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Tue, 22 Jan 2008 01:28:07 +0000 Subject: Max Kellermann : - Save initialization stage in the __run() loop --- src/run.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/run.c b/src/run.c index bf2798d..fe57858 100644 --- a/src/run.c +++ b/src/run.c @@ -233,19 +233,16 @@ void __attribute__((noreturn)) run(void) { struct timeval next_alarm; - struct timeval *next; - - /* initialization: get the next alarm available */ - next = get_next_alarm_run(&next_alarm); + struct timeval *next = NULL; while(1) { - __run(next); - sigprocmask(SIG_BLOCK, &STATE(block), NULL); if (next != NULL && !timerisset(next)) next = do_alarm_run(&next_alarm); else next = get_next_alarm_run(&next_alarm); sigprocmask(SIG_UNBLOCK, &STATE(block), NULL); + + __run(next); } } -- cgit v1.2.3 From 8078747751df6e8ccc27b76f2f53c5e393d745ae Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Tue, 22 Jan 2008 01:32:21 +0000 Subject: remove alarm counter --- include/alarm.h | 2 -- src/alarm.c | 6 +----- 2 files changed, 1 insertion(+), 7 deletions(-) (limited to 'src') diff --git a/include/alarm.h b/include/alarm.h index 3569025..c4ea9d7 100644 --- a/include/alarm.h +++ b/include/alarm.h @@ -5,8 +5,6 @@ #include -extern int alarm_counter; - struct alarm_list { struct list_head head; struct timeval tv; diff --git a/src/alarm.c b/src/alarm.c index 883a42c..7352ccb 100644 --- a/src/alarm.c +++ b/src/alarm.c @@ -24,7 +24,6 @@ #define ALARM_HASH_SIZE 2048 static struct list_head *alarm_hash; -int alarm_counter; void init_alarm(struct alarm_list *t, void *data, @@ -62,16 +61,13 @@ void add_alarm(struct alarm_list *alarm, unsigned long sc, unsigned long usc) gettimeofday(&tv, NULL); timeradd(&alarm->tv, &tv, &alarm->tv); __add_alarm(alarm); - alarm_counter++; } void del_alarm(struct alarm_list *alarm) { /* don't remove a non-inserted node */ - if (!list_empty(&alarm->head)) { + if (!list_empty(&alarm->head)) list_del_init(&alarm->head); - alarm_counter--; - } } static struct timeval * -- cgit v1.2.3 From 0adf963ed6cca5f1b096ff04f246d5e21e2ffe7b Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Tue, 22 Jan 2008 01:36:32 +0000 Subject: minor cleanups --- src/run.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/run.c b/src/run.c index fe57858..abe968f 100644 --- a/src/run.c +++ b/src/run.c @@ -43,7 +43,7 @@ void killer(int foo) local_server_destroy(STATE(local), CONFIG(local).path); STATE(mode)->kill(); destroy_alarm_hash(); - unlink(CONFIG(lockfile)); + unlink(CONFIG(lockfile)); dlog(LOG_NOTICE, "---- shutdown received ----"); close_log(); @@ -73,7 +73,7 @@ void local_handler(int fd, void *data) switch(type) { case FLUSH_MASTER: dlog(LOG_WARNING, "`conntrackd -F' is deprecated. " - "Use conntrack -F instead."); + "Use conntrack -F instead."); if (fork() == 0) { execlp("conntrack", "conntrack", "-F", NULL); exit(EXIT_SUCCESS); @@ -122,7 +122,8 @@ init(void) } if (nl_init_event_handler() == -1) { - dlog(LOG_ERR, "can't open netlink handler: %s", strerror(errno)); + dlog(LOG_ERR, "can't open netlink handler: %s", + strerror(errno)); dlog(LOG_ERR, "no ctnetlink kernel support?"); return -1; } @@ -178,8 +179,7 @@ static void __run(struct timeval *next_alarm) if (errno == EINTR) return; - dlog(LOG_WARNING, - "select failed: %s", strerror(errno)); + dlog(LOG_WARNING, "select failed: %s", strerror(errno)); return; } -- cgit v1.2.3 From 9e0585bb826cf7bb879ed3ad68a26767d3e33379 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Tue, 22 Jan 2008 01:45:57 +0000 Subject: fix inconsistent alarm update in cache_alarm_update --- src/sync-alarm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/sync-alarm.c b/src/sync-alarm.c index f7a1536..66727e7 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -57,7 +57,9 @@ static void cache_alarm_add(struct us_conntrack *u, void *data) static void cache_alarm_update(struct us_conntrack *u, void *data) { struct alarm_list *alarm = data; - add_alarm(alarm, random() % CONFIG(refresh) + 1, random() % 999999 + 1); + add_alarm(alarm, + random() % CONFIG(refresh) + 1, + ((random() % 5 + 1) * 200000) - 1); } static void cache_alarm_destroy(struct us_conntrack *u, void *data) -- cgit v1.2.3 From 86c4c05681e8e38616fb7b0b575b4cd944ddfa83 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Wed, 23 Jan 2008 10:16:03 +0000 Subject: Max Kellermann : fix error checking of local_create_server() --- ChangeLog | 1 + src/run.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 3ca5746..753fb80 100644 --- a/ChangeLog +++ b/ChangeLog @@ -90,6 +90,7 @@ o use fputs() instead of fprintf() in log.c o improve error message if netlink initialization fails o merge mod_alarm() into add_alarm(), remove alarm_set_expiration() o remove init_alarm() before add_alarm() +o fix error checking of local_create_server() version 0.9.5 (2007/07/29) ------------------------------ diff --git a/src/run.c b/src/run.c index abe968f..bdf6b0b 100644 --- a/src/run.c +++ b/src/run.c @@ -116,7 +116,7 @@ init(void) /* local UNIX socket */ STATE(local) = local_server_create(&CONFIG(local)); - if (!STATE(local)) { + if (STATE(local) == -1) { dlog(LOG_ERR, "can't open unix socket!"); return -1; } -- cgit v1.2.3 From a0754a2e4a63642e6fefb7bfbb19b9f5f9295009 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Wed, 23 Jan 2008 10:30:21 +0000 Subject: Max Kellermann : added struct local_server, several cleanups in local socket infrastructure This patch include minor changes by the comitter --- ChangeLog | 1 + include/conntrackd.h | 2 +- include/local.h | 11 ++++++++--- src/local.c | 18 +++++++++++------- src/run.c | 13 ++++++------- 5 files changed, 27 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 753fb80..b78f337 100644 --- a/ChangeLog +++ b/ChangeLog @@ -91,6 +91,7 @@ o improve error message if netlink initialization fails o merge mod_alarm() into add_alarm(), remove alarm_set_expiration() o remove init_alarm() before add_alarm() o fix error checking of local_create_server() +o added struct local_server, several cleanups in local socket infrastructure version 0.9.5 (2007/07/29) ------------------------------ diff --git a/include/conntrackd.h b/include/conntrackd.h index b223a17..47898e2 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -98,7 +98,7 @@ struct ct_general_state { sigset_t block; FILE *log; FILE *stats_log; - int local; + struct local_server local; struct ct_mode *mode; struct ignore_pool *ignore_pool; diff --git a/include/local.h b/include/local.h index be77d35..6940755 100644 --- a/include/local.h +++ b/include/local.h @@ -11,10 +11,15 @@ struct local_conf { char path[UNIX_PATH_MAX]; }; +struct local_server { + int fd; + char path[UNIX_PATH_MAX]; +}; + /* local server */ -int local_server_create(struct local_conf *conf); -void local_server_destroy(int fd, const char *); -int do_local_server_step(int fd, void *data, +int local_server_create(struct local_server *server, struct local_conf *conf); +void local_server_destroy(struct local_server *server); +int do_local_server_step(struct local_server *server, void *data, void (*process)(int fd, void *data)); /* local client */ diff --git a/src/local.c b/src/local.c index f0aba1c..258605f 100644 --- a/src/local.c +++ b/src/local.c @@ -26,7 +26,7 @@ #include #include -int local_server_create(struct local_conf *conf) +int local_server_create(struct local_server *server, struct local_conf *conf) { int fd; int len; @@ -59,23 +59,27 @@ int local_server_create(struct local_conf *conf) return -1; } - return fd; + server->fd = fd; + strcpy(server->path, conf->path); + + return 0; } -void local_server_destroy(int fd, const char *path) +void local_server_destroy(struct local_server *server) { - unlink(path); - close(fd); + unlink(server->path); + close(server->fd); } -int do_local_server_step(int fd, void *data, +int do_local_server_step(struct local_server *server, void *data, void (*process)(int fd, void *data)) { int rfd; struct sockaddr_un local; socklen_t sin_size = sizeof(struct sockaddr_un); - if ((rfd = accept(fd, (struct sockaddr *)&local, &sin_size)) == -1) + rfd = accept(server->fd, (struct sockaddr *) &local, &sin_size); + if (rfd == -1) return -1; process(rfd, data); diff --git a/src/run.c b/src/run.c index bdf6b0b..876e131 100644 --- a/src/run.c +++ b/src/run.c @@ -40,7 +40,7 @@ void killer(int foo) nfct_close(STATE(dump)); ignore_pool_destroy(STATE(ignore_pool)); - local_server_destroy(STATE(local), CONFIG(local).path); + local_server_destroy(&STATE(local)); STATE(mode)->kill(); destroy_alarm_hash(); unlink(CONFIG(lockfile)); @@ -115,8 +115,7 @@ init(void) } /* local UNIX socket */ - STATE(local) = local_server_create(&CONFIG(local)); - if (STATE(local) == -1) { + if (local_server_create(&STATE(local), &CONFIG(local)) == -1) { dlog(LOG_ERR, "can't open unix socket!"); return -1; } @@ -165,10 +164,10 @@ static void __run(struct timeval *next_alarm) fd_set readfds; FD_ZERO(&readfds); - FD_SET(STATE(local), &readfds); + FD_SET(STATE(local).fd, &readfds); FD_SET(nfct_fd(STATE(event)), &readfds); - max = MAX(STATE(local), nfct_fd(STATE(event))); + max = MAX(STATE(local).fd, nfct_fd(STATE(event))); if (STATE(mode)->add_fds_to_set) max = MAX(max, STATE(mode)->add_fds_to_set(&readfds)); @@ -187,8 +186,8 @@ static void __run(struct timeval *next_alarm) sigprocmask(SIG_BLOCK, &STATE(block), NULL); /* order received via UNIX socket */ - if (FD_ISSET(STATE(local), &readfds)) - do_local_server_step(STATE(local), NULL, local_handler); + if (FD_ISSET(STATE(local).fd, &readfds)) + do_local_server_step(&STATE(local), NULL, local_handler); /* conntrack event has happened */ if (FD_ISSET(nfct_fd(STATE(event)), &readfds)) { -- cgit v1.2.3 From 8661b951343f7fa8cbc56e81557e895e287b954b Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Wed, 23 Jan 2008 11:06:42 +0000 Subject: add comment to clarify handle_msg() --- src/sync-mode.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/sync-mode.c b/src/sync-mode.c index 4b2fad7..4f7833c 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -108,6 +108,7 @@ static void mcast_handler(void) ntohl(net->seq), ntohs(net->flags), ntohs(net->len), remain); + /* sanity check and convert nethdr to host byte order */ if (handle_netmsg(net) == -1) { STATE(malformed)++; return; -- cgit v1.2.3 From 70219213d3e9404a95844f567d6d6b44753d8dad Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Wed, 23 Jan 2008 11:38:30 +0000 Subject: Max Kellermann : check if the received packet is large enough Minor changes by the committer --- ChangeLog | 1 + src/sync-mode.c | 5 +++++ 2 files changed, 6 insertions(+) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 8205ec5..2f6c762 100644 --- a/ChangeLog +++ b/ChangeLog @@ -93,6 +93,7 @@ o remove init_alarm() before add_alarm() o fix error checking of local_create_server() o added struct local_server, several cleanups in local socket infrastructure o remove unused prototypes in network.h +o check if the received packet is large enough version 0.9.5 (2007/07/29) ------------------------------ diff --git a/src/sync-mode.c b/src/sync-mode.c index 4f7833c..f726272 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -99,6 +99,11 @@ static void mcast_handler(void) while (remain > 0) { struct nethdr *net = (struct nethdr *) ptr; + if (remain < NETHDR_SIZ) { + STATE(malformed)++; + break; + } + if (ntohs(net->len) > remain) { dlog(LOG_ERR, "fragmented messages"); break; -- cgit v1.2.3 From c4d3ba8748a12a9ad466b3b1c50cc31d36cd5418 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Wed, 23 Jan 2008 11:45:29 +0000 Subject: missing casting to keep -Werror happy --- src/sync-mode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/sync-mode.c b/src/sync-mode.c index f726272..5974474 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -99,7 +99,7 @@ static void mcast_handler(void) while (remain > 0) { struct nethdr *net = (struct nethdr *) ptr; - if (remain < NETHDR_SIZ) { + if ((size_t)remain < NETHDR_SIZ) { STATE(malformed)++; break; } -- cgit v1.2.3 From d658f3ed913affe96511309c6bf3d37aaec2910f Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Wed, 23 Jan 2008 12:15:25 +0000 Subject: Max Kellermann : introduce alarm_pending() --- ChangeLog | 1 + include/alarm.h | 2 ++ src/alarm.c | 8 ++++++++ src/cache_timer.c | 3 +++ 4 files changed, 14 insertions(+) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 2f6c762..5010775 100644 --- a/ChangeLog +++ b/ChangeLog @@ -94,6 +94,7 @@ o fix error checking of local_create_server() o added struct local_server, several cleanups in local socket infrastructure o remove unused prototypes in network.h o check if the received packet is large enough +o introduce alarm_pending() version 0.9.5 (2007/07/29) ------------------------------ diff --git a/include/alarm.h b/include/alarm.h index c4ea9d7..e3e08c1 100644 --- a/include/alarm.h +++ b/include/alarm.h @@ -24,6 +24,8 @@ void add_alarm(struct alarm_list *alarm, unsigned long sc, unsigned long usc); void del_alarm(struct alarm_list *alarm); +int alarm_pending(struct alarm_list *alarm); + struct timeval * get_next_alarm_run(struct timeval *next_alarm); diff --git a/src/alarm.c b/src/alarm.c index 7352ccb..4b23bd1 100644 --- a/src/alarm.c +++ b/src/alarm.c @@ -70,6 +70,14 @@ void del_alarm(struct alarm_list *alarm) list_del_init(&alarm->head); } +int alarm_pending(struct alarm_list *alarm) +{ + if (list_empty(&alarm->head)) + return 0; + + return 1; +} + static struct timeval * calculate_next_run(struct timeval *cand, struct timeval *tv, diff --git a/src/cache_timer.c b/src/cache_timer.c index 86bb8fc..fe997ec 100644 --- a/src/cache_timer.c +++ b/src/cache_timer.c @@ -60,6 +60,9 @@ static int timer_dump(struct us_conntrack *u, void *data, char *buf, int type) if (type == NFCT_O_XML) return 0; + if (!alarm_pending(alarm)) + return 0; + gettimeofday(&tv, NULL); timersub(&tv, &alarm->tv, &tmp); return sprintf(buf, " [expires in %lds]", tmp.tv_sec); -- cgit v1.2.3 From 379125b1f618b3102015a64b1e9be0bdbe883930 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Wed, 23 Jan 2008 12:30:36 +0000 Subject: Max Kellermann : use size_t --- ChangeLog | 1 + include/mcast.h | 4 ++-- include/network.h | 7 ++++--- src/build.c | 2 +- src/local.c | 4 ++-- src/mcast.c | 8 ++++---- src/network.c | 22 +++++++++++----------- src/sync-alarm.c | 2 +- src/sync-ftfw.c | 4 ++-- src/sync-mode.c | 9 +++++---- 10 files changed, 33 insertions(+), 30 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 5010775..4cd5eff 100644 --- a/ChangeLog +++ b/ChangeLog @@ -95,6 +95,7 @@ o added struct local_server, several cleanups in local socket infrastructure o remove unused prototypes in network.h o check if the received packet is large enough o introduce alarm_pending() +o cleanup: use size_t instead of integer version 0.9.5 (2007/07/29) ------------------------------ diff --git a/include/mcast.h b/include/mcast.h index e3cdb38..4e89c72 100644 --- a/include/mcast.h +++ b/include/mcast.h @@ -43,8 +43,8 @@ void mcast_server_destroy(struct mcast_sock *m); struct mcast_sock *mcast_client_create(struct mcast_conf *conf); void mcast_client_destroy(struct mcast_sock *m); -int mcast_send(struct mcast_sock *m, void *data, int size); -int mcast_recv(struct mcast_sock *m, void *data, int size); +ssize_t mcast_send(struct mcast_sock *m, void *data, int size); +ssize_t mcast_recv(struct mcast_sock *m, void *data, int size); struct mcast_stats *mcast_get_stats(struct mcast_sock *m); void mcast_dump_stats(int fd, struct mcast_sock *s, struct mcast_sock *r); diff --git a/include/network.h b/include/network.h index e3e9ce1..92a8490 100644 --- a/include/network.h +++ b/include/network.h @@ -2,6 +2,7 @@ #define _NETWORK_H_ #include +#include struct nf_conntrack; @@ -53,7 +54,7 @@ struct us_conntrack; struct mcast_sock; void build_netmsg(struct nf_conntrack *ct, int query, struct nethdr *net); -int prepare_send_netmsg(struct mcast_sock *m, void *data); +size_t prepare_send_netmsg(struct mcast_sock *m, void *data); int mcast_send_netmsg(struct mcast_sock *m, void *data); int handle_netmsg(struct nethdr *net); int mcast_track_seq(uint32_t seq, uint32_t *exp_seq); @@ -62,8 +63,8 @@ struct mcast_conf; int mcast_buffered_init(struct mcast_conf *conf); void mcast_buffered_destroy(void); -int mcast_buffered_send_netmsg(struct mcast_sock *m, void *data, int len); -int mcast_buffered_pending_netmsg(struct mcast_sock *m); +int mcast_buffered_send_netmsg(struct mcast_sock *m, void *data, size_t len); +ssize_t mcast_buffered_pending_netmsg(struct mcast_sock *m); #define IS_DATA(x) ((x->flags & ~NET_F_HELLO) == 0) #define IS_ACK(x) (x->flags & NET_F_ACK) diff --git a/src/build.c b/src/build.c index c99990b..3de1c25 100644 --- a/src/build.c +++ b/src/build.c @@ -20,7 +20,7 @@ #include #include "network.h" -static void addattr(struct netpld *pld, int attr, const void *data, int len) +static void addattr(struct netpld *pld, int attr, const void *data, size_t len) { struct netattr *nta; int tlen = NTA_LENGTH(len); diff --git a/src/local.c b/src/local.c index 258605f..e2c3599 100644 --- a/src/local.c +++ b/src/local.c @@ -29,7 +29,7 @@ int local_server_create(struct local_server *server, struct local_conf *conf) { int fd; - int len; + socklen_t len; struct sockaddr_un local; if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) @@ -90,7 +90,7 @@ int do_local_server_step(struct local_server *server, void *data, int local_client_create(struct local_conf *conf) { - int len; + socklen_t len; struct sockaddr_un local; int fd; diff --git a/src/mcast.c b/src/mcast.c index e977c0b..8307f26 100644 --- a/src/mcast.c +++ b/src/mcast.c @@ -238,9 +238,9 @@ void mcast_client_destroy(struct mcast_sock *m) free(m); } -int mcast_send(struct mcast_sock *m, void *data, int size) +ssize_t mcast_send(struct mcast_sock *m, void *data, int size) { - int ret; + ssize_t ret; ret = sendto(m->fd, data, @@ -260,9 +260,9 @@ int mcast_send(struct mcast_sock *m, void *data, int size) return ret; } -int mcast_recv(struct mcast_sock *m, void *data, int size) +ssize_t mcast_recv(struct mcast_sock *m, void *data, int size) { - int ret; + ssize_t ret; socklen_t sin_size = sizeof(struct sockaddr_in); ret = recvfrom(m->fd, diff --git a/src/network.c b/src/network.c index da26545..92999a1 100644 --- a/src/network.c +++ b/src/network.c @@ -27,7 +27,7 @@ static unsigned int seq_set, cur_seq; -static int __do_send(struct mcast_sock *m, void *data, int len) +static size_t __do_send(struct mcast_sock *m, void *data, size_t len) { struct nethdr *net = data; @@ -50,7 +50,7 @@ static int __do_send(struct mcast_sock *m, void *data, int len) return mcast_send(m, net, len); } -static int __do_prepare(struct mcast_sock *m, void *data, int len) +static size_t __do_prepare(struct mcast_sock *m, void *data, size_t len) { struct nethdr *net = data; @@ -66,12 +66,12 @@ static int __do_prepare(struct mcast_sock *m, void *data, int len) return len; } -static int __prepare_ctl(struct mcast_sock *m, void *data) +static size_t __prepare_ctl(struct mcast_sock *m, void *data) { return __do_prepare(m, data, NETHDR_ACK_SIZ); } -static int __prepare_data(struct mcast_sock *m, void *data) +static size_t __prepare_data(struct mcast_sock *m, void *data) { struct nethdr *net = (struct nethdr *) data; struct netpld *pld = NETHDR_DATA(net); @@ -79,7 +79,7 @@ static int __prepare_data(struct mcast_sock *m, void *data) return __do_prepare(m, data, ntohs(pld->len) + NETPLD_SIZ + NETHDR_SIZ); } -int prepare_send_netmsg(struct mcast_sock *m, void *data) +size_t prepare_send_netmsg(struct mcast_sock *m, void *data) { int ret = 0; struct nethdr *net = (struct nethdr *) data; @@ -92,8 +92,8 @@ int prepare_send_netmsg(struct mcast_sock *m, void *data) return ret; } -static int tx_buflenmax; -static int tx_buflen = 0; +static size_t tx_buflenmax; +static size_t tx_buflen = 0; static char *tx_buf; #define HEADERSIZ 28 /* IP header (20 bytes) + UDP header 8 (bytes) */ @@ -121,7 +121,7 @@ void mcast_buffered_destroy(void) } /* return 0 if it is not sent, otherwise return 1 */ -int mcast_buffered_send_netmsg(struct mcast_sock *m, void *data, int len) +int mcast_buffered_send_netmsg(struct mcast_sock *m, void *data, size_t len) { int ret = 0; struct nethdr *net = data; @@ -140,9 +140,9 @@ retry: return ret; } -int mcast_buffered_pending_netmsg(struct mcast_sock *m) +ssize_t mcast_buffered_pending_netmsg(struct mcast_sock *m) { - int ret; + ssize_t ret; if (tx_buflen == 0) return 0; @@ -156,7 +156,7 @@ int mcast_buffered_pending_netmsg(struct mcast_sock *m) int mcast_send_netmsg(struct mcast_sock *m, void *data) { int ret; - int len = prepare_send_netmsg(m, data); + size_t len = prepare_send_netmsg(m, data); ret = mcast_buffered_send_netmsg(m, data, len); mcast_buffered_pending_netmsg(m); diff --git a/src/sync-alarm.c b/src/sync-alarm.c index 66727e7..c7cecc8 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -29,7 +29,7 @@ static void refresher(struct alarm_list *a, void *data) { - int len; + size_t len; struct nethdr *net; struct us_conntrack *u = data; diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 1d12002..49c0b2c 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -285,7 +285,7 @@ static void ftfw_send(struct nethdr *net, struct us_conntrack *u) static int tx_queue_xmit(void *data1, const void *data2) { struct nethdr *net = data1; - int len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); + size_t len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); dp("tx_queue sq: %u fl:%u len:%u\n", ntohl(net->seq), ntohs(net->flags), ntohs(net->len)); @@ -307,7 +307,7 @@ static int tx_list_xmit(struct list_head *i, struct us_conntrack *u) { int ret; struct nethdr *net = BUILD_NETMSG(u->ct, NFCT_Q_UPDATE); - int len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); + size_t len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); dp("tx_list sq: %u fl:%u len:%u\n", ntohl(net->seq), ntohs(net->flags), diff --git a/src/sync-mode.c b/src/sync-mode.c index 5974474..b4972a8 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -88,7 +88,8 @@ retry: /* handler for multicast messages received */ static void mcast_handler(void) { - int numbytes, remain; + ssize_t numbytes; + ssize_t remain; char __net[65536], *ptr = __net; /* XXX: maximum MTU for IPv4 */ numbytes = mcast_recv(STATE_SYNC(mcast_server), __net, sizeof(__net)); @@ -339,7 +340,7 @@ static void mcast_send_sync(struct us_conntrack *u, struct nf_conntrack *ct, int query) { - int len; + size_t len; struct nethdr *net; if (!state_helper_verdict(query, ct)) @@ -373,7 +374,7 @@ static int overrun_cb(enum nf_conntrack_msg_type type, if (!cache_test(STATE_SYNC(internal), ct)) { if ((u = cache_update_force(STATE_SYNC(internal), ct))) { - int len; + size_t len; debug_ct(u->ct, "overrun resync"); @@ -397,7 +398,7 @@ static int overrun_purge_step(void *data1, void *data2) ret = nfct_query(h, NFCT_Q_GET, u->ct); if (ret == -1 && errno == ENOENT) { - int len; + size_t len; struct nethdr *net = BUILD_NETMSG(u->ct, NFCT_Q_DESTROY); debug_ct(u->ct, "overrun purge resync"); -- cgit v1.2.3 From b5a30cfc0b58a4ae7b3169ec9a8955b323b85ed6 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Wed, 23 Jan 2008 12:56:05 +0000 Subject: remain is size_t instead of ssize_t to remove the cast --- src/sync-mode.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/sync-mode.c b/src/sync-mode.c index b4972a8..b9fc25c 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -89,7 +89,7 @@ retry: static void mcast_handler(void) { ssize_t numbytes; - ssize_t remain; + size_t remain; char __net[65536], *ptr = __net; /* XXX: maximum MTU for IPv4 */ numbytes = mcast_recv(STATE_SYNC(mcast_server), __net, sizeof(__net)); @@ -100,7 +100,7 @@ static void mcast_handler(void) while (remain > 0) { struct nethdr *net = (struct nethdr *) ptr; - if ((size_t)remain < NETHDR_SIZ) { + if (remain < NETHDR_SIZ) { STATE(malformed)++; break; } -- cgit v1.2.3 From c66ed8fdb8b64fcb8973f6b60a9696b59ba29ee6 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Tue, 29 Jan 2008 13:54:24 +0000 Subject: implement a rb-tree based alarm framework --- ChangeLog | 2 +- include/Makefile.am | 2 +- include/alarm.h | 26 ++-- include/linux_rbtree.h | 160 ++++++++++++++++++++ src/Makefile.am | 2 +- src/alarm.c | 156 +++++++------------- src/cache_timer.c | 12 +- src/rbtree.c | 389 +++++++++++++++++++++++++++++++++++++++++++++++++ src/run.c | 6 - src/sync-alarm.c | 10 +- src/sync-ftfw.c | 4 +- 11 files changed, 631 insertions(+), 138 deletions(-) create mode 100644 include/linux_rbtree.h create mode 100644 src/rbtree.c (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 4cd5eff..dc4efab 100644 --- a/ChangeLog +++ b/ChangeLog @@ -39,7 +39,7 @@ o rename class `buffer' to `queue' which is what it really implements o fix logfiles permissions, do not default to umask o wake up the daemon iff there are real events to handle instead of polling o add support for tagged vlan interfaces in the config file, e.g. eth0.1 -o improve alarm framework based on suggestions from Max Kellerman +o implement a rb-tree based alarm framework o constify queue_iterate() o use list_del_init() and list_empty() to check if a node is in the list o remove unix socket file on exit diff --git a/include/Makefile.am b/include/Makefile.am index e8e7f81..d7f27a9 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -1,5 +1,5 @@ -noinst_HEADERS = alarm.h jhash.h slist.h cache.h linux_list.h \ +noinst_HEADERS = alarm.h jhash.h slist.h cache.h linux_list.h linux_rbtree.h \ sync.h conntrackd.h local.h us-conntrack.h \ debug.h log.h hash.h mcast.h conntrack.h \ state_helper.h network.h ignore.h queue.h \ diff --git a/include/alarm.h b/include/alarm.h index e3e08c1..38aaa01 100644 --- a/include/alarm.h +++ b/include/alarm.h @@ -1,30 +1,28 @@ -#ifndef _TIMER_H_ -#define _TIMER_H_ +#ifndef _ALARM_H_ +#define _ALARM_H_ +#include "linux_rbtree.h" #include "linux_list.h" #include -struct alarm_list { - struct list_head head; +struct alarm_block { + struct rb_node node; + struct list_head list; struct timeval tv; void *data; - void (*function)(struct alarm_list *a, void *data); + void (*function)(struct alarm_block *a, void *data); }; -int init_alarm_hash(void); - -void destroy_alarm_hash(void); - -void init_alarm(struct alarm_list *t, +void init_alarm(struct alarm_block *t, void *data, - void (*fcn)(struct alarm_list *a, void *data)); + void (*fcn)(struct alarm_block *a, void *data)); -void add_alarm(struct alarm_list *alarm, unsigned long sc, unsigned long usc); +void add_alarm(struct alarm_block *alarm, unsigned long sc, unsigned long usc); -void del_alarm(struct alarm_list *alarm); +void del_alarm(struct alarm_block *alarm); -int alarm_pending(struct alarm_list *alarm); +int alarm_pending(struct alarm_block *alarm); struct timeval * get_next_alarm_run(struct timeval *next_alarm); diff --git a/include/linux_rbtree.h b/include/linux_rbtree.h new file mode 100644 index 0000000..ee98891 --- /dev/null +++ b/include/linux_rbtree.h @@ -0,0 +1,160 @@ +/* + Red Black Trees + (C) 1999 Andrea Arcangeli + + 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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + linux/include/linux/rbtree.h + + To use rbtrees you'll have to implement your own insert and search cores. + This will avoid us to use callbacks and to drop drammatically performances. + I know it's not the cleaner way, but in C (not in C++) to get + performances and genericity... + + Some example of insert and search follows here. The search is a plain + normal search over an ordered tree. The insert instead must be implemented + int two steps: as first thing the code must insert the element in + order as a red leaf in the tree, then the support library function + rb_insert_color() must be called. Such function will do the + not trivial work to rebalance the rbtree if necessary. + +----------------------------------------------------------------------- +static inline struct page * rb_search_page_cache(struct inode * inode, + unsigned long offset) +{ + struct rb_node * n = inode->i_rb_page_cache.rb_node; + struct page * page; + + while (n) + { + page = rb_entry(n, struct page, rb_page_cache); + + if (offset < page->offset) + n = n->rb_left; + else if (offset > page->offset) + n = n->rb_right; + else + return page; + } + return NULL; +} + +static inline struct page * __rb_insert_page_cache(struct inode * inode, + unsigned long offset, + struct rb_node * node) +{ + struct rb_node ** p = &inode->i_rb_page_cache.rb_node; + struct rb_node * parent = NULL; + struct page * page; + + while (*p) + { + parent = *p; + page = rb_entry(parent, struct page, rb_page_cache); + + if (offset < page->offset) + p = &(*p)->rb_left; + else if (offset > page->offset) + p = &(*p)->rb_right; + else + return page; + } + + rb_link_node(node, parent, p); + + return NULL; +} + +static inline struct page * rb_insert_page_cache(struct inode * inode, + unsigned long offset, + struct rb_node * node) +{ + struct page * ret; + if ((ret = __rb_insert_page_cache(inode, offset, node))) + goto out; + rb_insert_color(node, &inode->i_rb_page_cache); + out: + return ret; +} +----------------------------------------------------------------------- +*/ + +#ifndef _LINUX_RBTREE_H +#define _LINUX_RBTREE_H + +#include + +struct rb_node +{ + unsigned long rb_parent_color; +#define RB_RED 0 +#define RB_BLACK 1 + struct rb_node *rb_right; + struct rb_node *rb_left; +} __attribute__((aligned(sizeof(long)))); + /* The alignment might seem pointless, but allegedly CRIS needs it */ + +struct rb_root +{ + struct rb_node *rb_node; +}; + + +#define rb_parent(r) ((struct rb_node *)((r)->rb_parent_color & ~3)) +#define rb_color(r) ((r)->rb_parent_color & 1) +#define rb_is_red(r) (!rb_color(r)) +#define rb_is_black(r) rb_color(r) +#define rb_set_red(r) do { (r)->rb_parent_color &= ~1; } while (0) +#define rb_set_black(r) do { (r)->rb_parent_color |= 1; } while (0) + +static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p) +{ + rb->rb_parent_color = (rb->rb_parent_color & 3) | (unsigned long)p; +} +static inline void rb_set_color(struct rb_node *rb, int color) +{ + rb->rb_parent_color = (rb->rb_parent_color & ~1) | color; +} + +#define RB_ROOT { NULL, } +#define rb_entry(ptr, type, member) container_of(ptr, type, member) + +#define RB_EMPTY_ROOT(root) ((root)->rb_node == NULL) +#define RB_EMPTY_NODE(node) (rb_parent(node) == node) +#define RB_CLEAR_NODE(node) (rb_set_parent(node, node)) + +extern void rb_insert_color(struct rb_node *, struct rb_root *); +extern void rb_erase(struct rb_node *, struct rb_root *); + +/* Find logical next and previous nodes in a tree */ +extern struct rb_node *rb_next(struct rb_node *); +extern struct rb_node *rb_prev(struct rb_node *); +extern struct rb_node *rb_first(struct rb_root *); +extern struct rb_node *rb_last(struct rb_root *); + +/* Fast replacement of a single node without remove/rebalance/add/rebalance */ +extern void rb_replace_node(struct rb_node *victim, struct rb_node *new, + struct rb_root *root); + +static inline void rb_link_node(struct rb_node * node, struct rb_node * parent, + struct rb_node ** rb_link) +{ + node->rb_parent_color = (unsigned long )parent; + node->rb_left = node->rb_right = NULL; + + *rb_link = node; +} + +#endif /* _LINUX_RBTREE_H */ diff --git a/src/Makefile.am b/src/Makefile.am index 15628b7..7274a14 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -10,7 +10,7 @@ conntrack_SOURCES = conntrack.c conntrack_LDADD = ../extensions/libct_proto_tcp.la ../extensions/libct_proto_udp.la ../extensions/libct_proto_icmp.la conntrack_LDFLAGS = $(all_libraries) @LIBNETFILTER_CONNTRACK_LIBS@ -conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c \ +conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c rbtree.c \ local.c log.c mcast.c netlink.c \ ignore_pool.c \ cache.c cache_iterators.c \ diff --git a/src/alarm.c b/src/alarm.c index 4b23bd1..5013735 100644 --- a/src/alarm.c +++ b/src/alarm.c @@ -1,5 +1,5 @@ /* - * (C) 2006 by Pablo Neira Ayuso + * (C) 2006-2008 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 @@ -17,41 +17,45 @@ */ #include "alarm.h" -#include "jhash.h" #include #include -#define ALARM_HASH_SIZE 2048 +static struct rb_root alarm_root = RB_ROOT; +static LIST_HEAD(alarm_run_queue); -static struct list_head *alarm_hash; - -void init_alarm(struct alarm_list *t, +void init_alarm(struct alarm_block *t, void *data, - void (*fcn)(struct alarm_list *a, void *data)) + void (*fcn)(struct alarm_block *a, void *data)) { /* initialize the head to check whether a node is inserted */ - INIT_LIST_HEAD(&t->head); + RB_CLEAR_NODE(&t->node); timerclear(&t->tv); t->data = data; t->function = fcn; } -static void -__add_alarm(struct alarm_list *alarm) +static void __add_alarm(struct alarm_block *alarm) { - struct alarm_list *t; - int i = jhash(alarm, sizeof(alarm), 0) % ALARM_HASH_SIZE; + struct rb_node **new = &(alarm_root.rb_node); + struct rb_node *parent = NULL; - list_for_each_entry(t, &alarm_hash[i], head) { - if (timercmp(&alarm->tv, &t->tv, <)) { - list_add_tail(&alarm->head, &t->head); - return; - } + while (*new) { + struct alarm_block *this; + + this = container_of(*new, struct alarm_block, node); + + parent = *new; + if (timercmp(&alarm->tv, &this->tv, <)) + new = &((*new)->rb_left); + else + new = &((*new)->rb_right); } - list_add_tail(&alarm->head, &alarm_hash[i]); + + rb_link_node(&alarm->node, parent, new); + rb_insert_color(&alarm->node, &alarm_root); } -void add_alarm(struct alarm_list *alarm, unsigned long sc, unsigned long usc) +void add_alarm(struct alarm_block *alarm, unsigned long sc, unsigned long usc) { struct timeval tv; @@ -63,16 +67,18 @@ void add_alarm(struct alarm_list *alarm, unsigned long sc, unsigned long usc) __add_alarm(alarm); } -void del_alarm(struct alarm_list *alarm) +void del_alarm(struct alarm_block *alarm) { /* don't remove a non-inserted node */ - if (!list_empty(&alarm->head)) - list_del_init(&alarm->head); + if (!RB_EMPTY_NODE(&alarm->node)) { + rb_erase(&alarm->node, &alarm_root); + RB_CLEAR_NODE(&alarm->node); + } } -int alarm_pending(struct alarm_list *alarm) +int alarm_pending(struct alarm_block *alarm) { - if (list_empty(&alarm->head)) + if (RB_EMPTY_NODE(&alarm->node)) return 0; return 1; @@ -99,101 +105,47 @@ calculate_next_run(struct timeval *cand, struct timeval * get_next_alarm_run(struct timeval *next_run) { - int i; - struct alarm_list *t; + struct rb_node *node = alarm_root.rb_node; struct timeval tv; - struct timeval cand = { - .tv_sec = LONG_MAX, - .tv_usec = LONG_MAX - }; gettimeofday(&tv, NULL); - for (i=0; itv, &cand, <)) { - cand.tv_sec = t->tv.tv_sec; - cand.tv_usec = t->tv.tv_usec; - } - } + node = rb_first(&alarm_root); + if (node) { + struct alarm_block *this; + this = container_of(node, struct alarm_block, node); + return calculate_next_run(&this->tv, &tv, next_run); } - - return calculate_next_run(&cand, &tv, next_run); -} - -static inline int -tv_compare(struct alarm_list *a, struct timeval *cur, struct timeval *cand) -{ - if (timercmp(&a->tv, cur, >)) { - /* select the next alarm candidate */ - if (timercmp(&a->tv, cand, <)) { - cand->tv_sec = a->tv.tv_sec; - cand->tv_usec = a->tv.tv_usec; - } - return 1; - } - return 0; + return NULL; } struct timeval * do_alarm_run(struct timeval *next_run) { - int i; - struct alarm_list *t, *next, *prev; + struct rb_node *node = alarm_root.rb_node; + struct alarm_block *this, *tmp; struct timeval tv; - struct timeval cand = { - .tv_sec = LONG_MAX, - .tv_usec = LONG_MAX - }; gettimeofday(&tv, NULL); - for (i=0; ihead.prev, - struct alarm_list, - head); - - del_alarm(t); - t->function(t, t->data); - - /* Special case: One deleted node is inserted - * again in the same place */ - if (next->head.prev == &prev->head) { - t = list_entry(next->head.prev, - struct alarm_list, - head); - if (tv_compare(t, &tv, &cand)) - break; - } - } - } + node = rb_first(&alarm_root); + while (node) { + this = container_of(node, struct alarm_block, node); - return calculate_next_run(&cand, &tv, next_run); -} + if (timercmp(&this->tv, &tv, >)) + break; -int init_alarm_hash(void) -{ - int i; + node = rb_next(node); - alarm_hash = malloc(sizeof(struct list_head) * ALARM_HASH_SIZE); - if (alarm_hash == NULL) - return -1; - - for (i=0; ilist, &alarm_run_queue); + } - return 0; -} + list_for_each_entry_safe(this, tmp, &alarm_run_queue, list) { + list_del(&this->list); + rb_erase(&this->node, &alarm_root); + RB_CLEAR_NODE(&this->node); + this->function(this, this->data); + } -void destroy_alarm_hash(void) -{ - free(alarm_hash); + return get_next_alarm_run(next_run); } diff --git a/src/cache_timer.c b/src/cache_timer.c index fe997ec..6619c2c 100644 --- a/src/cache_timer.c +++ b/src/cache_timer.c @@ -24,7 +24,7 @@ #include -static void timeout(struct alarm_list *a, void *data) +static void timeout(struct alarm_block *a, void *data) { struct us_conntrack *u = data; @@ -34,7 +34,7 @@ static void timeout(struct alarm_list *a, void *data) static void timer_add(struct us_conntrack *u, void *data) { - struct alarm_list *alarm = data; + struct alarm_block *alarm = data; init_alarm(alarm, u, timeout); add_alarm(alarm, CONFIG(cache_timeout), 0); @@ -42,20 +42,20 @@ static void timer_add(struct us_conntrack *u, void *data) static void timer_update(struct us_conntrack *u, void *data) { - struct alarm_list *alarm = data; + struct alarm_block *alarm = data; add_alarm(alarm, CONFIG(cache_timeout), 0); } static void timer_destroy(struct us_conntrack *u, void *data) { - struct alarm_list *alarm = data; + struct alarm_block *alarm = data; del_alarm(alarm); } static int timer_dump(struct us_conntrack *u, void *data, char *buf, int type) { struct timeval tv, tmp; - struct alarm_list *alarm = data; + struct alarm_block *alarm = data; if (type == NFCT_O_XML) return 0; @@ -69,7 +69,7 @@ static int timer_dump(struct us_conntrack *u, void *data, char *buf, int type) } struct cache_feature timer_feature = { - .size = sizeof(struct alarm_list), + .size = sizeof(struct alarm_block), .add = timer_add, .update = timer_update, .destroy = timer_destroy, diff --git a/src/rbtree.c b/src/rbtree.c new file mode 100644 index 0000000..199e2bb --- /dev/null +++ b/src/rbtree.c @@ -0,0 +1,389 @@ +/* + Red Black Trees + (C) 1999 Andrea Arcangeli + (C) 2002 David Woodhouse + + 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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + linux/lib/rbtree.c +*/ + +#include "linux_rbtree.h" + +static void __rb_rotate_left(struct rb_node *node, struct rb_root *root) +{ + struct rb_node *right = node->rb_right; + struct rb_node *parent = rb_parent(node); + + if ((node->rb_right = right->rb_left)) + rb_set_parent(right->rb_left, node); + right->rb_left = node; + + rb_set_parent(right, parent); + + if (parent) + { + if (node == parent->rb_left) + parent->rb_left = right; + else + parent->rb_right = right; + } + else + root->rb_node = right; + rb_set_parent(node, right); +} + +static void __rb_rotate_right(struct rb_node *node, struct rb_root *root) +{ + struct rb_node *left = node->rb_left; + struct rb_node *parent = rb_parent(node); + + if ((node->rb_left = left->rb_right)) + rb_set_parent(left->rb_right, node); + left->rb_right = node; + + rb_set_parent(left, parent); + + if (parent) + { + if (node == parent->rb_right) + parent->rb_right = left; + else + parent->rb_left = left; + } + else + root->rb_node = left; + rb_set_parent(node, left); +} + +void rb_insert_color(struct rb_node *node, struct rb_root *root) +{ + struct rb_node *parent, *gparent; + + while ((parent = rb_parent(node)) && rb_is_red(parent)) + { + gparent = rb_parent(parent); + + if (parent == gparent->rb_left) + { + { + register struct rb_node *uncle = gparent->rb_right; + if (uncle && rb_is_red(uncle)) + { + rb_set_black(uncle); + rb_set_black(parent); + rb_set_red(gparent); + node = gparent; + continue; + } + } + + if (parent->rb_right == node) + { + register struct rb_node *tmp; + __rb_rotate_left(parent, root); + tmp = parent; + parent = node; + node = tmp; + } + + rb_set_black(parent); + rb_set_red(gparent); + __rb_rotate_right(gparent, root); + } else { + { + register struct rb_node *uncle = gparent->rb_left; + if (uncle && rb_is_red(uncle)) + { + rb_set_black(uncle); + rb_set_black(parent); + rb_set_red(gparent); + node = gparent; + continue; + } + } + + if (parent->rb_left == node) + { + register struct rb_node *tmp; + __rb_rotate_right(parent, root); + tmp = parent; + parent = node; + node = tmp; + } + + rb_set_black(parent); + rb_set_red(gparent); + __rb_rotate_left(gparent, root); + } + } + + rb_set_black(root->rb_node); +} + +static void __rb_erase_color(struct rb_node *node, struct rb_node *parent, + struct rb_root *root) +{ + struct rb_node *other; + + while ((!node || rb_is_black(node)) && node != root->rb_node) + { + if (parent->rb_left == node) + { + other = parent->rb_right; + if (rb_is_red(other)) + { + rb_set_black(other); + rb_set_red(parent); + __rb_rotate_left(parent, root); + other = parent->rb_right; + } + if ((!other->rb_left || rb_is_black(other->rb_left)) && + (!other->rb_right || rb_is_black(other->rb_right))) + { + rb_set_red(other); + node = parent; + parent = rb_parent(node); + } + else + { + if (!other->rb_right || rb_is_black(other->rb_right)) + { + struct rb_node *o_left; + if ((o_left = other->rb_left)) + rb_set_black(o_left); + rb_set_red(other); + __rb_rotate_right(other, root); + other = parent->rb_right; + } + rb_set_color(other, rb_color(parent)); + rb_set_black(parent); + if (other->rb_right) + rb_set_black(other->rb_right); + __rb_rotate_left(parent, root); + node = root->rb_node; + break; + } + } + else + { + other = parent->rb_left; + if (rb_is_red(other)) + { + rb_set_black(other); + rb_set_red(parent); + __rb_rotate_right(parent, root); + other = parent->rb_left; + } + if ((!other->rb_left || rb_is_black(other->rb_left)) && + (!other->rb_right || rb_is_black(other->rb_right))) + { + rb_set_red(other); + node = parent; + parent = rb_parent(node); + } + else + { + if (!other->rb_left || rb_is_black(other->rb_left)) + { + register struct rb_node *o_right; + if ((o_right = other->rb_right)) + rb_set_black(o_right); + rb_set_red(other); + __rb_rotate_left(other, root); + other = parent->rb_left; + } + rb_set_color(other, rb_color(parent)); + rb_set_black(parent); + if (other->rb_left) + rb_set_black(other->rb_left); + __rb_rotate_right(parent, root); + node = root->rb_node; + break; + } + } + } + if (node) + rb_set_black(node); +} + +void rb_erase(struct rb_node *node, struct rb_root *root) +{ + struct rb_node *child, *parent; + int color; + + if (!node->rb_left) + child = node->rb_right; + else if (!node->rb_right) + child = node->rb_left; + else + { + struct rb_node *old = node, *left; + + node = node->rb_right; + while ((left = node->rb_left) != NULL) + node = left; + child = node->rb_right; + parent = rb_parent(node); + color = rb_color(node); + + if (child) + rb_set_parent(child, parent); + if (parent == old) { + parent->rb_right = child; + parent = node; + } else + parent->rb_left = child; + + node->rb_parent_color = old->rb_parent_color; + node->rb_right = old->rb_right; + node->rb_left = old->rb_left; + + if (rb_parent(old)) + { + if (rb_parent(old)->rb_left == old) + rb_parent(old)->rb_left = node; + else + rb_parent(old)->rb_right = node; + } else + root->rb_node = node; + + rb_set_parent(old->rb_left, node); + if (old->rb_right) + rb_set_parent(old->rb_right, node); + goto color; + } + + parent = rb_parent(node); + color = rb_color(node); + + if (child) + rb_set_parent(child, parent); + if (parent) + { + if (parent->rb_left == node) + parent->rb_left = child; + else + parent->rb_right = child; + } + else + root->rb_node = child; + + color: + if (color == RB_BLACK) + __rb_erase_color(child, parent, root); +} + +/* + * This function returns the first node (in sort order) of the tree. + */ +struct rb_node *rb_first(struct rb_root *root) +{ + struct rb_node *n; + + n = root->rb_node; + if (!n) + return NULL; + while (n->rb_left) + n = n->rb_left; + return n; +} + +struct rb_node *rb_last(struct rb_root *root) +{ + struct rb_node *n; + + n = root->rb_node; + if (!n) + return NULL; + while (n->rb_right) + n = n->rb_right; + return n; +} + +struct rb_node *rb_next(struct rb_node *node) +{ + struct rb_node *parent; + + if (rb_parent(node) == node) + return NULL; + + /* If we have a right-hand child, go down and then left as far + as we can. */ + if (node->rb_right) { + node = node->rb_right; + while (node->rb_left) + node=node->rb_left; + return node; + } + + /* No right-hand children. Everything down and left is + smaller than us, so any 'next' node must be in the general + direction of our parent. Go up the tree; any time the + ancestor is a right-hand child of its parent, keep going + up. First time it's a left-hand child of its parent, said + parent is our 'next' node. */ + while ((parent = rb_parent(node)) && node == parent->rb_right) + node = parent; + + return parent; +} + +struct rb_node *rb_prev(struct rb_node *node) +{ + struct rb_node *parent; + + if (rb_parent(node) == node) + return NULL; + + /* If we have a left-hand child, go down and then right as far + as we can. */ + if (node->rb_left) { + node = node->rb_left; + while (node->rb_right) + node=node->rb_right; + return node; + } + + /* No left-hand children. Go up till we find an ancestor which + is a right-hand child of its parent */ + while ((parent = rb_parent(node)) && node == parent->rb_left) + node = parent; + + return parent; +} + +void rb_replace_node(struct rb_node *victim, struct rb_node *new, + struct rb_root *root) +{ + struct rb_node *parent = rb_parent(victim); + + /* Set the surrounding nodes to point to the replacement */ + if (parent) { + if (victim == parent->rb_left) + parent->rb_left = new; + else + parent->rb_right = new; + } else { + root->rb_node = new; + } + if (victim->rb_left) + rb_set_parent(victim->rb_left, new); + if (victim->rb_right) + rb_set_parent(victim->rb_right, new); + + /* Copy the pointers/colour from the victim to the replacement */ + *new = *victim; +} diff --git a/src/run.c b/src/run.c index 876e131..f5832bc 100644 --- a/src/run.c +++ b/src/run.c @@ -42,7 +42,6 @@ void killer(int foo) ignore_pool_destroy(STATE(ignore_pool)); local_server_destroy(&STATE(local)); STATE(mode)->kill(); - destroy_alarm_hash(); unlink(CONFIG(lockfile)); dlog(LOG_NOTICE, "---- shutdown received ----"); close_log(); @@ -103,11 +102,6 @@ init(void) STATE(mode) = &stats_mode; } - if (init_alarm_hash() == -1) { - dlog(LOG_ERR, "can't initialize alarm hash"); - return -1; - } - /* Initialization */ if (STATE(mode)->init() == -1) { dlog(LOG_ERR, "initialization failed"); diff --git a/src/sync-alarm.c b/src/sync-alarm.c index c7cecc8..4473af2 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -27,7 +27,7 @@ #include #include -static void refresher(struct alarm_list *a, void *data) +static void refresher(struct alarm_block *a, void *data) { size_t len; struct nethdr *net; @@ -46,7 +46,7 @@ static void refresher(struct alarm_list *a, void *data) static void cache_alarm_add(struct us_conntrack *u, void *data) { - struct alarm_list *alarm = data; + struct alarm_block *alarm = data; init_alarm(alarm, u, refresher); add_alarm(alarm, @@ -56,7 +56,7 @@ static void cache_alarm_add(struct us_conntrack *u, void *data) static void cache_alarm_update(struct us_conntrack *u, void *data) { - struct alarm_list *alarm = data; + struct alarm_block *alarm = data; add_alarm(alarm, random() % CONFIG(refresh) + 1, ((random() % 5 + 1) * 200000) - 1); @@ -64,12 +64,12 @@ static void cache_alarm_update(struct us_conntrack *u, void *data) static void cache_alarm_destroy(struct us_conntrack *u, void *data) { - struct alarm_list *alarm = data; + struct alarm_block *alarm = data; del_alarm(alarm); } static struct cache_extra cache_alarm_extra = { - .size = sizeof(struct alarm_list), + .size = sizeof(struct alarm_block), .add = cache_alarm_add, .update = cache_alarm_update, .destroy = cache_alarm_destroy diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 49c0b2c..cac25d0 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -83,9 +83,9 @@ static void tx_queue_add_ctlmsg(uint32_t flags, uint32_t from, uint32_t to) queue_add(tx_queue, &ack, NETHDR_ACK_SIZ); } -static struct alarm_list alive_alarm; +static struct alarm_block alive_alarm; -static void do_alive_alarm(struct alarm_list *a, void *data) +static void do_alive_alarm(struct alarm_block *a, void *data) { tx_queue_add_ctlmsg(NET_F_ALIVE, 0, 0); -- cgit v1.2.3 From 6f7bc84fb819e87a9145394b0e08fd194b1497da Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Sat, 2 Feb 2008 04:35:05 +0000 Subject: add IPv6 support to conntrackd --- ChangeLog | 1 + TODO | 2 +- include/cache.h | 2 +- include/ignore.h | 5 ++- include/mcast.h | 3 +- src/cache.c | 107 ++++++++++++++++++++++++++++++++------------------- src/ignore_pool.c | 65 ++++++++++++++++++------------- src/mcast.c | 18 +++++---- src/read_config_yy.y | 99 ++++++++++++++++++++++++++++++++++------------- src/stats-mode.c | 1 - src/sync-mode.c | 2 - 11 files changed, 197 insertions(+), 108 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index dc4efab..aa9b3d2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -16,6 +16,7 @@ o cleanup error message o add support for -E -o xml,timestamp = conntrackd = +o Add IPv6 support o Remove window tracking disabling limitation (requires Linux kernel >= 2.6.22) o syslog support (based on patch from Simon Lodal) o add CacheWriteThrough clause: external cache write through policy diff --git a/TODO b/TODO index 04923fc..9450aeb 100644 --- a/TODO +++ b/TODO @@ -18,7 +18,7 @@ by dificulty levels: = Requires some work = [ ] study better keepalived transitions - [ ] test/fix ipv6 support + [X] fix ipv6 support [X] add support setup related conntracks [ ] NAT sequence adjustment support diff --git a/include/cache.h b/include/cache.h index a2b2005..f5afbe5 100644 --- a/include/cache.h +++ b/include/cache.h @@ -75,7 +75,7 @@ struct cache_extra { struct nf_conntrack; -struct cache *cache_create(const char *name, unsigned int features, uint8_t proto, struct cache_extra *extra); +struct cache *cache_create(const char *name, unsigned int features, struct cache_extra *extra); void cache_destroy(struct cache *e); struct us_conntrack *cache_add(struct cache *c, struct nf_conntrack *ct); diff --git a/include/ignore.h b/include/ignore.h index efb375d..e5e96ff 100644 --- a/include/ignore.h +++ b/include/ignore.h @@ -7,11 +7,12 @@ struct nf_conntrack; struct ignore_pool { struct hashtable *h; + struct hashtable *h6; }; -struct ignore_pool *ignore_pool_create(uint8_t family); +struct ignore_pool *ignore_pool_create(void); void ignore_pool_destroy(struct ignore_pool *ip); -int ignore_pool_add(struct ignore_pool *ip, void *data); +int ignore_pool_add(struct ignore_pool *ip, void *data, uint8_t family); int ignore_pool_test(struct ignore_pool *ip, struct nf_conntrack *ct); #endif diff --git a/include/mcast.h b/include/mcast.h index 4e89c72..c2fd3ec 100644 --- a/include/mcast.h +++ b/include/mcast.h @@ -16,7 +16,7 @@ struct mcast_conf { } in; union { struct in_addr interface_addr; - struct in6_addr interface_addr6; + unsigned int interface_index6; } ifa; int mtu; char iface[IFNAMSIZ]; @@ -34,6 +34,7 @@ struct mcast_sock { struct sockaddr_in ipv4; struct sockaddr_in6 ipv6; } addr; + socklen_t sockaddr_len; struct mcast_stats stats; }; diff --git a/src/cache.c b/src/cache.c index 2f0e57a..73d539a 100644 --- a/src/cache.c +++ b/src/cache.c @@ -19,6 +19,7 @@ #include "cache.h" #include "jhash.h" #include "hash.h" +#include "log.h" #include "us-conntrack.h" #include "conntrackd.h" @@ -27,11 +28,9 @@ #include #include -static uint32_t hash(const void *data, struct hashtable *table) +static uint32_t __hash4(const struct nf_conntrack *ct, struct hashtable *table) { unsigned int a, b; - const struct us_conntrack *u = data; - struct nf_conntrack *ct = u->ct; a = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV4_SRC), sizeof(uint32_t), ((nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO) << 16) | @@ -51,11 +50,9 @@ static uint32_t hash(const void *data, struct hashtable *table) return ((uint64_t)jhash_2words(a, b, 0) * table->hashsize) >> 32; } -static uint32_t hash6(const void *data, struct hashtable *table) +static uint32_t __hash6(const struct nf_conntrack *ct, struct hashtable *table) { unsigned int a, b; - const struct us_conntrack *u = data; - struct nf_conntrack *ct = u->ct; a = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV6_SRC), sizeof(uint32_t)*4, ((nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO) << 16) | @@ -68,12 +65,30 @@ static uint32_t hash6(const void *data, struct hashtable *table) return ((uint64_t)jhash_2words(a, b, 0) * table->hashsize) >> 32; } +static uint32_t hash(const void *data, struct hashtable *table) +{ + int ret = 0; + const struct us_conntrack *u = data; + + switch(nfct_get_attr_u8(u->ct, ATTR_L3PROTO)) { + case AF_INET: + ret = __hash4(u->ct, table); + break; + case AF_INET6: + ret = __hash6(u->ct, table); + break; + default: + dlog(LOG_ERR, "unknown layer 3 proto in hash"); + break; + } + + return ret; +} + static int __compare(const struct nf_conntrack *ct1, const struct nf_conntrack *ct2) { - return ((nfct_get_attr_u8(ct1, ATTR_ORIG_L3PROTO) == - nfct_get_attr_u8(ct2, ATTR_ORIG_L3PROTO)) && - (nfct_get_attr_u8(ct1, ATTR_ORIG_L4PROTO) == + return ((nfct_get_attr_u8(ct1, ATTR_ORIG_L4PROTO) == nfct_get_attr_u8(ct2, ATTR_ORIG_L4PROTO)) && (nfct_get_attr_u16(ct1, ATTR_ORIG_PORT_SRC) == nfct_get_attr_u16(ct2, ATTR_ORIG_PORT_SRC)) && @@ -85,11 +100,9 @@ static int __compare(const struct nf_conntrack *ct1, nfct_get_attr_u16(ct2, ATTR_REPL_PORT_DST))); } -static int compare(const void *data1, const void *data2) +static int +__compare4(const struct us_conntrack *u1, const struct us_conntrack *u2) { - const struct us_conntrack *u1 = data1; - const struct us_conntrack *u2 = data2; - return ((nfct_get_attr_u32(u1->ct, ATTR_ORIG_IPV4_SRC) == nfct_get_attr_u32(u2->ct, ATTR_ORIG_IPV4_SRC)) && (nfct_get_attr_u32(u1->ct, ATTR_ORIG_IPV4_DST) == @@ -101,20 +114,46 @@ static int compare(const void *data1, const void *data2) __compare(u1->ct, u2->ct)); } -static int compare6(const void *data1, const void *data2) +static int +__compare6(const struct us_conntrack *u1, const struct us_conntrack *u2) { + return ((memcmp(nfct_get_attr(u1->ct, ATTR_ORIG_IPV6_SRC), + nfct_get_attr(u2->ct, ATTR_ORIG_IPV6_SRC), + sizeof(uint32_t)*4) == 0) && + (memcmp(nfct_get_attr(u1->ct, ATTR_ORIG_IPV6_DST), + nfct_get_attr(u2->ct, ATTR_ORIG_IPV6_DST), + sizeof(uint32_t)*4) == 0) && + (memcmp(nfct_get_attr(u1->ct, ATTR_REPL_IPV6_SRC), + nfct_get_attr(u2->ct, ATTR_REPL_IPV6_SRC), + sizeof(uint32_t)*4) == 0) && + (memcmp(nfct_get_attr(u1->ct, ATTR_REPL_IPV6_DST), + nfct_get_attr(u2->ct, ATTR_REPL_IPV6_DST), + sizeof(uint32_t)*4) == 0) && + __compare(u1->ct, u2->ct)); +} + +static int compare(const void *data1, const void *data2) +{ + int ret = 0; const struct us_conntrack *u1 = data1; const struct us_conntrack *u2 = data2; - return ((nfct_get_attr_u32(u1->ct, ATTR_ORIG_IPV6_SRC) == - nfct_get_attr_u32(u2->ct, ATTR_ORIG_IPV6_SRC)) && - (nfct_get_attr_u32(u1->ct, ATTR_ORIG_IPV6_DST) == - nfct_get_attr_u32(u2->ct, ATTR_ORIG_IPV6_DST)) && - (nfct_get_attr_u32(u1->ct, ATTR_REPL_IPV6_SRC) == - nfct_get_attr_u32(u2->ct, ATTR_REPL_IPV6_SRC)) && - (nfct_get_attr_u32(u1->ct, ATTR_REPL_IPV6_DST) == - nfct_get_attr_u32(u2->ct, ATTR_REPL_IPV6_DST)) && - __compare(u1->ct, u2->ct)); + if (nfct_get_attr_u8(u1->ct, ATTR_L3PROTO) != + nfct_get_attr_u8(u2->ct, ATTR_L3PROTO)) + return ret; + + switch(nfct_get_attr_u8(u1->ct, ATTR_L3PROTO)) { + case AF_INET: + ret = __compare4(u1, u2); + break; + case AF_INET6: + ret = __compare6(u1, u2); + break; + default: + dlog(LOG_ERR, "unknown layer 3 in compare"); + break; + } + return ret; } struct cache_feature *cache_feature[CACHE_MAX_FEATURE] = { @@ -125,7 +164,6 @@ struct cache_feature *cache_feature[CACHE_MAX_FEATURE] = { struct cache *cache_create(const char *name, unsigned int features, - uint8_t proto, struct cache_extra *extra) { size_t size = sizeof(struct us_conntrack); @@ -175,22 +213,11 @@ struct cache *cache_create(const char *name, } memcpy(c->feature_offset, feature_offset, sizeof(unsigned int) * j); - switch(proto) { - case AF_INET: - c->h = hashtable_create(CONFIG(hashsize), - CONFIG(limit), - size, - hash, - compare); - break; - case AF_INET6: - c->h = hashtable_create(CONFIG(hashsize), - CONFIG(limit), - size, - hash6, - compare6); - break; - } + c->h = hashtable_create(CONFIG(hashsize), + CONFIG(limit), + size, + hash, + compare); if (!c->h) { free(c->features); diff --git a/src/ignore_pool.c b/src/ignore_pool.c index 2d898d1..027d628 100644 --- a/src/ignore_pool.c +++ b/src/ignore_pool.c @@ -26,7 +26,7 @@ #include #include -/* XXX: These should be configurable */ +/* XXX: These should be configurable, better use a rb-tree */ #define IGNORE_POOL_SIZE 128 #define IGNORE_POOL_LIMIT INT_MAX @@ -55,7 +55,7 @@ static int compare6(const void *data1, const void *data2) return memcmp(data1, data2, sizeof(uint32_t)*4) == 0; } -struct ignore_pool *ignore_pool_create(uint8_t proto) +struct ignore_pool *ignore_pool_create(void) { struct ignore_pool *ip; @@ -64,24 +64,23 @@ struct ignore_pool *ignore_pool_create(uint8_t proto) return NULL; memset(ip, 0, sizeof(struct ignore_pool)); - switch(proto) { - case AF_INET: - ip->h = hashtable_create(IGNORE_POOL_SIZE, - IGNORE_POOL_LIMIT, - sizeof(uint32_t), - hash, - compare); - break; - case AF_INET6: - ip->h = hashtable_create(IGNORE_POOL_SIZE, - IGNORE_POOL_LIMIT, - sizeof(uint32_t)*4, - hash6, - compare6); - break; + ip->h = hashtable_create(IGNORE_POOL_SIZE, + IGNORE_POOL_LIMIT, + sizeof(uint32_t), + hash, + compare); + if (!ip->h) { + free(ip); + return NULL; } - if (!ip->h) { + ip->h6 = hashtable_create(IGNORE_POOL_SIZE, + IGNORE_POOL_LIMIT, + sizeof(uint32_t)*4, + hash6, + compare6); + if (!ip->h6) { + free(ip->h); free(ip); return NULL; } @@ -92,20 +91,31 @@ struct ignore_pool *ignore_pool_create(uint8_t proto) void ignore_pool_destroy(struct ignore_pool *ip) { hashtable_destroy(ip->h); + hashtable_destroy(ip->h6); free(ip); } -int ignore_pool_add(struct ignore_pool *ip, void *data) +int ignore_pool_add(struct ignore_pool *ip, void *data, uint8_t family) { - if (!hashtable_add(ip->h, data)) - return 0; - + switch(family) { + case AF_INET: + if (!hashtable_add(ip->h, data)) + return 0; + break; + case AF_INET6: + if (!hashtable_add(ip->h6, data)) + return 0; + break; + } return 1; } static int __ignore_pool_test_ipv4(struct ignore_pool *ip, struct nf_conntrack *ct) { + if (!ip->h) + return 0; + return (hashtable_test(ip->h, nfct_get_attr(ct, ATTR_ORIG_IPV4_SRC)) || hashtable_test(ip->h, nfct_get_attr(ct, ATTR_ORIG_IPV4_DST)) || hashtable_test(ip->h, nfct_get_attr(ct, ATTR_REPL_IPV4_SRC)) || @@ -115,10 +125,13 @@ __ignore_pool_test_ipv4(struct ignore_pool *ip, struct nf_conntrack *ct) static int __ignore_pool_test_ipv6(struct ignore_pool *ip, struct nf_conntrack *ct) { - return (hashtable_test(ip->h, nfct_get_attr(ct, ATTR_ORIG_IPV6_SRC)) || - hashtable_test(ip->h, nfct_get_attr(ct, ATTR_ORIG_IPV6_DST)) || - hashtable_test(ip->h, nfct_get_attr(ct, ATTR_REPL_IPV6_SRC)) || - hashtable_test(ip->h, nfct_get_attr(ct, ATTR_REPL_IPV6_DST))); + if (!ip->h6) + return 0; + + return (hashtable_test(ip->h6, nfct_get_attr(ct, ATTR_ORIG_IPV6_SRC)) || + hashtable_test(ip->h6, nfct_get_attr(ct, ATTR_ORIG_IPV6_DST)) || + hashtable_test(ip->h6, nfct_get_attr(ct, ATTR_REPL_IPV6_SRC)) || + hashtable_test(ip->h6, nfct_get_attr(ct, ATTR_REPL_IPV6_DST))); } int ignore_pool_test(struct ignore_pool *ip, struct nf_conntrack *ct) diff --git a/src/mcast.c b/src/mcast.c index 8307f26..f945511 100644 --- a/src/mcast.c +++ b/src/mcast.c @@ -51,17 +51,20 @@ struct mcast_sock *mcast_server_create(struct mcast_conf *conf) m->addr.ipv4.sin_family = AF_INET; m->addr.ipv4.sin_port = htons(conf->port); m->addr.ipv4.sin_addr.s_addr = htonl(INADDR_ANY); + + m->sockaddr_len = sizeof(struct sockaddr_in); break; case AF_INET6: memcpy(&mreq.ipv6.ipv6mr_multiaddr, &conf->in.inet_addr6, sizeof(uint32_t) * 4); - memcpy(&mreq.ipv6.ipv6mr_interface, &conf->ifa.interface_addr6, - sizeof(uint32_t) * 4); + mreq.ipv6.ipv6mr_interface = conf->ifa.interface_index6; m->addr.ipv6.sin6_family = AF_INET6; m->addr.ipv6.sin6_port = htons(conf->port); m->addr.ipv6.sin6_addr = in6addr_any; + + m->sockaddr_len = sizeof(struct sockaddr_in6); break; } @@ -93,8 +96,7 @@ struct mcast_sock *mcast_server_create(struct mcast_conf *conf) return NULL; } - if (bind(m->fd, (struct sockaddr *) &m->addr, - sizeof(struct sockaddr)) == -1) { + if (bind(m->fd, (struct sockaddr *) &m->addr, m->sockaddr_len) == -1) { debug("mcast_sock_server_create:bind"); close(m->fd); free(m); @@ -139,6 +141,7 @@ __mcast_client_create_ipv4(struct mcast_sock *m, struct mcast_conf *conf) m->addr.ipv4.sin_family = AF_INET; m->addr.ipv4.sin_port = htons(conf->port); m->addr.ipv4.sin_addr = conf->in.inet_addr; + m->sockaddr_len = sizeof(struct sockaddr_in); if (setsockopt(m->fd, IPPROTO_IP, IP_MULTICAST_LOOP, &no, sizeof(int)) < 0) { @@ -168,6 +171,7 @@ __mcast_client_create_ipv6(struct mcast_sock *m, struct mcast_conf *conf) memcpy(&m->addr.ipv6.sin6_addr, &conf->in.inet_addr6, sizeof(struct in6_addr)); + m->sockaddr_len = sizeof(struct sockaddr_in6); if (setsockopt(m->fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &no, sizeof(int)) < 0) { @@ -177,8 +181,8 @@ __mcast_client_create_ipv6(struct mcast_sock *m, struct mcast_conf *conf) } if (setsockopt(m->fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, - &conf->ifa.interface_addr, - sizeof(struct in_addr)) == -1) { + &conf->ifa.interface_index6, + sizeof(unsigned int)) == -1) { debug("mcast_sock_client_create:setsockopt3"); close(m->fd); return -1; @@ -247,7 +251,7 @@ ssize_t mcast_send(struct mcast_sock *m, void *data, int size) size, 0, (struct sockaddr *) &m->addr, - sizeof(struct sockaddr)); + m->sockaddr_len); if (ret == -1) { debug("mcast_sock_send"); m->stats.error++; diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 0ba5331..86fee9b 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -177,37 +177,63 @@ ignore_traffic_options : ignore_traffic_option : T_IPV4_ADDR T_IP { union inet_address ip; - int family = 0; memset(&ip, 0, sizeof(union inet_address)); - if (inet_aton($2, &ip.ipv4)) - family = AF_INET; -#ifdef HAVE_INET_PTON_IPV6 - else if (inet_pton(AF_INET6, $2, &ip.ipv6) > 0) - family = AF_INET6; -#endif + if (!inet_aton($2, &ip.ipv4)) { + fprintf(stderr, "%s is not a valid IPv4, ignoring", $2); + break; + } + + if (!STATE(ignore_pool)) { + STATE(ignore_pool) = ignore_pool_create(); + if (!STATE(ignore_pool)) { + fprintf(stderr, "Can't create ignore pool!\n"); + exit(EXIT_FAILURE); + } + } + + if (!ignore_pool_add(STATE(ignore_pool), &ip, AF_INET)) { + if (errno == EEXIST) + fprintf(stderr, "IP %s is repeated " + "in the ignore pool\n", $2); + if (errno == ENOSPC) + fprintf(stderr, "Too many IP in the ignore pool!\n"); + } +}; - if (!family) { - fprintf(stderr, "%s is not a valid IP, ignoring", $2); +ignore_traffic_option : T_IPV6_ADDR T_IP +{ + union inet_address ip; + + memset(&ip, 0, sizeof(union inet_address)); + +#ifdef HAVE_INET_PTON_IPV6 + if (inet_pton(AF_INET6, $2, &ip.ipv6) <= 0) { + fprintf(stderr, "%s is not a valid IPv6, ignoring", $2); break; } +#else + fprintf(stderr, "Cannot find inet_pton(), IPv6 unsupported!"); + break; +#endif if (!STATE(ignore_pool)) { - STATE(ignore_pool) = ignore_pool_create(family); + STATE(ignore_pool) = ignore_pool_create(); if (!STATE(ignore_pool)) { fprintf(stderr, "Can't create ignore pool!\n"); exit(EXIT_FAILURE); } } - if (!ignore_pool_add(STATE(ignore_pool), &ip)) { + if (!ignore_pool_add(STATE(ignore_pool), &ip, AF_INET6)) { if (errno == EEXIST) fprintf(stderr, "IP %s is repeated " "in the ignore pool\n", $2); if (errno == ENOSPC) fprintf(stderr, "Too many IP in the ignore pool!\n"); } + }; multicast_line : T_MULTICAST '{' multicast_options '}'; @@ -235,8 +261,13 @@ multicast_option : T_IPV4_ADDR T_IP multicast_option : T_IPV6_ADDR T_IP { #ifdef HAVE_INET_PTON_IPV6 - if (inet_pton(AF_INET6, $2, &conf.mcast.in) <= 0) + if (inet_pton(AF_INET6, $2, &conf.mcast.in) <= 0) { fprintf(stderr, "%s is not a valid IPv6 address\n", $2); + break; + } +#else + fprintf(stderr, "Cannot find inet_pton(), IPv6 unsupported!"); + break; #endif if (conf.mcast.ipproto == AF_INET) { @@ -247,6 +278,19 @@ multicast_option : T_IPV6_ADDR T_IP } conf.mcast.ipproto = AF_INET6; + + if (conf.mcast.iface[0] && !conf.mcast.ifa.interface_index6) { + unsigned int idx; + + idx = if_nametoindex($2); + if (!idx) { + fprintf(stderr, "%s is an invalid interface.\n", $2); + break; + } + + conf.mcast.ifa.interface_index6 = idx; + conf.mcast.ipproto = AF_INET6; + } }; multicast_option : T_IPV4_IFACE T_IP @@ -268,24 +312,25 @@ multicast_option : T_IPV4_IFACE T_IP multicast_option : T_IPV6_IFACE T_IP { -#ifdef HAVE_INET_PTON_IPV6 - if (inet_pton(AF_INET6, $2, &conf.mcast.ifa) <= 0) - fprintf(stderr, "%s is not a valid IPv6 address\n", $2); -#endif - - if (conf.mcast.ipproto == AF_INET) { - fprintf(stderr, "Your multicast interface is IPv6 but " - "is binded to an IPv4 interface? Surely " - "this is not what you want\n"); - break; - } - - conf.mcast.ipproto = AF_INET6; -}; + fprintf(stderr, "IPv6_interface not required for IPv6, ignoring.\n"); +} multicast_option : T_IFACE T_STRING { strncpy(conf.mcast.iface, $2, IFNAMSIZ); + + if (conf.mcast.ipproto == AF_INET6) { + unsigned int idx; + + idx = if_nametoindex($2); + if (!idx) { + fprintf(stderr, "%s is an invalid interface.\n", $2); + break; + } + + conf.mcast.ifa.interface_index6 = idx; + conf.mcast.ipproto = AF_INET6; + } }; multicast_option : T_BACKLOG T_NUMBER @@ -690,7 +735,7 @@ init_config(char *filename) /* create empty pool */ if (!STATE(ignore_pool)) { - STATE(ignore_pool) = ignore_pool_create(CONFIG(family)); + STATE(ignore_pool) = ignore_pool_create(); if (!STATE(ignore_pool)) { fprintf(stderr, "Can't create ignore pool!\n"); exit(EXIT_FAILURE); diff --git a/src/stats-mode.c b/src/stats-mode.c index 9e6089c..b6ae2bd 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -38,7 +38,6 @@ static int init_stats(void) STATE_STATS(cache) = cache_create("stats", LIFETIME, - CONFIG(family), NULL); if (!STATE_STATS(cache)) { dlog(LOG_ERR, "can't allocate memory for the " diff --git a/src/sync-mode.c b/src/sync-mode.c index b9fc25c..a81309f 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -151,7 +151,6 @@ static int init_sync(void) STATE_SYNC(internal) = cache_create("internal", STATE_SYNC(sync)->internal_cache_flags, - CONFIG(family), STATE_SYNC(sync)->internal_cache_extra); if (!STATE_SYNC(internal)) { @@ -167,7 +166,6 @@ static int init_sync(void) STATE_SYNC(external) = cache_create("external", STATE_SYNC(sync)->external_cache_flags, - CONFIG(family), NULL); if (!STATE_SYNC(external)) { -- cgit v1.2.3 From 7784ef33db4361269afe9b302fa9dbb4a65aaf35 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Sat, 9 Feb 2008 20:07:36 +0000 Subject: o add IPv6 information to synchronization messages o add support for NAT sequence adjustment (requires Linux kernel >= 2.6.25) o remove TODO file from release tarballs --- ChangeLog | 2 ++ Makefile.am | 2 +- TODO | 2 +- configure.in | 2 +- src/build.c | 18 +++++++++++++++--- src/parse.c | 19 ++++++++++++++++--- 6 files changed, 36 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index aa9b3d2..a91511f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -45,6 +45,8 @@ o constify queue_iterate() o use list_del_init() and list_empty() to check if a node is in the list o remove unix socket file on exit o use umask() to set up file permissions +o add support for NAT sequence adjustment (requires Linux kernel >= 2.6.25) +o remove TODO file from release tarballs Max Kellermann : diff --git a/Makefile.am b/Makefile.am index 0cd321b..f9fba72 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5,7 +5,7 @@ include Make_global.am AUTOMAKE_OPTIONS = foreign dist-bzip2 1.6 man_MANS = conntrack.8 conntrackd.8 -EXTRA_DIST = $(man_MANS) Make_global.am ChangeLog TODO doc +EXTRA_DIST = $(man_MANS) Make_global.am ChangeLog doc SUBDIRS = extensions src DIST_SUBDIRS = include src extensions diff --git a/TODO b/TODO index 9450aeb..c3cd004 100644 --- a/TODO +++ b/TODO @@ -20,7 +20,7 @@ by dificulty levels: [ ] study better keepalived transitions [X] fix ipv6 support [X] add support setup related conntracks - [ ] NAT sequence adjustment support + [X] NAT sequence adjustment support = Open issues that won't be ever resolved = * unsupported stateful iptables matches: diff --git a/configure.in b/configure.in index 6a9d882..920f42f 100644 --- a/configure.in +++ b/configure.in @@ -18,7 +18,7 @@ esac dnl Dependencies LIBNFNETLINK_REQUIRED=0.0.32 -LIBNETFILTER_CONNTRACK_REQUIRED=0.0.88 +LIBNETFILTER_CONNTRACK_REQUIRED=0.0.89 PKG_CHECK_MODULES(LIBNFNETLINK, libnfnetlink >= $LIBNFNETLINK_REQUIRED,, AC_MSG_ERROR(Cannot find libnfnetlink >= $LIBNFNETLINK_REQUIRED)) diff --git a/src/build.c b/src/build.c index 3de1c25..d6c8837 100644 --- a/src/build.c +++ b/src/build.c @@ -58,6 +58,14 @@ static void __build_u32(const struct nf_conntrack *ct, addattr(pld, attr, &data, sizeof(uint32_t)); } +static void __build_pointer_be(const struct nf_conntrack *ct, + struct netpld *pld, + int attr, + size_t size) +{ + addattr(pld, attr, nfct_get_attr(ct, attr), size); +} + static void __nat_build_u32(uint32_t data, struct netpld *pld, int attr) { data = htonl(data); @@ -70,13 +78,17 @@ static void __nat_build_u16(uint16_t data, struct netpld *pld, int attr) addattr(pld, attr, &data, sizeof(uint16_t)); } -/* XXX: IPv6 and ICMP not supported */ +/* XXX: ICMP not supported */ void build_netpld(struct nf_conntrack *ct, struct netpld *pld, int query) { if (nfct_attr_is_set(ct, ATTR_IPV4_SRC)) - __build_u32(ct, pld, ATTR_IPV4_SRC); + __build_pointer_be(ct, pld, ATTR_IPV4_SRC, sizeof(uint32_t)); if (nfct_attr_is_set(ct, ATTR_IPV4_DST)) - __build_u32(ct, pld, ATTR_IPV4_DST); + __build_pointer_be(ct, pld, ATTR_IPV4_DST, sizeof(uint32_t)); + if (nfct_attr_is_set(ct, ATTR_IPV6_SRC)) + __build_pointer_be(ct, pld, ATTR_IPV6_SRC, sizeof(uint32_t)*4); + if (nfct_attr_is_set(ct, ATTR_IPV6_DST)) + __build_pointer_be(ct, pld, ATTR_IPV6_DST, sizeof(uint32_t)*4); if (nfct_attr_is_set(ct, ATTR_L3PROTO)) __build_u8(ct, pld, ATTR_L3PROTO); if (nfct_attr_is_set(ct, ATTR_PORT_SRC)) diff --git a/src/parse.c b/src/parse.c index 5bc71ef..8ef2e8d 100644 --- a/src/parse.c +++ b/src/parse.c @@ -38,11 +38,18 @@ static void parse_u32(struct nf_conntrack *ct, int attr, void *data) nfct_set_attr_u32(ct, attr, ntohl(*value)); } +static void parse_pointer_be(struct nf_conntrack *ct, int attr, void *data) +{ + nfct_set_attr(ct, attr, data); +} + typedef void (*parse)(struct nf_conntrack *ct, int attr, void *data); static parse h[ATTR_MAX] = { - [ATTR_IPV4_SRC] = parse_u32, - [ATTR_IPV4_DST] = parse_u32, + [ATTR_IPV4_SRC] = parse_pointer_be, + [ATTR_IPV4_DST] = parse_pointer_be, + [ATTR_IPV6_SRC] = parse_pointer_be, + [ATTR_IPV6_DST] = parse_pointer_be, [ATTR_L3PROTO] = parse_u8, [ATTR_PORT_SRC] = parse_u16, [ATTR_PORT_DST] = parse_u16, @@ -61,7 +68,13 @@ static parse h[ATTR_MAX] = { [ATTR_MASTER_L3PROTO] = parse_u8, [ATTR_MASTER_PORT_SRC] = parse_u16, [ATTR_MASTER_PORT_DST] = parse_u16, - [ATTR_MASTER_L4PROTO] = parse_u8 + [ATTR_MASTER_L4PROTO] = parse_u8, + [ATTR_ORIG_NAT_SEQ_CORRECTION_POS] = parse_u32, + [ATTR_ORIG_NAT_SEQ_OFFSET_BEFORE] = parse_u32, + [ATTR_ORIG_NAT_SEQ_OFFSET_AFTER] = parse_u32, + [ATTR_REPL_NAT_SEQ_CORRECTION_POS] = parse_u32, + [ATTR_REPL_NAT_SEQ_OFFSET_BEFORE] = parse_u32, + [ATTR_REPL_NAT_SEQ_OFFSET_AFTER] = parse_u32, }; void parse_netpld(struct nf_conntrack *ct, struct netpld *pld, int *query) -- cgit v1.2.3 From ef56ba7fa2103984eefce9eb01227feab6fa2898 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Sat, 9 Feb 2008 20:28:50 +0000 Subject: add missing bits for NAT sequence adjusment support --- src/build.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'src') diff --git a/src/build.c b/src/build.c index d6c8837..6363458 100644 --- a/src/build.c +++ b/src/build.c @@ -146,6 +146,20 @@ void build_netpld(struct nf_conntrack *ct, struct netpld *pld, int query) __nat_build_u16(data, pld, ATTR_DNAT_PORT); } + /* NAT sequence adjustment */ + if (nfct_attr_is_set(ct, ATTR_ORIG_NAT_SEQ_CORRECTION_POS)) + __build_u32(ct, pld, ATTR_ORIG_NAT_SEQ_CORRECTION_POS); + if (nfct_attr_is_set(ct, ATTR_ORIG_NAT_SEQ_OFFSET_BEFORE)) + __build_u32(ct, pld, ATTR_ORIG_NAT_SEQ_OFFSET_BEFORE); + if (nfct_attr_is_set(ct, ATTR_ORIG_NAT_SEQ_OFFSET_AFTER)) + __build_u32(ct, pld, ATTR_ORIG_NAT_SEQ_OFFSET_AFTER); + if (nfct_attr_is_set(ct, ATTR_REPL_NAT_SEQ_CORRECTION_POS)) + __build_u32(ct, pld, ATTR_REPL_NAT_SEQ_CORRECTION_POS); + if (nfct_attr_is_set(ct, ATTR_REPL_NAT_SEQ_OFFSET_BEFORE)) + __build_u32(ct, pld, ATTR_REPL_NAT_SEQ_OFFSET_BEFORE); + if (nfct_attr_is_set(ct, ATTR_REPL_NAT_SEQ_OFFSET_AFTER)) + __build_u32(ct, pld, ATTR_REPL_NAT_SEQ_OFFSET_AFTER); + pld->query = query; PLD_HOST2NETWORK(pld); -- cgit v1.2.3 From bc7329870e82a9909cfc01e4876ebcc5adeef629 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Thu, 14 Feb 2008 14:19:56 +0000 Subject: From: Max Kellermann eliminate duplicated initialization --- ChangeLog | 1 + src/alarm.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index a91511f..6b0fba9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -99,6 +99,7 @@ o remove unused prototypes in network.h o check if the received packet is large enough o introduce alarm_pending() o cleanup: use size_t instead of integer +o cleanup: remove unrequired initialization in the rbtree-based alarm version 0.9.5 (2007/07/29) ------------------------------ diff --git a/src/alarm.c b/src/alarm.c index 5013735..470efdd 100644 --- a/src/alarm.c +++ b/src/alarm.c @@ -105,7 +105,7 @@ calculate_next_run(struct timeval *cand, struct timeval * get_next_alarm_run(struct timeval *next_run) { - struct rb_node *node = alarm_root.rb_node; + struct rb_node *node; struct timeval tv; gettimeofday(&tv, NULL); @@ -122,7 +122,7 @@ get_next_alarm_run(struct timeval *next_run) struct timeval * do_alarm_run(struct timeval *next_run) { - struct rb_node *node = alarm_root.rb_node; + struct rb_node *node; struct alarm_block *this, *tmp; struct timeval tv; -- cgit v1.2.3 From 6b5befe9cde1a4c46bb0421cca9c659c732d40e1 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Thu, 14 Feb 2008 14:21:46 +0000 Subject: From: Max Kellermann use "for" loop instead of "while" --- ChangeLog | 2 +- src/alarm.c | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 6b0fba9..2942b24 100644 --- a/ChangeLog +++ b/ChangeLog @@ -99,7 +99,7 @@ o remove unused prototypes in network.h o check if the received packet is large enough o introduce alarm_pending() o cleanup: use size_t instead of integer -o cleanup: remove unrequired initialization in the rbtree-based alarm +o several cleanups in the rbtree-based alarm version 0.9.5 (2007/07/29) ------------------------------ diff --git a/src/alarm.c b/src/alarm.c index 470efdd..a3bdbe2 100644 --- a/src/alarm.c +++ b/src/alarm.c @@ -128,15 +128,12 @@ do_alarm_run(struct timeval *next_run) gettimeofday(&tv, NULL); - node = rb_first(&alarm_root); - while (node) { + for (node = rb_first(&alarm_root); node; node = rb_next(node)) { this = container_of(node, struct alarm_block, node); if (timercmp(&this->tv, &tv, >)) break; - node = rb_next(node); - list_add(&this->list, &alarm_run_queue); } -- cgit v1.2.3 From 4590cc9638d39cd189724915fc3d4763a52eb934 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Thu, 14 Feb 2008 14:24:09 +0000 Subject: From: Max Kellermann make alarm_run_queue a local variable --- src/alarm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/alarm.c b/src/alarm.c index a3bdbe2..c86ce44 100644 --- a/src/alarm.c +++ b/src/alarm.c @@ -21,7 +21,6 @@ #include static struct rb_root alarm_root = RB_ROOT; -static LIST_HEAD(alarm_run_queue); void init_alarm(struct alarm_block *t, void *data, @@ -122,12 +121,14 @@ get_next_alarm_run(struct timeval *next_run) struct timeval * do_alarm_run(struct timeval *next_run) { + struct list_head alarm_run_queue; struct rb_node *node; struct alarm_block *this, *tmp; struct timeval tv; gettimeofday(&tv, NULL); + INIT_LIST_HEAD(&alarm_run_queue); for (node = rb_first(&alarm_root); node; node = rb_next(node)) { this = container_of(node, struct alarm_block, node); -- cgit v1.2.3 From a293fcbc5df63a4867e1cff637b5935c267f5da0 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Thu, 14 Feb 2008 14:25:11 +0000 Subject: From: Max Kellermann use list_for_each_entry() --- src/alarm.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/alarm.c b/src/alarm.c index c86ce44..8056ee6 100644 --- a/src/alarm.c +++ b/src/alarm.c @@ -123,7 +123,7 @@ do_alarm_run(struct timeval *next_run) { struct list_head alarm_run_queue; struct rb_node *node; - struct alarm_block *this, *tmp; + struct alarm_block *this; struct timeval tv; gettimeofday(&tv, NULL); @@ -138,8 +138,7 @@ do_alarm_run(struct timeval *next_run) list_add(&this->list, &alarm_run_queue); } - list_for_each_entry_safe(this, tmp, &alarm_run_queue, list) { - list_del(&this->list); + list_for_each_entry(this, &alarm_run_queue, list) { rb_erase(&this->node, &alarm_root); RB_CLEAR_NODE(&this->node); this->function(this, this->data); -- cgit v1.2.3 From 426f53894b8ced42130425c196aea38d115e9e18 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Thu, 14 Feb 2008 14:44:59 +0000 Subject: From: Max Kellermann whitespace cleanups --- ChangeLog | 1 + include/queue.h | 4 ++-- src/alarm.c | 4 ++-- src/main.c | 6 +++--- src/netlink.c | 14 +++++++------- src/run.c | 12 ++++++------ 6 files changed, 21 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 2942b24..aa485a1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -100,6 +100,7 @@ o check if the received packet is large enough o introduce alarm_pending() o cleanup: use size_t instead of integer o several cleanups in the rbtree-based alarm +o whitespace cleanups version 0.9.5 (2007/07/29) ------------------------------ diff --git a/include/queue.h b/include/queue.h index 9a5d7b8..5a9cf39 100644 --- a/include/queue.h +++ b/include/queue.h @@ -21,8 +21,8 @@ void queue_destroy(struct queue *b); unsigned int queue_len(const struct queue *b); int queue_add(struct queue *b, const void *data, size_t size); void queue_del(struct queue *b, void *data); -void queue_iterate(struct queue *b, - const void *data, +void queue_iterate(struct queue *b, + const void *data, int (*iterate)(void *data1, const void *data2)); #endif diff --git a/src/alarm.c b/src/alarm.c index 8056ee6..91ee2ca 100644 --- a/src/alarm.c +++ b/src/alarm.c @@ -1,6 +1,6 @@ /* * (C) 2006-2008 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 @@ -85,7 +85,7 @@ int alarm_pending(struct alarm_block *alarm) static struct timeval * calculate_next_run(struct timeval *cand, - struct timeval *tv, + struct timeval *tv, struct timeval *next_run) { if (cand->tv_sec != LONG_MAX) { diff --git a/src/main.c b/src/main.c index 8221564..b6011f0 100644 --- a/src/main.c +++ b/src/main.c @@ -1,6 +1,6 @@ /* * (C) 2006-2007 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 @@ -34,7 +34,7 @@ static const char usage_daemon_commands[] = "Daemon mode commands:\n" " -d [options]\t\tRun in daemon mode\n"; -static const char usage_client_commands[] = +static const char usage_client_commands[] = "Client mode commands:\n" " -c, commit external cache to conntrack table\n" " -f, flush internal and external cache\n" @@ -244,7 +244,7 @@ int main(int argc, char *argv[]) exit(EXIT_FAILURE); } else if (pid) exit(EXIT_SUCCESS); - + setsid(); close(STDOUT_FILENO); diff --git a/src/netlink.c b/src/netlink.c index bb94001..f6a2378 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -1,6 +1,6 @@ /* * (C) 2006 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 @@ -35,7 +35,7 @@ int ignore_conntrack(struct nf_conntrack *ct) return 0; } - /* Accept SNAT'ed traffic: not really coming to the local machine */ + /* Accept SNAT'ed traffic: not really coming to the local machine */ if (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) { debug_ct(ct, "SNAT"); return 0; @@ -54,7 +54,7 @@ static int event_handler(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data) { - /* + /* * Ignore this conntrack: it talks about a * connection that is not interesting for us. */ @@ -94,7 +94,7 @@ int nl_init_event_handler(void) /* set up socket buffer size */ if (CONFIG(netlink_buffer_size)) - nfnl_rcvbufsiz(nfct_nfnlh(STATE(event)), + nfnl_rcvbufsiz(nfct_nfnlh(STATE(event)), CONFIG(netlink_buffer_size)); else { socklen_t socklen = sizeof(unsigned int); @@ -109,7 +109,7 @@ int nl_init_event_handler(void) /* ensure that maximum grown size is >= than maximum size */ if (CONFIG(netlink_buffer_size_max_grown) < CONFIG(netlink_buffer_size)) - CONFIG(netlink_buffer_size_max_grown) = + CONFIG(netlink_buffer_size_max_grown) = CONFIG(netlink_buffer_size); /* register callback for events */ @@ -122,7 +122,7 @@ static int dump_handler(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data) { - /* + /* * Ignore this conntrack: it talks about a * connection that is not interesting for us. */ @@ -167,7 +167,7 @@ void nl_resize_socket_buffer(struct nfct_handle *h) return; if (s > CONFIG(netlink_buffer_size_max_grown)) { - dlog(LOG_WARNING, + dlog(LOG_WARNING, "maximum netlink socket buffer " "size has been reached. We are likely to " "be losing events, this may lead to " diff --git a/src/run.c b/src/run.c index f5832bc..6cf259d 100644 --- a/src/run.c +++ b/src/run.c @@ -48,7 +48,7 @@ void killer(int foo) sigprocmask(SIG_UNBLOCK, &STATE(block), NULL); - exit(0); + exit(0); } static void child(int foo) @@ -115,7 +115,7 @@ init(void) } if (nl_init_event_handler() == -1) { - dlog(LOG_ERR, "can't open netlink handler: %s", + dlog(LOG_ERR, "can't open netlink handler: %s", strerror(errno)); dlog(LOG_ERR, "no ctnetlink kernel support?"); return -1; @@ -128,7 +128,7 @@ init(void) return -1; } - /* Signals handling */ + /* Signals handling */ sigemptyset(&STATE(block)); sigaddset(&STATE(block), SIGTERM); sigaddset(&STATE(block), SIGINT); @@ -177,7 +177,7 @@ static void __run(struct timeval *next_alarm) } /* signals are racy */ - sigprocmask(SIG_BLOCK, &STATE(block), NULL); + sigprocmask(SIG_BLOCK, &STATE(block), NULL); /* order received via UNIX socket */ if (FD_ISSET(STATE(local).fd, &readfds)) @@ -189,8 +189,8 @@ static void __run(struct timeval *next_alarm) if (ret == -1) { switch(errno) { case ENOBUFS: - /* - * It seems that ctnetlink can't back off, + /* + * It seems that ctnetlink can't back off, * it's likely that we're losing events. * Solution: duplicate the socket buffer * size and resync with master conntrack table. -- cgit v1.2.3 From 13f4c15f214dd807899c10ebdff74ab5148d650f Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Tue, 19 Feb 2008 23:04:49 +0000 Subject: compose the file descriptor set at initialization stage to save some cycles --- ChangeLog | 1 + include/Makefile.am | 2 +- include/conntrackd.h | 4 ++- include/fds.h | 16 ++++++++++++ src/Makefile.am | 2 +- src/fds.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/run.c | 31 +++++++++++++--------- src/stats-mode.c | 2 +- src/sync-mode.c | 9 +++---- 9 files changed, 120 insertions(+), 21 deletions(-) create mode 100644 include/fds.h create mode 100644 src/fds.c (limited to 'src') diff --git a/ChangeLog b/ChangeLog index aa485a1..411118e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -47,6 +47,7 @@ o remove unix socket file on exit o use umask() to set up file permissions o add support for NAT sequence adjustment (requires Linux kernel >= 2.6.25) o remove TODO file from release tarballs +o compose the file descriptor set at initialization stage to save some cycles Max Kellermann : diff --git a/include/Makefile.am b/include/Makefile.am index d7f27a9..92ebbcc 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -3,5 +3,5 @@ noinst_HEADERS = alarm.h jhash.h slist.h cache.h linux_list.h linux_rbtree.h \ sync.h conntrackd.h local.h us-conntrack.h \ debug.h log.h hash.h mcast.h conntrack.h \ state_helper.h network.h ignore.h queue.h \ - traffic_stats.h netlink.h + traffic_stats.h netlink.h fds.h diff --git a/include/conntrackd.h b/include/conntrackd.h index 47898e2..69c1303 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -105,6 +105,8 @@ struct ct_general_state { struct nfct_handle *event; /* event handler */ struct nfct_handle *dump; /* dump handler */ + struct fds *fds; + /* statistics */ uint64_t malformed; uint64_t bytes[NFCT_DIR_MAX]; @@ -151,7 +153,7 @@ extern struct ct_general_state st; struct ct_mode { int (*init)(void); - int (*add_fds_to_set)(fd_set *readfds); + int (*register_fds)(struct fds *fds); void (*run)(fd_set *readfds); int (*local)(int fd, int type, void *data); void (*kill)(void); diff --git a/include/fds.h b/include/fds.h new file mode 100644 index 0000000..cc213fe --- /dev/null +++ b/include/fds.h @@ -0,0 +1,16 @@ +#ifndef _FDS_H_ +#define _FDS_H_ + +struct fds { + int maxfd; + int fd_array_len; + int fd_array_cur; + int *fd_array; + fd_set readfds; +}; + +struct fds *create_fds(void); +void destroy_fds(struct fds *); +int register_fd(int fd, struct fds *fds); + +#endif diff --git a/src/Makefile.am b/src/Makefile.am index 7274a14..494da4f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -12,7 +12,7 @@ conntrack_LDFLAGS = $(all_libraries) @LIBNETFILTER_CONNTRACK_LIBS@ conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c rbtree.c \ local.c log.c mcast.c netlink.c \ - ignore_pool.c \ + ignore_pool.c fds.c \ cache.c cache_iterators.c \ cache_lifetime.c cache_timer.c cache_wt.c \ sync-mode.c sync-alarm.c sync-ftfw.c \ diff --git a/src/fds.c b/src/fds.c new file mode 100644 index 0000000..908f048 --- /dev/null +++ b/src/fds.c @@ -0,0 +1,74 @@ +/* + * (C) 2006-2008 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include "fds.h" + +/* we don't handle that many descriptors so eight is just fine */ +#define FDS_ARRAY_LEN 8 +#define FDS_ARRAY_SIZE (sizeof(int) * FDS_ARRAY_LEN) + +struct fds *create_fds(void) +{ + struct fds *fds; + + fds = (struct fds *) malloc(sizeof(struct fds)); + if (fds == NULL) + return NULL; + + memset(fds, 0, sizeof(struct fds)); + + fds->fd_array = (int *) malloc(FDS_ARRAY_SIZE); + if (fds->fd_array == NULL) { + free(fds); + return NULL; + } + + memset(fds->fd_array, 0, FDS_ARRAY_SIZE); + fds->fd_array_len = FDS_ARRAY_LEN; + + return fds; +} + +void destroy_fds(struct fds *fds) +{ + free(fds->fd_array); + free(fds); +} + +int register_fd(int fd, struct fds *fds) +{ + FD_SET(fd, &fds->readfds); + + if (fd > fds->maxfd) + fds->maxfd = fd; + + if (fds->fd_array_cur >= fds->fd_array_len) { + fds->fd_array_len += FDS_ARRAY_LEN; + fds->fd_array = realloc(fds->fd_array, + fds->fd_array_len * sizeof(int)); + if (fds->fd_array == NULL) { + fds->fd_array_len -= FDS_ARRAY_LEN; + return -1; + } + } + + fds->fd_array[fds->fd_array_cur++] = fd; + + return 0; +} diff --git a/src/run.c b/src/run.c index 6cf259d..b259f2e 100644 --- a/src/run.c +++ b/src/run.c @@ -23,6 +23,7 @@ #include "ignore.h" #include "log.h" #include "alarm.h" +#include "fds.h" #include #include @@ -128,6 +129,21 @@ init(void) return -1; } + STATE(fds) = create_fds(); + if (STATE(fds) == NULL) { + dlog(LOG_ERR, "can't create file descriptor pool"); + return -1; + } + + register_fd(STATE(local).fd, STATE(fds)); + register_fd(nfct_fd(STATE(event)), STATE(fds)); + + if (STATE(mode)->register_fds && + STATE(mode)->register_fds(STATE(fds)) == -1) { + dlog(LOG_ERR, "fds registration failed"); + return -1; + } + /* Signals handling */ sigemptyset(&STATE(block)); sigaddset(&STATE(block), SIGTERM); @@ -154,19 +170,10 @@ init(void) static void __run(struct timeval *next_alarm) { - int max, ret; - fd_set readfds; - - FD_ZERO(&readfds); - FD_SET(STATE(local).fd, &readfds); - FD_SET(nfct_fd(STATE(event)), &readfds); - - max = MAX(STATE(local).fd, nfct_fd(STATE(event))); - - if (STATE(mode)->add_fds_to_set) - max = MAX(max, STATE(mode)->add_fds_to_set(&readfds)); + int ret; + fd_set readfds = STATE(fds)->readfds; - ret = select(max+1, &readfds, NULL, NULL, next_alarm); + ret = select(STATE(fds)->maxfd + 1, &readfds, NULL, NULL, next_alarm); if (ret == -1) { /* interrupted syscall, retry */ if (errno == EINTR) diff --git a/src/stats-mode.c b/src/stats-mode.c index b6ae2bd..42fa35a 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -181,7 +181,7 @@ static int event_destroy_stats(struct nf_conntrack *ct) struct ct_mode stats_mode = { .init = init_stats, - .add_fds_to_set = NULL, + .register_fds = NULL, .run = NULL, .local = local_handler_stats, .kill = kill_stats, diff --git a/src/sync-mode.c b/src/sync-mode.c index a81309f..79afcdf 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -25,6 +25,7 @@ #include "conntrackd.h" #include "us-conntrack.h" #include "network.h" +#include "fds.h" #include "debug.h" #include @@ -202,11 +203,9 @@ static int init_sync(void) return 0; } -static int add_fds_to_set_sync(fd_set *readfds) +static int register_fds_sync(struct fds *fds) { - FD_SET(STATE_SYNC(mcast_server->fd), readfds); - - return STATE_SYNC(mcast_server->fd); + return register_fd(STATE_SYNC(mcast_server->fd), fds); } static void run_sync(fd_set *readfds) @@ -500,7 +499,7 @@ static int event_destroy_sync(struct nf_conntrack *ct) struct ct_mode sync_mode = { .init = init_sync, - .add_fds_to_set = add_fds_to_set_sync, + .register_fds = register_fds_sync, .run = run_sync, .local = local_handler_sync, .kill = kill_sync, -- cgit v1.2.3 From 5015fd45430f054d3ec4a8b4157da3506c45950f Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Fri, 22 Feb 2008 12:17:09 +0000 Subject: cleanup: remove config_set from main(), use config_file variable instead --- ChangeLog | 1 + src/main.c | 7 +++---- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 411118e..588ea01 100644 --- a/ChangeLog +++ b/ChangeLog @@ -48,6 +48,7 @@ o use umask() to set up file permissions o add support for NAT sequence adjustment (requires Linux kernel >= 2.6.25) o remove TODO file from release tarballs o compose the file descriptor set at initialization stage to save some cycles +o cleanup: remove config_set from main(), use config_file variable instead Max Kellermann : diff --git a/src/main.c b/src/main.c index b6011f0..2e1ccd8 100644 --- a/src/main.c +++ b/src/main.c @@ -77,8 +77,8 @@ set_operation_mode(int *current, int want, char *argv[]) int main(int argc, char *argv[]) { - int ret, i, config_set = 0, action = -1; - char config_file[PATH_MAX]; + int ret, i, action = -1; + char config_file[PATH_MAX] = {}; int type = 0; struct utsname u; int version, major, minor; @@ -126,7 +126,6 @@ int main(int argc, char *argv[]) "down to %d characters", PATH_MAX); } - config_set = 1; break; } show_usage(argv[0]); @@ -184,7 +183,7 @@ int main(int argc, char *argv[]) } } - if (config_set == 0) + if (!config_file[0]) strcpy(config_file, DEFAULT_CONFIGFILE); umask(0177); -- cgit v1.2.3 From 2d92fdb0912f3546492b114485951287fca4e5ab Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Sat, 8 Mar 2008 11:28:05 +0000 Subject: relicense conntrack-tools as GPLv3+, so far the most significant contributor has been Max Kellermann and has no issues with relicensing their contributions. --- COPYING | 913 +++++++++++++++++++++++++++++++++---------------- src/alarm.c | 2 +- src/build.c | 2 +- src/cache.c | 2 +- src/cache_iterators.c | 2 +- src/cache_lifetime.c | 2 +- src/cache_timer.c | 2 +- src/cache_wt.c | 2 +- src/conntrack.c | 2 +- src/fds.c | 2 +- src/hash.c | 2 +- src/ignore_pool.c | 2 +- src/local.c | 2 +- src/log.c | 2 +- src/main.c | 2 +- src/mcast.c | 2 +- src/netlink.c | 2 +- src/network.c | 2 +- src/parse.c | 2 +- src/queue.c | 2 +- src/rbtree.c | 2 +- src/read_config_lex.l | 2 +- src/read_config_yy.y | 2 +- src/run.c | 2 +- src/state_helper.c | 2 +- src/state_helper_tcp.c | 2 +- src/stats-mode.c | 2 +- src/sync-alarm.c | 2 +- src/sync-ftfw.c | 2 +- src/sync-mode.c | 2 +- src/traffic_stats.c | 2 +- 31 files changed, 654 insertions(+), 319 deletions(-) (limited to 'src') diff --git a/COPYING b/COPYING index a43ea21..94a9ed0 100644 --- a/COPYING +++ b/COPYING @@ -1,285 +1,626 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 675 Mass Ave, Cambridge, MA 02139, USA + Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. - Preamble + Preamble - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of this License. - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - Appendix: How to Apply These Terms to Your New Programs + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it @@ -287,15 +628,15 @@ free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least +state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. - Copyright (C) 19yy + Copyright (C) - This program is free software; you can redistribute it and/or modify + 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 + the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -304,36 +645,30 @@ the "copyright" line and a pointer to where the full notice is found. GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: - Gnomovision version 69, Copyright (C) 19yy name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/src/alarm.c b/src/alarm.c index 91ee2ca..db3f105 100644 --- a/src/alarm.c +++ b/src/alarm.c @@ -3,7 +3,7 @@ * * 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 + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/build.c b/src/build.c index 6363458..1ab0ed4 100644 --- a/src/build.c +++ b/src/build.c @@ -3,7 +3,7 @@ * * 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 + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/cache.c b/src/cache.c index 73d539a..6f81725 100644 --- a/src/cache.c +++ b/src/cache.c @@ -3,7 +3,7 @@ * * 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 + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/cache_iterators.c b/src/cache_iterators.c index 92b7b7f..662e4a9 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -3,7 +3,7 @@ * * 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 + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/cache_lifetime.c b/src/cache_lifetime.c index ad3416a..989e069 100644 --- a/src/cache_lifetime.c +++ b/src/cache_lifetime.c @@ -3,7 +3,7 @@ * * 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 + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/cache_timer.c b/src/cache_timer.c index 6619c2c..aba342c 100644 --- a/src/cache_timer.c +++ b/src/cache_timer.c @@ -3,7 +3,7 @@ * * 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 + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/cache_wt.c b/src/cache_wt.c index 8ff8fae..bf683b0 100644 --- a/src/cache_wt.c +++ b/src/cache_wt.c @@ -3,7 +3,7 @@ * * 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 + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/conntrack.c b/src/conntrack.c index 82ff544..e0ff92d 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -3,7 +3,7 @@ * * 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 + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/fds.c b/src/fds.c index 908f048..ccb639b 100644 --- a/src/fds.c +++ b/src/fds.c @@ -3,7 +3,7 @@ * * 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 + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/hash.c b/src/hash.c index cf64df4..5df33dd 100644 --- a/src/hash.c +++ b/src/hash.c @@ -3,7 +3,7 @@ * * 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 + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/ignore_pool.c b/src/ignore_pool.c index 027d628..7540b3a 100644 --- a/src/ignore_pool.c +++ b/src/ignore_pool.c @@ -3,7 +3,7 @@ * * 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 + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/local.c b/src/local.c index e2c3599..a67b2fb 100644 --- a/src/local.c +++ b/src/local.c @@ -3,7 +3,7 @@ * * 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 + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/log.c b/src/log.c index 51e757f..1638dc2 100644 --- a/src/log.c +++ b/src/log.c @@ -3,7 +3,7 @@ * * 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 + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/main.c b/src/main.c index 2e1ccd8..fa05da0 100644 --- a/src/main.c +++ b/src/main.c @@ -3,7 +3,7 @@ * * 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 + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/mcast.c b/src/mcast.c index f945511..30313bc 100644 --- a/src/mcast.c +++ b/src/mcast.c @@ -3,7 +3,7 @@ * * 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 + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/netlink.c b/src/netlink.c index f6a2378..8ac6f93 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -3,7 +3,7 @@ * * 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 + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/network.c b/src/network.c index 92999a1..f5b0909 100644 --- a/src/network.c +++ b/src/network.c @@ -3,7 +3,7 @@ * * 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 + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/parse.c b/src/parse.c index 8ef2e8d..1e5fdf6 100644 --- a/src/parse.c +++ b/src/parse.c @@ -3,7 +3,7 @@ * * 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 + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/queue.c b/src/queue.c index 7b20e83..22460e3 100644 --- a/src/queue.c +++ b/src/queue.c @@ -3,7 +3,7 @@ * * 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 + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/rbtree.c b/src/rbtree.c index 199e2bb..2228f98 100644 --- a/src/rbtree.c +++ b/src/rbtree.c @@ -5,7 +5,7 @@ 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 + the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, diff --git a/src/read_config_lex.l b/src/read_config_lex.l index 65df1e7..4f0d864 100644 --- a/src/read_config_lex.l +++ b/src/read_config_lex.l @@ -4,7 +4,7 @@ * * 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 + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 86fee9b..f89677a 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -4,7 +4,7 @@ * * 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 + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/run.c b/src/run.c index b259f2e..0d91f4d 100644 --- a/src/run.c +++ b/src/run.c @@ -3,7 +3,7 @@ * * 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 + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/state_helper.c b/src/state_helper.c index 9034864..2fa0e02 100644 --- a/src/state_helper.c +++ b/src/state_helper.c @@ -3,7 +3,7 @@ * * 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 + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/state_helper_tcp.c b/src/state_helper_tcp.c index 88af35e..625928c 100644 --- a/src/state_helper_tcp.c +++ b/src/state_helper_tcp.c @@ -3,7 +3,7 @@ * * 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 + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/stats-mode.c b/src/stats-mode.c index 42fa35a..06962d2 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -3,7 +3,7 @@ * * 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 + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/sync-alarm.c b/src/sync-alarm.c index 4473af2..709e27b 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -3,7 +3,7 @@ * * 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 + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index cac25d0..4ed8928 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -3,7 +3,7 @@ * * 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 + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/sync-mode.c b/src/sync-mode.c index 79afcdf..86ac5e8 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -3,7 +3,7 @@ * * 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 + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/traffic_stats.c b/src/traffic_stats.c index 9e40d53..b5a97ec 100644 --- a/src/traffic_stats.c +++ b/src/traffic_stats.c @@ -3,7 +3,7 @@ * * 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 + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, -- cgit v1.2.3 From 4f0edbba3cca03e4816c015cbf2c1a29fb62d073 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Sat, 8 Mar 2008 11:35:02 +0000 Subject: revert relicensing... still we use linux_list.h code which seems to be GPLv2 only which is incompatible AFAIK --- COPYING | 913 ++++++++++++++++--------------------------------- src/alarm.c | 2 +- src/build.c | 2 +- src/cache.c | 2 +- src/cache_iterators.c | 2 +- src/cache_lifetime.c | 2 +- src/cache_timer.c | 2 +- src/cache_wt.c | 2 +- src/conntrack.c | 2 +- src/fds.c | 2 +- src/hash.c | 2 +- src/ignore_pool.c | 2 +- src/local.c | 2 +- src/log.c | 2 +- src/main.c | 2 +- src/mcast.c | 2 +- src/netlink.c | 2 +- src/network.c | 2 +- src/parse.c | 2 +- src/queue.c | 2 +- src/rbtree.c | 2 +- src/read_config_lex.l | 2 +- src/read_config_yy.y | 2 +- src/run.c | 2 +- src/state_helper.c | 2 +- src/state_helper_tcp.c | 2 +- src/stats-mode.c | 2 +- src/sync-alarm.c | 2 +- src/sync-ftfw.c | 2 +- src/sync-mode.c | 2 +- src/traffic_stats.c | 2 +- 31 files changed, 319 insertions(+), 654 deletions(-) (limited to 'src') diff --git a/COPYING b/COPYING index 94a9ed0..a43ea21 100644 --- a/COPYING +++ b/COPYING @@ -1,626 +1,285 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 - Copyright (C) 2007 Free Software Foundation, Inc. + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. - Preamble + Preamble - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to this License. - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it @@ -628,15 +287,15 @@ free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least +convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. - Copyright (C) + Copyright (C) 19yy - This program is free software: you can redistribute it and/or modify + 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 3 of the License, or + the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -645,30 +304,36 @@ the "copyright" line and a pointer to where the full notice is found. GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program. If not, see . + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Also add information on how to contact you by electronic and paper mail. - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/src/alarm.c b/src/alarm.c index db3f105..91ee2ca 100644 --- a/src/alarm.c +++ b/src/alarm.c @@ -3,7 +3,7 @@ * * 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 3 of the License, or + * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/build.c b/src/build.c index 1ab0ed4..6363458 100644 --- a/src/build.c +++ b/src/build.c @@ -3,7 +3,7 @@ * * 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 3 of the License, or + * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/cache.c b/src/cache.c index 6f81725..73d539a 100644 --- a/src/cache.c +++ b/src/cache.c @@ -3,7 +3,7 @@ * * 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 3 of the License, or + * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/cache_iterators.c b/src/cache_iterators.c index 662e4a9..92b7b7f 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -3,7 +3,7 @@ * * 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 3 of the License, or + * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/cache_lifetime.c b/src/cache_lifetime.c index 989e069..ad3416a 100644 --- a/src/cache_lifetime.c +++ b/src/cache_lifetime.c @@ -3,7 +3,7 @@ * * 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 3 of the License, or + * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/cache_timer.c b/src/cache_timer.c index aba342c..6619c2c 100644 --- a/src/cache_timer.c +++ b/src/cache_timer.c @@ -3,7 +3,7 @@ * * 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 3 of the License, or + * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/cache_wt.c b/src/cache_wt.c index bf683b0..8ff8fae 100644 --- a/src/cache_wt.c +++ b/src/cache_wt.c @@ -3,7 +3,7 @@ * * 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 3 of the License, or + * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/conntrack.c b/src/conntrack.c index e0ff92d..82ff544 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -3,7 +3,7 @@ * * 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 3 of the License, or + * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/fds.c b/src/fds.c index ccb639b..908f048 100644 --- a/src/fds.c +++ b/src/fds.c @@ -3,7 +3,7 @@ * * 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 3 of the License, or + * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/hash.c b/src/hash.c index 5df33dd..cf64df4 100644 --- a/src/hash.c +++ b/src/hash.c @@ -3,7 +3,7 @@ * * 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 3 of the License, or + * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/ignore_pool.c b/src/ignore_pool.c index 7540b3a..027d628 100644 --- a/src/ignore_pool.c +++ b/src/ignore_pool.c @@ -3,7 +3,7 @@ * * 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 3 of the License, or + * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/local.c b/src/local.c index a67b2fb..e2c3599 100644 --- a/src/local.c +++ b/src/local.c @@ -3,7 +3,7 @@ * * 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 3 of the License, or + * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/log.c b/src/log.c index 1638dc2..51e757f 100644 --- a/src/log.c +++ b/src/log.c @@ -3,7 +3,7 @@ * * 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 3 of the License, or + * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/main.c b/src/main.c index fa05da0..2e1ccd8 100644 --- a/src/main.c +++ b/src/main.c @@ -3,7 +3,7 @@ * * 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 3 of the License, or + * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/mcast.c b/src/mcast.c index 30313bc..f945511 100644 --- a/src/mcast.c +++ b/src/mcast.c @@ -3,7 +3,7 @@ * * 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 3 of the License, or + * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/netlink.c b/src/netlink.c index 8ac6f93..f6a2378 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -3,7 +3,7 @@ * * 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 3 of the License, or + * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/network.c b/src/network.c index f5b0909..92999a1 100644 --- a/src/network.c +++ b/src/network.c @@ -3,7 +3,7 @@ * * 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 3 of the License, or + * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/parse.c b/src/parse.c index 1e5fdf6..8ef2e8d 100644 --- a/src/parse.c +++ b/src/parse.c @@ -3,7 +3,7 @@ * * 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 3 of the License, or + * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/queue.c b/src/queue.c index 22460e3..7b20e83 100644 --- a/src/queue.c +++ b/src/queue.c @@ -3,7 +3,7 @@ * * 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 3 of the License, or + * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/rbtree.c b/src/rbtree.c index 2228f98..199e2bb 100644 --- a/src/rbtree.c +++ b/src/rbtree.c @@ -5,7 +5,7 @@ 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 3 of the License, or + the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, diff --git a/src/read_config_lex.l b/src/read_config_lex.l index 4f0d864..65df1e7 100644 --- a/src/read_config_lex.l +++ b/src/read_config_lex.l @@ -4,7 +4,7 @@ * * 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 3 of the License, or + * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/read_config_yy.y b/src/read_config_yy.y index f89677a..86fee9b 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -4,7 +4,7 @@ * * 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 3 of the License, or + * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/run.c b/src/run.c index 0d91f4d..b259f2e 100644 --- a/src/run.c +++ b/src/run.c @@ -3,7 +3,7 @@ * * 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 3 of the License, or + * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/state_helper.c b/src/state_helper.c index 2fa0e02..9034864 100644 --- a/src/state_helper.c +++ b/src/state_helper.c @@ -3,7 +3,7 @@ * * 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 3 of the License, or + * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/state_helper_tcp.c b/src/state_helper_tcp.c index 625928c..88af35e 100644 --- a/src/state_helper_tcp.c +++ b/src/state_helper_tcp.c @@ -3,7 +3,7 @@ * * 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 3 of the License, or + * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/stats-mode.c b/src/stats-mode.c index 06962d2..42fa35a 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -3,7 +3,7 @@ * * 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 3 of the License, or + * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/sync-alarm.c b/src/sync-alarm.c index 709e27b..4473af2 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -3,7 +3,7 @@ * * 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 3 of the License, or + * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 4ed8928..cac25d0 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -3,7 +3,7 @@ * * 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 3 of the License, or + * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/sync-mode.c b/src/sync-mode.c index 86ac5e8..79afcdf 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -3,7 +3,7 @@ * * 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 3 of the License, or + * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, diff --git a/src/traffic_stats.c b/src/traffic_stats.c index b5a97ec..9e40d53 100644 --- a/src/traffic_stats.c +++ b/src/traffic_stats.c @@ -3,7 +3,7 @@ * * 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 3 of the License, or + * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, -- cgit v1.2.3 From 0e82c979fb08611ecb1aff659d9ac0ed056948ea Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Tue, 25 Mar 2008 14:37:51 +0000 Subject: Krzysztof Oledzki : o add ICMPv6 (-p icmpv6) support o add possibility to distinguish between invalid (unknown) and empty proto --- ChangeLog | 4 +++- extensions/Makefile.am | 3 ++- include/conntrack.h | 1 + src/Makefile.am | 2 +- src/conntrack.c | 6 +++++- 5 files changed, 12 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 6a33399..a7ffb25 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,6 +6,8 @@ o remove .svn directory from make distcheck tarballs (reported by B.Benjamini) Krzysztof Oledzki : o fix minor compilation warning +o add ICMPv6 (-p icmpv6) support +o add possibility to distinguish between invalid (unknown) and empty proto version 0.9.6 (2008/03/08) ------------------------------ @@ -161,7 +163,7 @@ o fork when internal/external dump and commit requests are received o lots of cleanups = conntrack = -o fix segfault with conntrack --output (Krzysztof Oledzky) +o fix segfault with conntrack --output (Krzysztof Oledzki) o use NFCT_SOPT_SETUP_* facilities: nfct_setobjopt o remove bogus option to get a conntrack in test.sh example file o add aliases --sport and --dport to make it more iptables-like diff --git a/extensions/Makefile.am b/extensions/Makefile.am index cf45688..0eede22 100644 --- a/extensions/Makefile.am +++ b/extensions/Makefile.am @@ -1,8 +1,9 @@ include $(top_srcdir)/Make_global.am noinst_LTLIBRARIES = libct_proto_tcp.la libct_proto_udp.la \ - libct_proto_icmp.la + libct_proto_icmp.la libct_proto_icmpv6.la libct_proto_tcp_la_SOURCES = libct_proto_tcp.c libct_proto_udp_la_SOURCES = libct_proto_udp.c libct_proto_icmp_la_SOURCES = libct_proto_icmp.c +libct_proto_icmpv6_la_SOURCES = libct_proto_icmpv6.c diff --git a/include/conntrack.h b/include/conntrack.h index 63facf4..36897c2 100644 --- a/include/conntrack.h +++ b/include/conntrack.h @@ -188,5 +188,6 @@ extern void register_proto(struct ctproto_handler *h); extern void register_tcp(void); extern void register_udp(void); extern void register_icmp(void); +extern void register_icmpv6(void); #endif diff --git a/src/Makefile.am b/src/Makefile.am index 494da4f..d3fc020 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -7,7 +7,7 @@ CLEANFILES = read_config_yy.c read_config_lex.c sbin_PROGRAMS = conntrack conntrackd conntrack_SOURCES = conntrack.c -conntrack_LDADD = ../extensions/libct_proto_tcp.la ../extensions/libct_proto_udp.la ../extensions/libct_proto_icmp.la +conntrack_LDADD = ../extensions/libct_proto_tcp.la ../extensions/libct_proto_udp.la ../extensions/libct_proto_icmp.la ../extensions/libct_proto_icmpv6.la conntrack_LDFLAGS = $(all_libraries) @LIBNETFILTER_CONNTRACK_LIBS@ conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c rbtree.c \ diff --git a/src/conntrack.c b/src/conntrack.c index 82ff544..a6e7d6f 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -684,6 +684,7 @@ int main(int argc, char *argv[]) register_tcp(); register_udp(); register_icmp(); + register_icmpv6(); while ((c = getopt_long(argc, argv, "L::I::U::D::G::E::F::hVs:d:r:q:" "p:t:u:e:a:z[:]:{:}:m:i::f:o:n::" @@ -819,10 +820,13 @@ int main(int argc, char *argv[]) nfct_set_attr_u8(obj, ATTR_REPL_L3PROTO, l3protonum); break; case 'p': + if (!optarg || !*optarg) + exit_error(PARAMETER_PROBLEM, "proto needed\n"); + options |= CT_OPT_PROTO; h = findproto(optarg); if (!h) - exit_error(PARAMETER_PROBLEM, "proto needed\n"); + exit_error(PARAMETER_PROBLEM, "unknown proto\n"); nfct_set_attr_u8(obj, ATTR_ORIG_L4PROTO, h->protonum); nfct_set_attr_u8(obj, ATTR_REPL_L4PROTO, h->protonum); -- cgit v1.2.3 From 68a85b576d96ede8c8986fa4e27be8676f420c80 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Wed, 26 Mar 2008 15:58:42 +0000 Subject: fix minor compilation issue in amd64 with gcc4.3 (reported by Daniel Schepler via M.Kellermann) --- ChangeLog | 1 + src/conntrack.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index a7ffb25..6d94c6a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,7 @@ version 0.9.7 (yet unreleased) Pablo Neira Ayuso : o remove .svn directory from make distcheck tarballs (reported by B.Benjamini) +o fix minor compilation issue in amd64 with gcc4.3 (reported by Daniel Schepler) Krzysztof Oledzki : o fix minor compilation warning diff --git a/src/conntrack.c b/src/conntrack.c index a6e7d6f..0ef230e 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -299,7 +299,7 @@ err2str(int err, enum action command) { CT_CREATE, ETIME, "conntrack has expired" }, { EXP_CREATE, ENOENT, "master conntrack not found" }, { EXP_CREATE, EINVAL, "invalid parameters" }, - { ~0UL, EPERM, "sorry, you must be root or get " + { ~0U, EPERM, "sorry, you must be root or get " "CAP_NET_ADMIN capability to do this"} }; -- cgit v1.2.3 From c36b87b8562e1d8e7ba4df84daee002f7c2a6dbf Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Tue, 8 Apr 2008 11:50:57 +0000 Subject: fix compilation in ARM (reported by Thiemo Seufer via Max Kellermann) --- src/read_config_lex.l | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/read_config_lex.l b/src/read_config_lex.l index 65df1e7..fe2090b 100644 --- a/src/read_config_lex.l +++ b/src/read_config_lex.l @@ -23,6 +23,7 @@ %} %option yylineno +%option noinput %option nounput ws [ \t]+ -- cgit v1.2.3 From 92701a6b224c533346f233061226bee5bb29a5dd Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Tue, 8 Apr 2008 15:50:42 +0000 Subject: fix asymmetric path support (still some open concerns) --- ChangeLog | 1 + include/netlink.h | 4 ++++ src/cache_wt.c | 36 ++++++++++++++++++++++++++++++++---- src/netlink.c | 31 +++++++++++++++++++++++++++++++ 4 files changed, 68 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 6d94c6a..4bd878b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,7 @@ version 0.9.7 (yet unreleased) Pablo Neira Ayuso : o remove .svn directory from make distcheck tarballs (reported by B.Benjamini) o fix minor compilation issue in amd64 with gcc4.3 (reported by Daniel Schepler) +o fix asymmetric path support (reported by Gary Richards) Krzysztof Oledzki : o fix minor compilation warning diff --git a/include/netlink.h b/include/netlink.h index 543eeda..d345656 100644 --- a/include/netlink.h +++ b/include/netlink.h @@ -14,8 +14,12 @@ void nl_resize_socket_buffer(struct nfct_handle *h); int nl_dump_conntrack_table(void); +int nl_exist_conntrack(struct nf_conntrack *ct); + int nl_create_conntrack(struct nf_conntrack *ct); +int nl_update_conntrack(struct nf_conntrack *ct); + int nl_destroy_conntrack(struct nf_conntrack *ct); #endif diff --git a/src/cache_wt.c b/src/cache_wt.c index 8ff8fae..65eb3fe 100644 --- a/src/cache_wt.c +++ b/src/cache_wt.c @@ -16,30 +16,58 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "conntrackd.h" #include "cache.h" #include "netlink.h" #include "us-conntrack.h" +#include "log.h" #include +#include -static void add_update(struct us_conntrack *u) +static void add_wt(struct us_conntrack *u) +{ + int ret; + char __ct[nfct_maxsize()]; + struct nf_conntrack *ct = (struct nf_conntrack *)(void*) __ct; + + ret = nl_exist_conntrack(u->ct); + switch (ret) { + case -1: + dlog(LOG_ERR, "cache_wt problem: %s", strerror(errno)); + break; + case 0: + memcpy(ct, u->ct, nfct_maxsize()); + if (nl_create_conntrack(ct) == -1) + dlog(LOG_ERR, "cache_wt create: %s", strerror(errno)); + break; + case 1: + memcpy(ct, u->ct, nfct_maxsize()); + if (nl_update_conntrack(ct) == -1) + dlog(LOG_ERR, "cache_wt crt-upd: %s", strerror(errno)); + break; + } +} + +static void upd_wt(struct us_conntrack *u) { char __ct[nfct_maxsize()]; struct nf_conntrack *ct = (struct nf_conntrack *)(void*) __ct; memcpy(ct, u->ct, nfct_maxsize()); - nl_create_conntrack(ct); + if (nl_update_conntrack(ct) == -1) + dlog(LOG_ERR, "cache_wt update:%s", strerror(errno)); } static void writethrough_add(struct us_conntrack *u, void *data) { - add_update(u); + add_wt(u); } static void writethrough_update(struct us_conntrack *u, void *data) { - add_update(u); + upd_wt(u); } static void writethrough_destroy(struct us_conntrack *u, void *data) diff --git a/src/netlink.c b/src/netlink.c index f6a2378..1ab75e4 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -23,6 +23,8 @@ #include "log.h" #include "debug.h" +#include + int ignore_conntrack(struct nf_conntrack *ct) { /* ignore a certain protocol */ @@ -193,6 +195,17 @@ int nl_dump_conntrack_table(void) return nfct_query(STATE(dump), NFCT_Q_DUMP, &CONFIG(family)); } +int nl_exist_conntrack(struct nf_conntrack *ct) +{ + int ret; + + ret = nfct_query(STATE(dump), NFCT_Q_GET, ct); + if (ret == -1) + return errno == ENOENT ? 0 : -1; + + return 1; +} + /* This function modifies the conntrack passed as argument! */ int nl_create_conntrack(struct nf_conntrack *ct) { @@ -219,6 +232,24 @@ int nl_create_conntrack(struct nf_conntrack *ct) return nfct_query(STATE(dump), NFCT_Q_CREATE_UPDATE, ct); } +/* This function modifies the conntrack passed as argument! */ +int nl_update_conntrack(struct nf_conntrack *ct) +{ + /* unset NAT info, otherwise we hit error */ + nfct_attr_unset(ct, ATTR_SNAT_IPV4); + nfct_attr_unset(ct, ATTR_DNAT_IPV4); + nfct_attr_unset(ct, ATTR_SNAT_PORT); + nfct_attr_unset(ct, ATTR_DNAT_PORT); + + if (nfct_attr_is_set(ct, ATTR_STATUS)) { + uint32_t status = nfct_get_attr_u32(ct, ATTR_STATUS); + status &= ~IPS_NAT_MASK; + nfct_set_attr_u32(ct, ATTR_STATUS, status); + } + + return nl_create_conntrack(ct); +} + int nl_destroy_conntrack(struct nf_conntrack *ct) { return nfct_query(STATE(dump), NFCT_Q_DESTROY, ct); -- cgit v1.2.3 From 5e5d8cdb3cfed98f1af3f3e265220c90df684674 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Wed, 9 Apr 2008 15:25:59 +0000 Subject: improve netlink overrun handling --- ChangeLog | 1 + include/conntrackd.h | 8 ++++- include/netlink.h | 4 +++ src/netlink.c | 21 +++++++++++++ src/run.c | 27 ++++++++++++++-- src/stats-mode.c | 36 ++++++++++----------- src/sync-mode.c | 89 +++++++++++++++++++++------------------------------- 7 files changed, 111 insertions(+), 75 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 4bd878b..4ca2af1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,6 +5,7 @@ Pablo Neira Ayuso : o remove .svn directory from make distcheck tarballs (reported by B.Benjamini) o fix minor compilation issue in amd64 with gcc4.3 (reported by Daniel Schepler) o fix asymmetric path support (reported by Gary Richards) +o improve netlink overrun handling Krzysztof Oledzki : o fix minor compilation warning diff --git a/include/conntrackd.h b/include/conntrackd.h index 69c1303..57ac7e4 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -3,6 +3,7 @@ #include "mcast.h" #include "local.h" +#include "alarm.h" #include #include @@ -104,6 +105,8 @@ struct ct_general_state { struct nfct_handle *event; /* event handler */ struct nfct_handle *dump; /* dump handler */ + struct nfct_handle *overrun; /* overrun handler */ + struct alarm_block overrun_alarm; struct fds *fds; @@ -158,7 +161,10 @@ struct ct_mode { int (*local)(int fd, int type, void *data); void (*kill)(void); void (*dump)(struct nf_conntrack *ct); - void (*overrun)(void); + int (*overrun)(enum nf_conntrack_msg_type type, + struct nf_conntrack *ct, + void *data); + int (*purge)(void); void (*event_new)(struct nf_conntrack *ct); void (*event_upd)(struct nf_conntrack *ct); int (*event_dst)(struct nf_conntrack *ct); diff --git a/include/netlink.h b/include/netlink.h index d345656..a46fe11 100644 --- a/include/netlink.h +++ b/include/netlink.h @@ -10,6 +10,10 @@ int nl_init_event_handler(void); int nl_init_dump_handler(void); +int nl_init_overrun_handler(void); + +int nl_overrun_request_resync(void); + void nl_resize_socket_buffer(struct nfct_handle *h); int nl_dump_conntrack_table(void); diff --git a/src/netlink.c b/src/netlink.c index 1ab75e4..10c4643 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -158,6 +158,21 @@ int nl_init_dump_handler(void) return 0; } +int nl_init_overrun_handler(void) +{ + STATE(overrun) = nfct_open(CONNTRACK, 0); + if (!STATE(overrun)) + return -1; + + fcntl(nfct_fd(STATE(overrun)), F_SETFL, O_NONBLOCK); + + nfct_callback_register(STATE(overrun), + NFCT_T_ALL, + STATE(mode)->overrun, + NULL); + return 0; +} + static int warned = 0; void nl_resize_socket_buffer(struct nfct_handle *h) @@ -195,6 +210,12 @@ int nl_dump_conntrack_table(void) return nfct_query(STATE(dump), NFCT_Q_DUMP, &CONFIG(family)); } +int nl_overrun_request_resync(void) +{ + int family = CONFIG(family); + return nfct_send(STATE(overrun), NFCT_Q_DUMP, &family); +} + int nl_exist_conntrack(struct nf_conntrack *ct) { int ret; diff --git a/src/run.c b/src/run.c index b259f2e..63761b4 100644 --- a/src/run.c +++ b/src/run.c @@ -89,6 +89,12 @@ void local_handler(int fd, void *data) dlog(LOG_WARNING, "unknown local request %d", type); } +static void do_overrun_alarm(struct alarm_block *a, void *data) +{ + nl_overrun_request_resync(); + add_alarm(&STATE(overrun_alarm), 2, 0); +} + int init(void) { @@ -129,6 +135,15 @@ init(void) return -1; } + if (nl_init_overrun_handler() == -1) { + dlog(LOG_ERR, "can't open netlink handler: %s", + strerror(errno)); + dlog(LOG_ERR, "no ctnetlink kernel support?"); + return -1; + } + + init_alarm(&STATE(overrun_alarm), NULL, do_overrun_alarm); + STATE(fds) = create_fds(); if (STATE(fds) == NULL) { dlog(LOG_ERR, "can't create file descriptor pool"); @@ -137,6 +152,7 @@ init(void) register_fd(STATE(local).fd, STATE(fds)); register_fd(nfct_fd(STATE(event)), STATE(fds)); + register_fd(nfct_fd(STATE(overrun)), STATE(fds)); if (STATE(mode)->register_fds && STATE(mode)->register_fds(STATE(fds)) == -1) { @@ -203,8 +219,8 @@ static void __run(struct timeval *next_alarm) * size and resync with master conntrack table. */ nl_resize_socket_buffer(STATE(event)); - /* XXX: schedule overrun call via alarm */ - STATE(mode)->overrun(); + nl_overrun_request_resync(); + add_alarm(&STATE(overrun_alarm), 2, 0); break; case ENOENT: /* @@ -223,6 +239,13 @@ static void __run(struct timeval *next_alarm) } } + if (FD_ISSET(nfct_fd(STATE(overrun)), &readfds)) { + del_alarm(&STATE(overrun_alarm)); + nfct_catch(STATE(overrun)); + if (STATE(mode)->purge) + STATE(mode)->purge(); + } + if (STATE(mode)->run) STATE(mode)->run(&readfds); diff --git a/src/stats-mode.c b/src/stats-mode.c index 42fa35a..3773feb 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -22,10 +22,12 @@ #include "cache.h" #include "log.h" #include "conntrackd.h" +#include "us-conntrack.h" #include #include #include +#include static int init_stats(void) { @@ -93,9 +95,9 @@ static void dump_stats(struct nf_conntrack *ct) debug_ct(ct, "resync entry"); } -static int overrun_cb(enum nf_conntrack_msg_type type, - struct nf_conntrack *ct, - void *data) +static int overrun_stats(enum nf_conntrack_msg_type type, + struct nf_conntrack *ct, + void *data) { if (ignore_conntrack(ct)) return NFCT_CB_CONTINUE; @@ -115,28 +117,25 @@ static int overrun_cb(enum nf_conntrack_msg_type type, return NFCT_CB_CONTINUE; } -static void overrun_stats(void) +static int purge_step(void *data1, void *data2) { int ret; - struct nfct_handle *h; - int family = CONFIG(family); + struct us_conntrack *u = data2; - h = nfct_open(CONNTRACK, 0); - if (!h) { - dlog(LOG_ERR, "can't open overrun handler"); - return; + ret = nfct_query(STATE(dump), NFCT_Q_GET, u->ct); + if (ret == -1 && errno == ENOENT) { + debug_ct(u->ct, "overrun purge stats"); + cache_del(STATE_STATS(cache), u->ct); } - nfct_callback_register(h, NFCT_T_ALL, overrun_cb, NULL); - - cache_flush(STATE_STATS(cache)); + return 0; +} - ret = nfct_query(h, NFCT_Q_DUMP, &family); - if (ret == -1) - dlog(LOG_ERR, - "overrun query error %s", strerror(errno)); +static int purge_stats(void) +{ + cache_iterate(STATE_STATS(cache), NULL, purge_step); - nfct_close(h); + return 0; } static void event_new_stats(struct nf_conntrack *ct) @@ -187,6 +186,7 @@ struct ct_mode stats_mode = { .kill = kill_stats, .dump = dump_stats, .overrun = overrun_stats, + .purge = purge_stats, .event_new = event_new_stats, .event_upd = event_update_stats, .event_dst = event_destroy_stats diff --git a/src/sync-mode.c b/src/sync-mode.c index 79afcdf..3851e4a 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -350,9 +350,40 @@ static void mcast_send_sync(struct us_conntrack *u, STATE_SYNC(sync)->send(net, u); } -static int overrun_cb(enum nf_conntrack_msg_type type, - struct nf_conntrack *ct, - void *data) +static int purge_step(void *data1, void *data2) +{ + int ret; + struct nfct_handle *h = STATE(dump); + struct us_conntrack *u = data2; + + ret = nfct_query(h, NFCT_Q_GET, u->ct); + if (ret == -1 && errno == ENOENT) { + size_t len; + struct nethdr *net = BUILD_NETMSG(u->ct, NFCT_Q_DESTROY); + + debug_ct(u->ct, "overrun purge resync"); + + len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); + mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); + if (STATE_SYNC(sync)->send) + STATE_SYNC(sync)->send(net, u); + + cache_del(STATE_SYNC(internal), u->ct); + } + + return 0; +} + +static int purge_sync(void) +{ + cache_iterate(STATE_SYNC(internal), NULL, purge_step); + + return 0; +} + +static int overrun_sync(enum nf_conntrack_msg_type type, + struct nf_conntrack *ct, + void *data) { struct us_conntrack *u; @@ -387,57 +418,6 @@ static int overrun_cb(enum nf_conntrack_msg_type type, return NFCT_CB_CONTINUE; } -static int overrun_purge_step(void *data1, void *data2) -{ - int ret; - struct nfct_handle *h = data1; - struct us_conntrack *u = data2; - - ret = nfct_query(h, NFCT_Q_GET, u->ct); - if (ret == -1 && errno == ENOENT) { - size_t len; - struct nethdr *net = BUILD_NETMSG(u->ct, NFCT_Q_DESTROY); - - debug_ct(u->ct, "overrun purge resync"); - - len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); - if (STATE_SYNC(sync)->send) - STATE_SYNC(sync)->send(net, u); - - cache_del(STATE_SYNC(internal), u->ct); - } - - return 0; -} - -/* it's likely that we're losing events, just try to do our best here */ -static void overrun_sync(void) -{ - int ret; - struct nfct_handle *h; - int family = CONFIG(family); - - h = nfct_open(CONNTRACK, 0); - if (!h) { - dlog(LOG_ERR, "can't open overrun handler"); - return; - } - - nfct_callback_register(h, NFCT_T_ALL, overrun_cb, NULL); - - ret = nfct_query(h, NFCT_Q_DUMP, &family); - if (ret == -1) - dlog(LOG_ERR, - "overrun query error %s", strerror(errno)); - - nfct_callback_unregister(h); - - cache_iterate(STATE_SYNC(internal), h, overrun_purge_step); - - nfct_close(h); -} - static void event_new_sync(struct nf_conntrack *ct) { struct us_conntrack *u; @@ -505,6 +485,7 @@ struct ct_mode sync_mode = { .kill = kill_sync, .dump = dump_sync, .overrun = overrun_sync, + .purge = purge_sync, .event_new = event_new_sync, .event_upd = event_update_sync, .event_dst = event_destroy_sync -- cgit v1.2.3 From 15c3aa58b5f1011e0116fe4d277c4f8a9c5704c2 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Sat, 12 Apr 2008 04:21:33 +0000 Subject: o simplify parameter-handling code o check for missing source/address IP/ports o minor cleanups --- ChangeLog | 3 + extensions/libct_proto_tcp.c | 33 +--- extensions/libct_proto_udp.c | 33 +--- src/conntrack.c | 355 +++++++++++++++++-------------------------- 4 files changed, 157 insertions(+), 267 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index d170f78..e3cf6c0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -7,6 +7,9 @@ o fix minor compilation issue in amd64 with gcc4.3 (reported by Daniel Schepler) o fix asymmetric path support (reported by Gary Richards) o improve netlink overrun handling o update manpages with the new URL: http://conntrack-tools.netfilter.org +o simplify parameter-handling code +o check for missing source/address IP/ports +o minor cleanups Krzysztof Oledzki : o fix minor compilation warning diff --git a/extensions/libct_proto_tcp.c b/extensions/libct_proto_tcp.c index a3b1826..b17a931 100644 --- a/extensions/libct_proto_tcp.c +++ b/extensions/libct_proto_tcp.c @@ -44,10 +44,10 @@ static char tcp_commands_v_options[NUMBER_OF_CMD][TCP_NUMBER_OF_OPT] = { /* 1 2 3 4 5 6 7 8 9 */ /*CT_LIST*/ {2,2,2,2,0,0,2,0,0}, -/*CT_CREATE*/ {1,1,1,1,0,0,1,0,0}, -/*CT_UPDATE*/ {1,1,1,1,0,0,2,0,0}, -/*CT_DELETE*/ {1,1,1,1,0,0,0,0,0}, -/*CT_GET*/ {1,1,1,1,0,0,2,0,0}, +/*CT_CREATE*/ {2,2,2,2,0,0,1,0,0}, +/*CT_UPDATE*/ {2,2,2,2,0,0,2,0,0}, +/*CT_DELETE*/ {2,2,2,2,0,0,0,0,0}, +/*CT_GET*/ {2,2,2,2,0,0,2,0,0}, /*CT_FLUSH*/ {0,0,0,0,0,0,0,0,0}, /*CT_EVENT*/ {2,2,2,2,0,0,2,0,0}, /*CT_VERSION*/ {0,0,0,0,0,0,0,0,0}, @@ -200,27 +200,10 @@ static void final_check(unsigned int flags, unsigned int cmd, struct nf_conntrack *ct) { - if ((flags & (TCP_ORIG_SPORT|TCP_ORIG_DPORT)) - && !(flags & (TCP_REPL_SPORT|TCP_REPL_DPORT))) { - nfct_set_attr_u16(ct, - ATTR_REPL_PORT_SRC, - nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST)); - nfct_set_attr_u16(ct, - ATTR_REPL_PORT_DST, - nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC)); - flags |= TCP_REPL_SPORT; - flags |= TCP_REPL_DPORT; - } else if (!(flags & (TCP_ORIG_SPORT|TCP_ORIG_DPORT)) - && (flags & (TCP_REPL_SPORT|TCP_REPL_DPORT))) { - nfct_set_attr_u16(ct, - ATTR_ORIG_PORT_SRC, - nfct_get_attr_u16(ct, ATTR_REPL_PORT_DST)); - nfct_set_attr_u16(ct, - ATTR_ORIG_PORT_DST, - nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC)); - flags |= TCP_ORIG_SPORT; - flags |= TCP_ORIG_DPORT; - } + if ((1 << cmd) & (CT_CREATE|CT_UPDATE|CT_DELETE|CT_GET) && + !((flags & TCP_ORIG_SPORT && flags & TCP_ORIG_DPORT) || + (flags & TCP_REPL_SPORT && flags & TCP_REPL_DPORT))) + exit_error(PARAMETER_PROBLEM, "missing ports"); generic_opt_check(flags, TCP_NUMBER_OF_OPT, diff --git a/extensions/libct_proto_udp.c b/extensions/libct_proto_udp.c index a72f9cf..cb52c58 100644 --- a/extensions/libct_proto_udp.c +++ b/extensions/libct_proto_udp.c @@ -54,10 +54,10 @@ static char udp_commands_v_options[NUMBER_OF_CMD][UDP_NUMBER_OF_OPT] = { /* 1 2 3 4 5 6 7 8 */ /*CT_LIST*/ {2,2,2,2,0,0,0,0}, -/*CT_CREATE*/ {1,1,1,1,0,0,0,0}, -/*CT_UPDATE*/ {1,1,1,1,0,0,0,0}, -/*CT_DELETE*/ {1,1,1,1,0,0,0,0}, -/*CT_GET*/ {1,1,1,1,0,0,0,0}, +/*CT_CREATE*/ {2,2,2,2,0,0,0,0}, +/*CT_UPDATE*/ {2,2,2,2,0,0,0,0}, +/*CT_DELETE*/ {2,2,2,2,0,0,0,0}, +/*CT_GET*/ {2,2,2,2,0,0,0,0}, /*CT_FLUSH*/ {0,0,0,0,0,0,0,0}, /*CT_EVENT*/ {2,2,2,2,0,0,0,0}, /*CT_VERSION*/ {0,0,0,0,0,0,0,0}, @@ -165,27 +165,10 @@ static void final_check(unsigned int flags, unsigned int cmd, struct nf_conntrack *ct) { - if ((flags & (UDP_ORIG_SPORT|UDP_ORIG_DPORT)) - && !(flags & (UDP_REPL_SPORT|UDP_REPL_DPORT))) { - nfct_set_attr_u16(ct, - ATTR_REPL_PORT_SRC, - nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST)); - nfct_set_attr_u16(ct, - ATTR_REPL_PORT_DST, - nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC)); - flags |= UDP_REPL_SPORT; - flags |= UDP_REPL_DPORT; - } else if (!(flags & (UDP_ORIG_SPORT|UDP_ORIG_DPORT)) - && (flags & (UDP_REPL_SPORT|UDP_REPL_DPORT))) { - nfct_set_attr_u16(ct, - ATTR_ORIG_PORT_SRC, - nfct_get_attr_u16(ct, ATTR_REPL_PORT_DST)); - nfct_set_attr_u16(ct, - ATTR_ORIG_PORT_DST, - nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC)); - flags |= UDP_ORIG_SPORT; - flags |= UDP_ORIG_DPORT; - } + if ((1 << cmd) & (CT_CREATE|CT_UPDATE|CT_DELETE|CT_GET) && + !((flags & UDP_ORIG_SPORT && flags & UDP_ORIG_DPORT) || + (flags & UDP_REPL_SPORT && flags & UDP_REPL_DPORT))) + exit_error(PARAMETER_PROBLEM, "missing ports"); generic_opt_check(flags, UDP_NUMBER_OF_OPT, diff --git a/src/conntrack.c b/src/conntrack.c index 0ef230e..4fa5c9a 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -200,6 +200,7 @@ exit_error(enum exittype status, const char *msg, ...) va_start(args, msg); fprintf(stderr,"%s v%s: ", PROGNAME, VERSION); vfprintf(stderr, msg, args); + fprintf(stderr, "\n"); va_end(args); if (status == PARAMETER_PROBLEM) exit_tryhelp(status); @@ -211,7 +212,7 @@ generic_cmd_check(int command, int local_options) { if (cmd_need_param[command] == 0 && !local_options) exit_error(PARAMETER_PROBLEM, - "You need to supply parameters to `-%c'\n", + "You need to supply parameters to `-%c'", cmdflags[command]); } @@ -239,12 +240,12 @@ void generic_opt_check(int local_options, exit_error(PARAMETER_PROBLEM, "You need to supply the " "`--%s' option for this " - "command\n", optflg[i]); + "command", optflg[i]); } else { if (optset[i] == 0) exit_error(PARAMETER_PROBLEM, "Illegal " "option `--%s' with this " - "command\n", optflg[i]); + "command", optflg[i]); } } } @@ -377,9 +378,9 @@ parse_parameter(const char *arg, unsigned int *status, int parse_type) } static void -add_command(unsigned int *cmd, const int newcmd, const int othercmds) +add_command(unsigned int *cmd, const int newcmd) { - if (*cmd & (~othercmds)) + if (*cmd) exit_error(PARAMETER_PROBLEM, "Invalid commands combination\n"); *cmd |= newcmd; } @@ -406,7 +407,7 @@ check_type(int argc, char *argv[]) else if (strncmp("conntrack", table, 9) == 0) return 0; else - exit_error(PARAMETER_PROBLEM, "unknown type `%s'\n", table); + exit_error(PARAMETER_PROBLEM, "unknown type `%s'", table); return 0; } @@ -416,7 +417,7 @@ static void set_family(int *family, int new) if (*family == AF_UNSPEC) *family = new; else if (*family != new) - exit_error(PARAMETER_PROBLEM, "mismatched address family\n"); + exit_error(PARAMETER_PROBLEM, "mismatched address family"); } struct addr_parse { @@ -435,7 +436,7 @@ parse_inetaddr(const char *cp, struct addr_parse *parse) return AF_INET6; #endif - exit_error(PARAMETER_PROBLEM, "Invalid IP address `%s'.", cp); + exit_error(PARAMETER_PROBLEM, "Invalid IP address `%s'", cp); } union ct_address { @@ -476,12 +477,12 @@ nat_parse(char *arg, int portok, struct nf_conntrack *obj, int type) port = (uint16_t)atoi(colon+1); if (port == 0) exit_error(PARAMETER_PROBLEM, - "Port `%s' not valid\n", colon+1); + "Port `%s' not valid", colon+1); error = strchr(colon+1, ':'); if (error) exit_error(PARAMETER_PROBLEM, - "Invalid port:port syntax\n"); + "Invalid port:port syntax"); if (type == CT_OPT_SRC_NAT) nfct_set_attr_u16(obj, ATTR_SNAT_PORT, port); @@ -658,6 +659,51 @@ static int dump_exp_cb(enum nf_conntrack_msg_type type, static struct ctproto_handler *h; +static const int cmd2type[][2] = { + ['L'] = { CT_LIST, EXP_LIST }, + ['I'] = { CT_CREATE, EXP_CREATE }, + ['D'] = { CT_DELETE, EXP_DELETE }, + ['G'] = { CT_GET, EXP_GET }, + ['F'] = { CT_FLUSH, EXP_FLUSH }, + ['V'] = { CT_VERSION, CT_VERSION }, + ['h'] = { CT_HELP, CT_HELP }, +}; + +static const int opt2type[] = { + ['s'] = CT_OPT_ORIG_SRC, + ['d'] = CT_OPT_ORIG_DST, + ['r'] = CT_OPT_REPL_SRC, + ['q'] = CT_OPT_REPL_DST, + ['{'] = CT_OPT_MASK_SRC, + ['}'] = CT_OPT_MASK_DST, + ['['] = CT_OPT_EXP_SRC, + [']'] = CT_OPT_EXP_DST, + ['n'] = CT_OPT_SRC_NAT, + ['g'] = CT_OPT_DST_NAT, + ['m'] = CT_OPT_MARK, + ['c'] = CT_OPT_SECMARK, +}; + +static const int opt2family_attr[][2] = { + ['s'] = { ATTR_ORIG_IPV4_SRC, ATTR_ORIG_IPV6_SRC }, + ['d'] = { ATTR_ORIG_IPV4_DST, ATTR_ORIG_IPV6_DST }, + ['r'] = { ATTR_REPL_IPV4_SRC, ATTR_REPL_IPV6_SRC }, + ['q'] = { ATTR_REPL_IPV4_DST, ATTR_REPL_IPV6_DST }, + ['{'] = { ATTR_ORIG_IPV4_SRC, ATTR_ORIG_IPV6_SRC }, + ['}'] = { ATTR_ORIG_IPV4_DST, ATTR_ORIG_IPV6_DST }, + ['['] = { ATTR_ORIG_IPV4_SRC, ATTR_ORIG_IPV6_SRC }, + [']'] = { ATTR_ORIG_IPV4_DST, ATTR_ORIG_IPV6_DST }, +}; + +static const int opt2attr[] = { + ['s'] = ATTR_ORIG_L3PROTO, + ['d'] = ATTR_ORIG_L3PROTO, + ['r'] = ATTR_REPL_L3PROTO, + ['q'] = ATTR_REPL_L3PROTO, + ['m'] = ATTR_MARK, + ['c'] = ATTR_SECMARK, +}; + int main(int argc, char *argv[]) { int c, cmd; @@ -691,142 +737,83 @@ int main(int argc, char *argv[]) "g::c:", opts, NULL)) != -1) { switch(c) { + /* commands */ case 'L': - type = check_type(argc, argv); - if (type == 0) - add_command(&command, CT_LIST, CT_NONE); - else if (type == 1) - add_command(&command, EXP_LIST, CT_NONE); - break; case 'I': - type = check_type(argc, argv); - if (type == 0) - add_command(&command, CT_CREATE, CT_NONE); - else if (type == 1) - add_command(&command, EXP_CREATE, CT_NONE); - break; - case 'U': - type = check_type(argc, argv); - if (type == 0) - add_command(&command, CT_UPDATE, CT_NONE); - else - exit_error(PARAMETER_PROBLEM, "Can't update " - "expectations"); - break; case 'D': - type = check_type(argc, argv); - if (type == 0) - add_command(&command, CT_DELETE, CT_NONE); - else if (type == 1) - add_command(&command, EXP_DELETE, CT_NONE); - break; case 'G': - type = check_type(argc, argv); - if (type == 0) - add_command(&command, CT_GET, CT_NONE); - else if (type == 1) - add_command(&command, EXP_GET, CT_NONE); - break; case 'F': + case 'E': + case 'V': + case 'h': type = check_type(argc, argv); - if (type == 0) - add_command(&command, CT_FLUSH, CT_NONE); - else if (type == 1) - add_command(&command, EXP_FLUSH, CT_NONE); + add_command(&command, cmd2type[c][type]); break; - case 'E': + case 'U': type = check_type(argc, argv); if (type == 0) - add_command(&command, CT_EVENT, CT_NONE); - else if (type == 1) - add_command(&command, EXP_EVENT, CT_NONE); - break; - case 'V': - add_command(&command, CT_VERSION, CT_NONE); - break; - case 'h': - add_command(&command, CT_HELP, CT_NONE); + add_command(&command, CT_UPDATE); + else + exit_error(PARAMETER_PROBLEM, + "Can't update expectations"); break; + /* options */ case 's': - options |= CT_OPT_ORIG_SRC; - if (!optarg) - break; - - l3protonum = parse_addr(optarg, &ad); - set_family(&family, l3protonum); - if (l3protonum == AF_INET) { - nfct_set_attr_u32(obj, - ATTR_ORIG_IPV4_SRC, - ad.v4); - } else if (l3protonum == AF_INET6) { - nfct_set_attr(obj, - ATTR_ORIG_IPV6_SRC, - &ad.v6); - } - nfct_set_attr_u8(obj, ATTR_ORIG_L3PROTO, l3protonum); - break; case 'd': - options |= CT_OPT_ORIG_DST; - if (!optarg) - break; - - l3protonum = parse_addr(optarg, &ad); - set_family(&family, l3protonum); - if (l3protonum == AF_INET) { - nfct_set_attr_u32(obj, - ATTR_ORIG_IPV4_DST, - ad.v4); - } else if (l3protonum == AF_INET6) { - nfct_set_attr(obj, - ATTR_ORIG_IPV6_DST, - &ad.v6); - } - nfct_set_attr_u8(obj, ATTR_ORIG_L3PROTO, l3protonum); - break; case 'r': - options |= CT_OPT_REPL_SRC; + case 'q': if (!optarg) - break; + exit_error(PARAMETER_PROBLEM, + "-%c requires an IP", c); + + options |= opt2type[c]; l3protonum = parse_addr(optarg, &ad); set_family(&family, l3protonum); if (l3protonum == AF_INET) { nfct_set_attr_u32(obj, - ATTR_REPL_IPV4_SRC, + opt2family_attr[c][0], ad.v4); } else if (l3protonum == AF_INET6) { nfct_set_attr(obj, - ATTR_REPL_IPV6_SRC, + opt2family_attr[c][1], &ad.v6); } - nfct_set_attr_u8(obj, ATTR_REPL_L3PROTO, l3protonum); + nfct_set_attr_u8(obj, opt2attr[c], l3protonum); break; - case 'q': - options |= CT_OPT_REPL_DST; + case '{': + case '}': + case '[': + case ']': if (!optarg) - break; + exit_error(PARAMETER_PROBLEM, + "-%c requires an IP", c); + options |= opt2type[c]; l3protonum = parse_addr(optarg, &ad); set_family(&family, l3protonum); if (l3protonum == AF_INET) { - nfct_set_attr_u32(obj, - ATTR_REPL_IPV4_DST, + nfct_set_attr_u32(mask, + opt2family_attr[c][0], ad.v4); } else if (l3protonum == AF_INET6) { - nfct_set_attr(obj, - ATTR_REPL_IPV6_DST, + nfct_set_attr(mask, + opt2family_attr[c][1], &ad.v6); } - nfct_set_attr_u8(obj, ATTR_REPL_L3PROTO, l3protonum); + nfct_set_attr_u8(mask, ATTR_ORIG_L3PROTO, l3protonum); break; case 'p': if (!optarg || !*optarg) - exit_error(PARAMETER_PROBLEM, "proto needed\n"); + exit_error(PARAMETER_PROBLEM, + "-%c requires a valid protocol", c); options |= CT_OPT_PROTO; h = findproto(optarg); if (!h) - exit_error(PARAMETER_PROBLEM, "unknown proto\n"); + exit_error(PARAMETER_PROBLEM, + "`%s' unsupported protocol", + optarg); nfct_set_attr_u8(obj, ATTR_ORIG_L4PROTO, h->protonum); nfct_set_attr_u8(obj, ATTR_REPL_L4PROTO, h->protonum); @@ -838,140 +825,72 @@ int main(int argc, char *argv[]) h->protonum); opts = merge_options(opts, h->opts, &h->option_offset); if (opts == NULL) - exit_error(EXIT_FAILURE, "out of memory\n"); + exit_error(OTHER_PROBLEM, "out of memory"); break; case 't': - options |= CT_OPT_TIMEOUT; if (!optarg) - continue; + exit_error(PARAMETER_PROBLEM, + "-%c requires value", c); + options |= CT_OPT_TIMEOUT; nfct_set_attr_u32(obj, ATTR_TIMEOUT, atol(optarg)); nfexp_set_attr_u32(exp, ATTR_EXP_TIMEOUT, atol(optarg)); break; - case 'u': { + case 'u': if (!optarg) - continue; + exit_error(PARAMETER_PROBLEM, + "-%c requires type", c); options |= CT_OPT_STATUS; parse_parameter(optarg, &status, PARSE_STATUS); nfct_set_attr_u32(obj, ATTR_STATUS, status); break; - } case 'e': - options |= CT_OPT_EVENT_MASK; - parse_parameter(optarg, &event_mask, PARSE_EVENT); - break; - case 'z': - options |= CT_OPT_ZERO; - break; - case '{': - options |= CT_OPT_MASK_SRC; - if (!optarg) - break; - - l3protonum = parse_addr(optarg, &ad); - set_family(&family, l3protonum); - if (l3protonum == AF_INET) { - nfct_set_attr_u32(mask, - ATTR_ORIG_IPV4_SRC, - ad.v4); - } else if (l3protonum == AF_INET6) { - nfct_set_attr(mask, - ATTR_ORIG_IPV6_SRC, - &ad.v6); - } - nfct_set_attr_u8(mask, ATTR_ORIG_L3PROTO, l3protonum); - break; - case '}': - options |= CT_OPT_MASK_DST; if (!optarg) - break; + exit_error(PARAMETER_PROBLEM, + "-%c requires type", c); - l3protonum = parse_addr(optarg, &ad); - set_family(&family, l3protonum); - if (l3protonum == AF_INET) { - nfct_set_attr_u32(mask, - ATTR_ORIG_IPV4_DST, - ad.v4); - } else if (l3protonum == AF_INET6) { - nfct_set_attr(mask, - ATTR_ORIG_IPV6_DST, - &ad.v6); - } - nfct_set_attr_u8(mask, ATTR_ORIG_L3PROTO, l3protonum); + options |= CT_OPT_EVENT_MASK; + parse_parameter(optarg, &event_mask, PARSE_EVENT); break; - case '[': - options |= CT_OPT_EXP_SRC; + case 'o': if (!optarg) - break; + exit_error(PARAMETER_PROBLEM, + "-%c requires type", c); - l3protonum = parse_addr(optarg, &ad); - set_family(&family, l3protonum); - if (l3protonum == AF_INET) { - nfct_set_attr_u32(exptuple, - ATTR_ORIG_IPV4_SRC, - ad.v4); - } else if (l3protonum == AF_INET6) { - nfct_set_attr(exptuple, - ATTR_ORIG_IPV6_SRC, - &ad.v6); - } - nfct_set_attr_u8(exptuple, - ATTR_ORIG_L3PROTO, - l3protonum); + options |= CT_OPT_OUTPUT; + parse_parameter(optarg, &output_mask, PARSE_OUTPUT); break; - case ']': - options |= CT_OPT_EXP_DST; - if (!optarg) - break; + case 'z': + if (optarg) + exit_error(PARAMETER_PROBLEM, + "-%c does not require parameters",c); - l3protonum = parse_addr(optarg, &ad); - set_family(&family, l3protonum); - if (l3protonum == AF_INET) { - nfct_set_attr_u32(exptuple, - ATTR_ORIG_IPV4_DST, - ad.v4); - } else if (l3protonum == AF_INET6) { - nfct_set_attr(exptuple, - ATTR_ORIG_IPV6_DST, - &ad.v6); - } - nfct_set_attr_u8(exptuple, - ATTR_ORIG_L3PROTO, - l3protonum); - break; - case 'a': - fprintf(stderr, "warning: ignoring --nat-range, " - "use --src-nat or --dst-nat instead.\n"); + options |= CT_OPT_ZERO; break; case 'n': - options |= CT_OPT_SRC_NAT; - if (!optarg) - break; - set_family(&family, AF_INET); - nat_parse(optarg, 1, obj, CT_OPT_SRC_NAT); - break; case 'g': - options |= CT_OPT_DST_NAT; if (!optarg) - break; + exit_error(PARAMETER_PROBLEM, + "-%c requires an IP", c); + + options |= opt2type[c]; set_family(&family, AF_INET); - nat_parse(optarg, 1, obj, CT_OPT_DST_NAT); - case 'm': - options |= CT_OPT_MARK; - if (!optarg) - continue; - nfct_set_attr_u32(obj, ATTR_MARK, atol(optarg)); + nat_parse(optarg, 1, obj, opt2type[c]); break; + case 'm': case 'c': - options |= CT_OPT_SECMARK; + options |= opt2type[c]; if (!optarg) - continue; - nfct_set_attr_u32(obj, ATTR_SECMARK, atol(optarg)); + exit_error(PARAMETER_PROBLEM, + "-%c requires value", c); + + nfct_set_attr_u32(obj, opt2attr[c], atol(optarg)); break; case 'i': - fprintf(stderr, - "warning: ignoring --id. deprecated option.\n"); + case 'a': + fprintf(stderr, "WARNING: ignoring -%c, " + "deprecated option.\n", c); break; case 'f': options |= CT_OPT_FAMILY; @@ -980,24 +899,21 @@ int main(int argc, char *argv[]) else if (strncmp(optarg, "ipv6", strlen("ipv6")) == 0) set_family(&family, AF_INET6); else - exit_error(PARAMETER_PROBLEM, "Unknown " - "protocol family\n"); - break; - case 'o': - options |= CT_OPT_OUTPUT; - parse_parameter(optarg, &output_mask, PARSE_OUTPUT); + exit_error(PARAMETER_PROBLEM, + "`%s' unsupported protocol", + optarg); break; default: if (h && h->parse_opts &&!h->parse_opts(c - h->option_offset, obj, exptuple, mask, &l4flags)) - exit_error(PARAMETER_PROBLEM, "parse error\n"); + exit_error(PARAMETER_PROBLEM, "parse error"); /* Unknown argument... */ if (!h) { usage(argv[0]); - exit_error(PARAMETER_PROBLEM, "Missing " - "arguments...\n"); + exit_error(PARAMETER_PROBLEM, + "Missing arguments..."); } break; } @@ -1014,6 +930,11 @@ int main(int argc, char *argv[]) commands_v_options[cmd], optflags); + if (command & (CT_CREATE|CT_UPDATE|CT_DELETE|CT_GET) && + !((options & CT_OPT_ORIG_SRC && options & CT_OPT_ORIG_DST) || + (options & CT_OPT_REPL_SRC && options & CT_OPT_REPL_DST))) + exit_error(PARAMETER_PROBLEM, "missing IP address"); + if (!(command & CT_HELP) && h && h->final_check) h->final_check(l4flags, cmd, obj); -- cgit v1.2.3 From de56472737c5aa007f775bc475570f49c0e55fb3 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Sun, 13 Apr 2008 01:25:48 +0000 Subject: This is a major improvement of the conntrack command line tool: o check for missing source/address IP/ports in creation and get operations o way more flexible conntrack updates and deletions o fix NAT filtering via --src-nat and --dst-nat (reported by K.Oledzki) o show display counters to stderr o minor cleanups --- ChangeLog | 20 ++-- configure.in | 2 +- src/conntrack.c | 289 ++++++++++++++++++++++++++++++++++++++++++-------------- 3 files changed, 233 insertions(+), 78 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index e3cf6c0..5dd73a9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,20 +1,24 @@ version 0.9.7 (yet unreleased) ------------------------------ -Pablo Neira Ayuso : o remove .svn directory from make distcheck tarballs (reported by B.Benjamini) o fix minor compilation issue in amd64 with gcc4.3 (reported by Daniel Schepler) -o fix asymmetric path support (reported by Gary Richards) -o improve netlink overrun handling o update manpages with the new URL: http://conntrack-tools.netfilter.org + += conntrack = +o fix minor compilation warning (Krzysztof Oledzki) +o add ICMPv6 (-p icmpv6) support (Krzysztof Oledzki) +o distinguish between invalid (unknown) and empty proto (Krzysztof Oledzki) o simplify parameter-handling code -o check for missing source/address IP/ports +o check for missing source/address IP/ports in creation and get operations +o way more flexible conntrack updates and deletions +o fix NAT filtering via --src-nat and --dst-nat (reported by K.Oledzki) +o show display counters to stderr o minor cleanups -Krzysztof Oledzki : -o fix minor compilation warning -o add ICMPv6 (-p icmpv6) support -o add possibility to distinguish between invalid (unknown) and empty proto += conntrackd = +o fix asymmetric path support (reported by Gary Richards) +o improve netlink overrun handling version 0.9.6 (2008/03/08) ------------------------------ diff --git a/configure.in b/configure.in index a98a324..92a0389 100644 --- a/configure.in +++ b/configure.in @@ -18,7 +18,7 @@ esac dnl Dependencies LIBNFNETLINK_REQUIRED=0.0.32 -LIBNETFILTER_CONNTRACK_REQUIRED=0.0.89 +LIBNETFILTER_CONNTRACK_REQUIRED=0.0.91 PKG_CHECK_MODULES(LIBNFNETLINK, libnfnetlink >= $LIBNFNETLINK_REQUIRED,, AC_MSG_ERROR(Cannot find libnfnetlink >= $LIBNFNETLINK_REQUIRED)) diff --git a/src/conntrack.c b/src/conntrack.c index 4fa5c9a..f4dfec7 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -1,5 +1,5 @@ /* - * (C) 2005-2007 by Pablo Neira Ayuso + * (C) 2005-2008 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 @@ -31,7 +31,8 @@ * Remove remaints of "-A" * 2007-04-22 Pablo Neira Ayuso : * Ported to the new libnetfilter_conntrack API - * + * 2008-04-13 Pablo Neira Ayuso : + * Way more flexible update and delete operations */ #include "conntrack.h" @@ -103,7 +104,7 @@ static struct option original_opts[] = { #define OPTION_OFFSET 256 -static struct nfct_handle *cth; +static struct nfct_handle *cth, *ith; static struct option *opts = original_opts; static unsigned int global_option_offset = 0; @@ -122,8 +123,8 @@ static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = /* s d r q p t u z e [ ] { } a m i f n g o c */ /*CT_LIST*/ {2,2,2,2,2,0,0,2,0,0,0,0,0,0,2,2,2,2,2,2,2}, /*CT_CREATE*/ {2,2,2,2,1,1,1,0,0,0,0,0,0,2,2,0,0,2,2,0,2}, -/*CT_UPDATE*/ {2,2,2,2,1,2,2,0,0,0,0,0,0,0,2,2,0,0,0,0,2}, -/*CT_DELETE*/ {2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0}, +/*CT_UPDATE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,2}, +/*CT_DELETE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,2}, /*CT_GET*/ {2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,2,0,0,0,2,0}, /*CT_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, /*CT_EVENT*/ {2,2,2,2,2,0,0,0,2,0,0,0,0,0,2,0,0,2,2,2,2}, @@ -499,14 +500,6 @@ nat_parse(char *arg, int portok, struct nf_conntrack *obj, int type) nfct_set_attr_u32(obj, ATTR_DNAT_IPV4, parse.v4); } -static void __attribute__((noreturn)) -event_sighandler(int s) -{ - fprintf(stdout, "Now closing conntrack event dumping...\n"); - nfct_close(cth); - exit(0); -} - static const char usage_commands[] = "Commands:\n" " -L [table] [options]\t\tList conntrack or expectation table\n" @@ -566,82 +559,207 @@ usage(char *prog) static unsigned int output_mask; +static int ignore_nat(const struct nf_conntrack *obj, + const struct nf_conntrack *ct) +{ + uint32_t ip; + + if (options & CT_OPT_SRC_NAT && options & CT_OPT_DST_NAT) { + if (!nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT) && + !nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) + return 1; + + if (nfct_attr_is_set(obj, ATTR_SNAT_IPV4)) { + ip = nfct_get_attr_u32(obj, ATTR_SNAT_IPV4); + if (ip != nfct_get_attr_u32(ct, ATTR_REPL_IPV4_DST)) + return 1; + } + + if (nfct_attr_is_set(obj, ATTR_DNAT_IPV4)) { + ip = nfct_get_attr_u32(obj, ATTR_DNAT_IPV4); + if (ip != nfct_get_attr_u32(ct, ATTR_REPL_IPV4_SRC)) + return 1; + } + } else if (options & CT_OPT_SRC_NAT) { + if (!nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) + return 1; + + if (nfct_attr_is_set(obj, ATTR_SNAT_IPV4)) { + ip = nfct_get_attr_u32(obj, ATTR_SNAT_IPV4); + if (ip != nfct_get_attr_u32(ct, ATTR_REPL_IPV4_DST)) + return 1; + } + } else if (options & CT_OPT_DST_NAT) { + if (!nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) + return 1; + + if (nfct_attr_is_set(obj, ATTR_DNAT_IPV4)) { + ip = nfct_get_attr_u32(obj, ATTR_DNAT_IPV4); + if (ip != nfct_get_attr_u32(ct, ATTR_REPL_IPV4_SRC)) + return 1; + } + } + + return 0; +} + +static int events_counter; + +static void __attribute__((noreturn)) +event_sighandler(int s) +{ + fprintf(stderr, "%s v%s: ", PROGNAME, VERSION); + fprintf(stderr, "%d flow events has been shown.\n", events_counter); + nfct_close(cth); + exit(0); +} + static int event_cb(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data) { char buf[1024]; struct nf_conntrack *obj = data; - unsigned int output_type = NFCT_O_DEFAULT; - unsigned int output_flags = 0; + unsigned int op_type = NFCT_O_DEFAULT; + unsigned int op_flags = 0; - if (options & CT_OPT_SRC_NAT && options & CT_OPT_DST_NAT) { - if (!nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT) && - !nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) - return NFCT_CB_CONTINUE; - } else if (options & CT_OPT_SRC_NAT && - !nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) { - return NFCT_CB_CONTINUE; - } else if (options & CT_OPT_DST_NAT && - !nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) { + if (ignore_nat(obj, ct)) return NFCT_CB_CONTINUE; - } - if (options & CT_COMPARISON && !nfct_compare(obj, ct)) + if (options & CT_COMPARISON && !nfct_cmp(obj, ct, NFCT_CMP_ALL)) return NFCT_CB_CONTINUE; if (output_mask & _O_XML) - output_type = NFCT_O_XML; + op_type = NFCT_O_XML; if (output_mask & _O_EXT) - output_flags = NFCT_OF_SHOW_LAYER3; + op_flags = NFCT_OF_SHOW_LAYER3; if (output_mask & _O_TMS) { if (!(output_mask & _O_XML)) { struct timeval tv; gettimeofday(&tv, NULL); printf("[%-8ld.%-6ld]\t", tv.tv_sec, tv.tv_usec); } else - output_flags |= NFCT_OF_TIME; + op_flags |= NFCT_OF_TIME; } - nfct_snprintf(buf, 1024, ct, type, output_type, output_flags); + nfct_snprintf(buf, 1024, ct, type, op_type, op_flags); printf("%s\n", buf); fflush(stdout); + events_counter++; + return NFCT_CB_CONTINUE; } +static int list_counter; + static int dump_cb(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data) { char buf[1024]; struct nf_conntrack *obj = data; - unsigned int output_type = NFCT_O_DEFAULT; - unsigned int output_flags = 0; + unsigned int op_type = NFCT_O_DEFAULT; + unsigned int op_flags = 0; - if (options & CT_OPT_SRC_NAT && options & CT_OPT_DST_NAT) { - if (!nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT) && - !nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) - return NFCT_CB_CONTINUE; - } else if (options & CT_OPT_SRC_NAT && - !nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) { - return NFCT_CB_CONTINUE; - } else if (options & CT_OPT_DST_NAT && - !nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) { + if (ignore_nat(obj, ct)) return NFCT_CB_CONTINUE; - } - if (options & CT_COMPARISON && !nfct_compare(obj, ct)) + if (options & CT_COMPARISON && !nfct_cmp(obj, ct, NFCT_CMP_ALL)) return NFCT_CB_CONTINUE; if (output_mask & _O_XML) - output_type = NFCT_O_XML; + op_type = NFCT_O_XML; if (output_mask & _O_EXT) - output_flags = NFCT_OF_SHOW_LAYER3; + op_flags = NFCT_OF_SHOW_LAYER3; - nfct_snprintf(buf, 1024, ct, NFCT_T_UNKNOWN, output_type, output_flags); + nfct_snprintf(buf, 1024, ct, NFCT_T_UNKNOWN, op_type, op_flags); printf("%s\n", buf); + list_counter++; + + return NFCT_CB_CONTINUE; +} + +static int delete_counter; + +static int delete_cb(enum nf_conntrack_msg_type type, + struct nf_conntrack *ct, + void *data) +{ + int res; + char buf[1024]; + struct nf_conntrack *obj = data; + unsigned int op_type = NFCT_O_DEFAULT; + unsigned int op_flags = 0; + + if (ignore_nat(obj, ct)) + return NFCT_CB_CONTINUE; + + if (options & CT_COMPARISON && !nfct_cmp(obj, ct, NFCT_CMP_ALL)) + return NFCT_CB_CONTINUE; + + res = nfct_query(ith, NFCT_Q_DESTROY, ct); + if (res < 0) + exit_error(OTHER_PROBLEM, + "Operation failed: %s", + err2str(errno, CT_DELETE)); + + if (output_mask & _O_XML) + op_type = NFCT_O_XML; + if (output_mask & _O_EXT) + op_flags = NFCT_OF_SHOW_LAYER3; + + nfct_snprintf(buf, 1024, ct, NFCT_T_UNKNOWN, op_type, op_flags); + printf("%s\n", buf); + + delete_counter++; + + return NFCT_CB_CONTINUE; +} + +static int update_counter; + +static int update_cb(enum nf_conntrack_msg_type type, + struct nf_conntrack *ct, + void *data) +{ + int res; + char buf[1024]; + struct nf_conntrack *obj = data; + char __tmp[nfct_maxsize()]; + struct nf_conntrack *tmp = (struct nf_conntrack *) (void *)__tmp; + unsigned int op_type = NFCT_O_DEFAULT; + unsigned int op_flags = 0; + + memcpy(tmp, obj, sizeof(__tmp)); + + if (ignore_nat(tmp, ct)) + return NFCT_CB_CONTINUE; + + if (options & CT_OPT_ORIG && !nfct_cmp(tmp, ct, NFCT_CMP_ORIG)) + return NFCT_CB_CONTINUE; + if (options & CT_OPT_REPL && !nfct_cmp(tmp, ct, NFCT_CMP_REPL)) + return NFCT_CB_CONTINUE; + + nfct_copy(tmp, ct, NFCT_CP_ORIG); + + res = nfct_query(ith, NFCT_Q_UPDATE, tmp); + if (res < 0) + exit_error(OTHER_PROBLEM, + "Operation failed: %s", + err2str(errno, CT_UPDATE)); + + if (output_mask & _O_XML) + op_type = NFCT_O_XML; + if (output_mask & _O_EXT) + op_flags = NFCT_OF_SHOW_LAYER3; + + nfct_snprintf(buf, 1024, ct, NFCT_T_UNKNOWN, op_type, op_flags); + printf("%s\n", buf); + + update_counter++; + return NFCT_CB_CONTINUE; } @@ -665,6 +783,7 @@ static const int cmd2type[][2] = { ['D'] = { CT_DELETE, EXP_DELETE }, ['G'] = { CT_GET, EXP_GET }, ['F'] = { CT_FLUSH, EXP_FLUSH }, + ['E'] = { CT_EVENT, EXP_EVENT }, ['V'] = { CT_VERSION, CT_VERSION }, ['h'] = { CT_HELP, CT_HELP }, }; @@ -714,7 +833,8 @@ int main(int argc, char *argv[]) char __exptuple[nfct_maxsize()]; char __mask[nfct_maxsize()]; struct nf_conntrack *obj = (struct nf_conntrack *)(void*) __obj; - struct nf_conntrack *exptuple = (struct nf_conntrack *)(void*) __exptuple; + struct nf_conntrack *exptuple = + (struct nf_conntrack *)(void*) __exptuple; struct nf_conntrack *mask = (struct nf_conntrack *)(void*) __mask; char __exp[nfexp_maxsize()]; struct nf_expect *exp = (struct nf_expect *)(void*) __exp; @@ -869,15 +989,24 @@ int main(int argc, char *argv[]) options |= CT_OPT_ZERO; break; case 'n': - case 'g': - if (!optarg) - exit_error(PARAMETER_PROBLEM, - "-%c requires an IP", c); + case 'g': { + char *tmp = NULL; options |= opt2type[c]; + + if (optarg) + continue; + else if (optind < argc && argv[optind][0] != '-' + && argv[optind][0] != '!') + tmp = argv[optind++]; + + if (tmp == NULL) + continue; + set_family(&family, AF_INET); - nat_parse(optarg, 1, obj, opt2type[c]); + nat_parse(tmp, 1, obj, opt2type[c]); break; + } case 'm': case 'c': options |= opt2type[c]; @@ -930,7 +1059,7 @@ int main(int argc, char *argv[]) commands_v_options[cmd], optflags); - if (command & (CT_CREATE|CT_UPDATE|CT_DELETE|CT_GET) && + if (command & (CT_CREATE|CT_GET) && !((options & CT_OPT_ORIG_SRC && options & CT_OPT_ORIG_DST) || (options & CT_OPT_REPL_SRC && options & CT_OPT_REPL_DST))) exit_error(PARAMETER_PROBLEM, "missing IP address"); @@ -958,6 +1087,10 @@ int main(int argc, char *argv[]) res = nfct_query(cth, NFCT_Q_DUMP, &family); nfct_close(cth); + + fprintf(stderr, "%s v%s: ", PROGNAME, VERSION); + fprintf(stderr, "%d flow entries has been shown.\n", + list_counter); break; case EXP_LIST: @@ -982,6 +1115,9 @@ int main(int argc, char *argv[]) res = nfct_query(cth, NFCT_Q_CREATE, obj); nfct_close(cth); + fprintf(stderr, "%s v%s: ", PROGNAME, VERSION); + fprintf(stderr, "%d flow entry has been created.\n", + res == -1 ? 0 : 1); break; case EXP_CREATE: @@ -998,29 +1134,38 @@ int main(int argc, char *argv[]) break; case CT_UPDATE: - if ((options & CT_OPT_ORIG) && !(options & CT_OPT_REPL)) - nfct_setobjopt(obj, NFCT_SOPT_SETUP_REPLY); - else if (!(options & CT_OPT_ORIG) && (options & CT_OPT_REPL)) - nfct_setobjopt(obj, NFCT_SOPT_SETUP_ORIGINAL); - cth = nfct_open(CONNTRACK, 0); - if (!cth) + /* internal handler for delete_cb, otherwise we hit EILSEQ */ + ith = nfct_open(CONNTRACK, 0); + if (!cth || !ith) exit_error(OTHER_PROBLEM, "Can't open handler"); - res = nfct_query(cth, NFCT_Q_UPDATE, obj); + nfct_callback_register(cth, NFCT_T_ALL, update_cb, obj); + + res = nfct_query(cth, NFCT_Q_DUMP, &family); + nfct_close(ith); nfct_close(cth); + + fprintf(stderr, "%s v%s: ", PROGNAME, VERSION); + fprintf(stderr, "%d flow entries has been updated.\n", + update_counter); break; case CT_DELETE: - if (!(options & CT_OPT_ORIG) && !(options & CT_OPT_REPL)) - exit_error(PARAMETER_PROBLEM, "Can't kill conntracks " - "just by its ID"); cth = nfct_open(CONNTRACK, 0); - if (!cth) + ith = nfct_open(CONNTRACK, 0); + if (!cth || !ith) exit_error(OTHER_PROBLEM, "Can't open handler"); - res = nfct_query(cth, NFCT_Q_DESTROY, obj); + nfct_callback_register(cth, NFCT_T_ALL, delete_cb, obj); + + res = nfct_query(cth, NFCT_Q_DUMP, &family); + nfct_close(ith); nfct_close(cth); + + fprintf(stderr, "%s v%s: ", PROGNAME, VERSION); + fprintf(stderr, "%d flow entries has been deleted.\n", + delete_counter); break; case EXP_DELETE: @@ -1042,6 +1187,9 @@ int main(int argc, char *argv[]) nfct_callback_register(cth, NFCT_T_ALL, dump_cb, obj); res = nfct_query(cth, NFCT_Q_GET, obj); nfct_close(cth); + fprintf(stderr, "%s v%s: ", PROGNAME, VERSION); + fprintf(stderr, "%d flow entry has been shown.\n", + res == -1 ? 0 : 1); break; case EXP_GET: @@ -1062,6 +1210,8 @@ int main(int argc, char *argv[]) exit_error(OTHER_PROBLEM, "Can't open handler"); res = nfct_query(cth, NFCT_Q_FLUSH, &family); nfct_close(cth); + fprintf(stderr, "%s v%s: ", PROGNAME, VERSION); + fprintf(stderr,"connection tracking table has been emptied.\n"); break; case EXP_FLUSH: @@ -1081,6 +1231,7 @@ int main(int argc, char *argv[]) if (!cth) exit_error(OTHER_PROBLEM, "Can't open handler"); signal(SIGINT, event_sighandler); + signal(SIGTERM, event_sighandler); nfct_callback_register(cth, NFCT_T_ALL, event_cb, obj); res = nfct_catch(cth); nfct_close(cth); @@ -1091,6 +1242,7 @@ int main(int argc, char *argv[]) if (!cth) exit_error(OTHER_PROBLEM, "Can't open handler"); signal(SIGINT, event_sighandler); + signal(SIGTERM, event_sighandler); nfexp_callback_register(cth, NFCT_T_ALL, dump_exp_cb, NULL); res = nfexp_catch(cth); nfct_close(cth); @@ -1115,10 +1267,9 @@ int main(int argc, char *argv[]) global_option_offset = 0; } - if (res < 0) { - fprintf(stderr, "Operation failed: %s\n", err2str(errno, command)); - exit(OTHER_PROBLEM); - } + if (res < 0) + exit_error(OTHER_PROBLEM, "Operation failed: %s", + err2str(errno, command)); return 0; } -- cgit v1.2.3 From ebb9a1aa3813d71b99d7508c88b9cbf525e15b4a Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Sun, 13 Apr 2008 21:59:46 +0000 Subject: fix conntrack -U -p tcp [...] --- extensions/libct_proto_icmp.c | 9 +++++++++ extensions/libct_proto_icmpv6.c | 9 +++++++++ extensions/libct_proto_tcp.c | 20 ++++++++++++++++++++ extensions/libct_proto_udp.c | 20 ++++++++++++++++++++ include/conntrack.h | 3 +++ src/conntrack.c | 17 +++++++---------- 6 files changed, 68 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/extensions/libct_proto_icmp.c b/extensions/libct_proto_icmp.c index f81c3b4..62ad00f 100644 --- a/extensions/libct_proto_icmp.c +++ b/extensions/libct_proto_icmp.c @@ -74,6 +74,9 @@ static int parse(char c, nfct_set_attr_u8(ct, ATTR_ICMP_TYPE, atoi(optarg)); + + nfct_set_attr_u8(ct, ATTR_L4PROTO, IPPROTO_ICMP); + *flags |= ICMP_TYPE; break; case '2': @@ -83,6 +86,9 @@ static int parse(char c, nfct_set_attr_u8(ct, ATTR_ICMP_CODE, atoi(optarg)); + + nfct_set_attr_u8(ct, ATTR_L4PROTO, IPPROTO_ICMP); + *flags |= ICMP_CODE; break; case '3': @@ -92,6 +98,9 @@ static int parse(char c, nfct_set_attr_u16(ct, ATTR_ICMP_ID, htons(atoi(optarg))); + + nfct_set_attr_u8(ct, ATTR_L4PROTO, IPPROTO_ICMP); + *flags |= ICMP_ID; break; } diff --git a/extensions/libct_proto_icmpv6.c b/extensions/libct_proto_icmpv6.c index 6c1c358..5346b59 100644 --- a/extensions/libct_proto_icmpv6.c +++ b/extensions/libct_proto_icmpv6.c @@ -77,6 +77,9 @@ static int parse(char c, nfct_set_attr_u8(ct, ATTR_ICMP_TYPE, atoi(optarg)); + + nfct_set_attr_u8(ct, ATTR_L4PROTO, IPPROTO_ICMPV6); + *flags |= ICMP_TYPE; break; @@ -87,6 +90,9 @@ static int parse(char c, nfct_set_attr_u8(ct, ATTR_ICMP_CODE, atoi(optarg)); + + nfct_set_attr_u8(ct, ATTR_L4PROTO, IPPROTO_ICMPV6); + *flags |= ICMP_CODE; break; @@ -97,6 +103,9 @@ static int parse(char c, nfct_set_attr_u16(ct, ATTR_ICMP_ID, htons(atoi(optarg))); + + nfct_set_attr_u8(ct, ATTR_L4PROTO, IPPROTO_ICMPV6); + *flags |= ICMP_ID; break; } diff --git a/extensions/libct_proto_tcp.c b/extensions/libct_proto_tcp.c index dc48d09..0246758 100644 --- a/extensions/libct_proto_tcp.c +++ b/extensions/libct_proto_tcp.c @@ -103,6 +103,8 @@ static int parse_options(char c, ATTR_ORIG_PORT_SRC, htons(atoi(optarg))); + nfct_set_attr_u8(ct, ATTR_ORIG_L4PROTO, IPPROTO_TCP); + *flags |= TCP_ORIG_SPORT; break; case '2': @@ -113,6 +115,8 @@ static int parse_options(char c, ATTR_ORIG_PORT_DST, htons(atoi(optarg))); + nfct_set_attr_u8(ct, ATTR_ORIG_L4PROTO, IPPROTO_TCP); + *flags |= TCP_ORIG_DPORT; break; case '3': @@ -123,6 +127,8 @@ static int parse_options(char c, ATTR_REPL_PORT_SRC, htons(atoi(optarg))); + nfct_set_attr_u8(ct, ATTR_REPL_L4PROTO, IPPROTO_TCP); + *flags |= TCP_REPL_SPORT; break; case '4': @@ -133,6 +139,8 @@ static int parse_options(char c, ATTR_REPL_PORT_DST, htons(atoi(optarg))); + nfct_set_attr_u8(ct, ATTR_REPL_L4PROTO, IPPROTO_TCP); + *flags |= TCP_REPL_DPORT; break; case '5': @@ -143,6 +151,8 @@ static int parse_options(char c, ATTR_ORIG_PORT_SRC, htons(atoi(optarg))); + nfct_set_attr_u8(mask, ATTR_ORIG_L4PROTO, IPPROTO_TCP); + *flags |= TCP_MASK_SPORT; break; case '6': @@ -153,6 +163,8 @@ static int parse_options(char c, ATTR_ORIG_PORT_DST, htons(atoi(optarg))); + nfct_set_attr_u8(mask, ATTR_ORIG_L4PROTO, IPPROTO_TCP); + *flags |= TCP_MASK_DPORT; break; case '7': @@ -180,6 +192,10 @@ static int parse_options(char c, ATTR_ORIG_PORT_SRC, htons(atoi(optarg))); + nfct_set_attr_u8(exptuple, + ATTR_ORIG_L4PROTO, + IPPROTO_TCP); + *flags |= TCP_EXPTUPLE_SPORT; break; case '9': @@ -190,6 +206,10 @@ static int parse_options(char c, ATTR_ORIG_PORT_DST, htons(atoi(optarg))); + nfct_set_attr_u8(exptuple, + ATTR_ORIG_L4PROTO, + IPPROTO_TCP); + *flags |= TCP_EXPTUPLE_DPORT; break; } diff --git a/extensions/libct_proto_udp.c b/extensions/libct_proto_udp.c index d74def5..f9793d0 100644 --- a/extensions/libct_proto_udp.c +++ b/extensions/libct_proto_udp.c @@ -85,6 +85,8 @@ static int parse_options(char c, ATTR_ORIG_PORT_SRC, htons(atoi(optarg))); + nfct_set_attr_u8(ct, ATTR_ORIG_L4PROTO, IPPROTO_UDP); + *flags |= UDP_ORIG_SPORT; break; case '2': @@ -95,6 +97,8 @@ static int parse_options(char c, ATTR_ORIG_PORT_DST, htons(atoi(optarg))); + nfct_set_attr_u8(ct, ATTR_ORIG_L4PROTO, IPPROTO_UDP); + *flags |= UDP_ORIG_DPORT; break; case '3': @@ -105,6 +109,8 @@ static int parse_options(char c, ATTR_REPL_PORT_SRC, htons(atoi(optarg))); + nfct_set_attr_u8(ct, ATTR_REPL_L4PROTO, IPPROTO_UDP); + *flags |= UDP_REPL_SPORT; break; case '4': @@ -115,6 +121,8 @@ static int parse_options(char c, ATTR_REPL_PORT_DST, htons(atoi(optarg))); + nfct_set_attr_u8(ct, ATTR_REPL_L4PROTO, IPPROTO_UDP); + *flags |= UDP_REPL_DPORT; break; case '5': @@ -125,6 +133,8 @@ static int parse_options(char c, ATTR_ORIG_PORT_SRC, htons(atoi(optarg))); + nfct_set_attr_u8(mask, ATTR_ORIG_L4PROTO, IPPROTO_UDP); + *flags |= UDP_MASK_SPORT; break; case '6': @@ -135,6 +145,8 @@ static int parse_options(char c, ATTR_ORIG_PORT_DST, htons(atoi(optarg))); + nfct_set_attr_u8(mask, ATTR_ORIG_L4PROTO, IPPROTO_UDP); + *flags |= UDP_MASK_DPORT; break; case '7': @@ -145,6 +157,10 @@ static int parse_options(char c, ATTR_ORIG_PORT_SRC, htons(atoi(optarg))); + nfct_set_attr_u8(exptuple, + ATTR_ORIG_L4PROTO, + IPPROTO_UDP); + *flags |= UDP_EXPTUPLE_SPORT; break; case '8': @@ -155,6 +171,10 @@ static int parse_options(char c, ATTR_ORIG_PORT_DST, htons(atoi(optarg))); + nfct_set_attr_u8(exptuple, + ATTR_ORIG_L4PROTO, + IPPROTO_UDP); + *flags |= UDP_EXPTUPLE_DPORT; break; } diff --git a/include/conntrack.h b/include/conntrack.h index 36897c2..9e005d9 100644 --- a/include/conntrack.h +++ b/include/conntrack.h @@ -82,6 +82,9 @@ enum options { CT_OPT_PROTO_BIT = 4, CT_OPT_PROTO = (1 << CT_OPT_PROTO_BIT), + CT_OPT_TUPLE_ORIG = (CT_OPT_ORIG | CT_OPT_PROTO), + CT_OPT_TUPLE_REPL = (CT_OPT_REPL | CT_OPT_PROTO), + CT_OPT_TIMEOUT_BIT = 5, CT_OPT_TIMEOUT = (1 << CT_OPT_TIMEOUT_BIT), diff --git a/src/conntrack.c b/src/conntrack.c index f4dfec7..2dfb601 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -737,9 +737,9 @@ static int update_cb(enum nf_conntrack_msg_type type, if (ignore_nat(tmp, ct)) return NFCT_CB_CONTINUE; - if (options & CT_OPT_ORIG && !nfct_cmp(tmp, ct, NFCT_CMP_ORIG)) + if (options & CT_OPT_TUPLE_ORIG && !nfct_cmp(tmp, ct, NFCT_CMP_ORIG)) return NFCT_CB_CONTINUE; - if (options & CT_OPT_REPL && !nfct_cmp(tmp, ct, NFCT_CMP_REPL)) + if (options & CT_OPT_TUPLE_REPL && !nfct_cmp(tmp, ct, NFCT_CMP_REPL)) return NFCT_CB_CONTINUE; nfct_copy(tmp, ct, NFCT_CP_ORIG); @@ -935,14 +935,6 @@ int main(int argc, char *argv[]) "`%s' unsupported protocol", optarg); - nfct_set_attr_u8(obj, ATTR_ORIG_L4PROTO, h->protonum); - nfct_set_attr_u8(obj, ATTR_REPL_L4PROTO, h->protonum); - nfct_set_attr_u8(exptuple, - ATTR_ORIG_L4PROTO, - h->protonum); - nfct_set_attr_u8(mask, - ATTR_ORIG_L4PROTO, - h->protonum); opts = merge_options(opts, h->opts, &h->option_offset); if (opts == NULL) exit_error(OTHER_PROBLEM, "out of memory"); @@ -1052,6 +1044,11 @@ int main(int argc, char *argv[]) if (family == AF_UNSPEC) family = AF_INET; + /* set the protocol number if we have seen -p with no parameters */ + if (h && !nfct_attr_is_set(obj, ATTR_ORIG_L4PROTO) && + !nfct_attr_is_set(obj, ATTR_REPL_L4PROTO)) + nfct_set_attr_u8(obj, ATTR_L4PROTO, h->protonum); + cmd = bit2cmd(command); generic_cmd_check(cmd, options); generic_opt_check(options, -- cgit v1.2.3 From 953bcf62fbd110f63c946905f9642d17b63c50cf Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Wed, 16 Apr 2008 14:54:24 +0000 Subject: o fix NAT filtering via --src-nat and --dst-nat (reported by K.Oledzki) o recover the ID support o show display counters to stderr o enable filtering by status and ID --- ChangeLog | 3 ++ configure.in | 2 +- conntrack.8 | 27 +++++++++------ include/conntrack.h | 12 +++---- qa/test-conntrack.c | 18 +++++++--- qa/testsuite/00create | 4 +++ qa/testsuite/01delete | 8 +++-- qa/testsuite/02filter | 20 +++++++++++ src/conntrack.c | 92 +++++++++++++++++++++++++++++---------------------- 9 files changed, 120 insertions(+), 66 deletions(-) create mode 100644 qa/testsuite/02filter (limited to 'src') diff --git a/ChangeLog b/ChangeLog index f15849b..d6fbe30 100644 --- a/ChangeLog +++ b/ChangeLog @@ -14,7 +14,10 @@ o simplify parameter-handling code o check for missing source/address IP/ports in creation and get operations o way more flexible conntrack updates and deletions o fix NAT filtering via --src-nat and --dst-nat (reported by K.Oledzki) +o recover the ID support o show display counters to stderr +o enable filtering by status and ID +o update manpage o minor cleanups = conntrackd = diff --git a/configure.in b/configure.in index 46dd7b8..17101e9 100644 --- a/configure.in +++ b/configure.in @@ -18,7 +18,7 @@ esac dnl Dependencies LIBNFNETLINK_REQUIRED=0.0.32 -LIBNETFILTER_CONNTRACK_REQUIRED=0.0.91 +LIBNETFILTER_CONNTRACK_REQUIRED=0.0.92 AC_CHECK_PROG(HAVE_PKG_CONFIG, pkg-config, yes) if test "x$HAVE_PKG_CONFIG" = "x" diff --git a/conntrack.8 b/conntrack.8 index 670770a..9fb9508 100644 --- a/conntrack.8 +++ b/conntrack.8 @@ -73,9 +73,8 @@ Flush the whole given table Atomically zero counters after reading them. This option is only valid in combination with the "-L, --dump" command options. .TP -.BI "-o, --output [extended,xml,timestamp] " -Display output in a certain format. This option is only valid in combination -with the "-L, --dump", "-E, --event" and "-G, --get" command options. +.BI "-o, --output [extended,xml,timestamp,id] " +Display output in a certain format. .TP .BI "-e, --event-mask " "[ALL|NEW|UPDATES|DESTROY][,...]" Set the bitmask of events that are to be generated by the in-kernel ctnetlink @@ -136,10 +135,10 @@ Specify the destination address mask of an expectation. .TP TCP-specific fields: .TP -.BI "--orig-port-src " "PORT" +.BI "--sport, --orig-port-src " "PORT" Source port in original direction .TP -.BI "--orig-port-dst " "PORT" +.BI "--dport, --orig-port-dst " "PORT" Destination port in original direction .TP .BI "--reply-port-src " "PORT" @@ -153,10 +152,10 @@ TCP state .TP UDP-specific fields: .TP -.BI "--orig-port-src " "PORT" +.BI "--sport, --orig-port-src " "PORT" Source port in original direction .TP -.BI "--orig-port-dst " "PORT" +.BI "--dport, --orig-port-dst " "PORT" Destination port in original direction .TP .BI "--reply-port-src " "PORT" @@ -182,22 +181,28 @@ cause an exit code of 1. .SH EXAMPLES .TP .B conntrack \-L -Dump the connection tracking table in /proc/net/ip_conntrack format +Show the connection tracking table in /proc/net/ip_conntrack format .TP .B conntrack \-L -o extended -Dump the connection tracking table in /proc/net/nf_conntrack format +Show the connection tracking table in /proc/net/nf_conntrack format .TP .B conntrack \-L \-o xml -Dump the connection tracking table in XML +Show the connection tracking table in XML .TP .B conntrack \-L -f ipv6 -o extended Only dump IPv6 connections in /proc/net/nf_conntrack format .TP .B conntrack \-L --src-nat -Dump source NAT connections +Show source NAT connections .TP .B conntrack \-E \-o timestamp Show connection events together with the timestamp +.TP +.B conntrack \-D \-s 1.2.3.4 +Delete all flow whose source address is 1.2.3.4 +.TP +.B conntrack \-U \-s 1.2.3.4 \-m 1 +Set connmark to 1 of all the flows whose source address is 1.2.3.4 .SH BUGS Bugs? What's this ;-) .SH SEE ALSO diff --git a/include/conntrack.h b/include/conntrack.h index 9e005d9..2e17475 100644 --- a/include/conntrack.h +++ b/include/conntrack.h @@ -138,14 +138,10 @@ enum options { #define NUMBER_OF_OPT CT_OPT_MAX+1 enum { - _O_XML_BIT = 0, - _O_XML = (1 << _O_XML_BIT), - - _O_EXT_BIT = 1, - _O_EXT = (1 << _O_EXT_BIT), - - _O_TMS_BIT = 2, - _O_TMS = (1 << _O_TMS_BIT), + _O_XML = (1 << 0), + _O_EXT = (1 << 1), + _O_TMS = (1 << 2), + _O_ID = (1 << 3), }; struct ctproto_handler { diff --git a/qa/test-conntrack.c b/qa/test-conntrack.c index c58aa8d..c9097b6 100644 --- a/qa/test-conntrack.c +++ b/qa/test-conntrack.c @@ -21,7 +21,7 @@ int main() { - int ret, ok = 0, bad = 0; + int ret, ok = 0, bad = 0, line; FILE *fp; DIR *d; char buf[1024]; @@ -34,6 +34,8 @@ int main() sprintf(file, "testsuite/%s", dent->d_name); + line = 0; + fp = fopen(file, "r"); if (fp == NULL) { perror("cannot find testsuite file"); @@ -44,15 +46,22 @@ int main() char tmp[1024] = CT_PROG, *res; tmp[strlen(CT_PROG)] = ' '; + line++; + if (buf[0] == '#' || buf[0] == ' ') continue; res = strchr(buf, ';'); + if (!res) { + printf("malformed file %s at line %d\n", + dent->d_name, line); + exit(EXIT_FAILURE); + } *res = '\0'; res+=2; strcpy(tmp + strlen(CT_PROG) + 1, buf); - printf("Executing: %s\n", tmp); + printf("(%d) Executing: %s\n", line, tmp); ret = system(tmp); @@ -75,10 +84,11 @@ int main() printf("^----- BAD\n"); } } + printf("=====\n"); } + fclose(fp); } + closedir(d); fprintf(stdout, "OK: %d BAD: %d\n", ok, bad); - - fclose(fp); } diff --git a/qa/testsuite/00create b/qa/testsuite/00create index 7af7d37..40e2c19 100644 --- a/qa/testsuite/00create +++ b/qa/testsuite/00create @@ -12,5 +12,9 @@ -I -s 1.1.1.1 -d 2.2.2.2 -p tcp --sport 10 --dport 20 --state LISTEN -u SEEN_REPLY -t 50 ; OK # create again -I -s 1.1.1.1 -d 2.2.2.2 -p tcp --sport 10 --dport 20 --state LISTEN -u SEEN_REPLY -t 50 ; BAD +# delete +-D -s 1.1.1.1 -d 2.2.2.2 -p tcp --sport 10 --dport 20 ; OK # create from reply -I -r 2.2.2.2 -q 1.1.1.1 -p tcp --reply-port-src 11 --reply-port-dst 21 --state LISTEN -u SEEN_REPLY -t 50 ; OK +# delete reverse +-D -r 2.2.2.2 -q 1.1.1.1 -p tcp --reply-port-src 11 --reply-port-dst 21 ; OK diff --git a/qa/testsuite/01delete b/qa/testsuite/01delete index dd3ca8b..3c38ac5 100644 --- a/qa/testsuite/01delete +++ b/qa/testsuite/01delete @@ -1,2 +1,6 @@ -# delete --D -s 1.1.1.1 -d 2.2.2.2 -p tcp --sport 10 --dport 20 ; OK +# create dummy +-I -s 1.1.1.1 -d 2.2.2.2 -p tcp --sport 10 --dport 20 --state LISTEN -u SEEN_REPLY -t 50 ; OK +# delete bad source +-D -s 2.2.2.2 -p tcp --sport 10 --dport 20 ; BAD +# delete by source +-D -s 1.1.1.1 ; OK diff --git a/qa/testsuite/02filter b/qa/testsuite/02filter new file mode 100644 index 0000000..1ae9abd --- /dev/null +++ b/qa/testsuite/02filter @@ -0,0 +1,20 @@ +# create dummy +conntrack -I -s 1.1.1.1 -d 2.2.2.2 -p tcp --sport 10 --dport 20 --state LISTEN -u SEEN_REPLY -t 50 ; OK +# filter by source +conntrack -L -s 1.1.1.1 ; OK +# filter by destination +conntrack -L -d 2.2.2.2 ; OK +# filter by protocol +conntrack -L -p tcp ; OK +# filter by status +conntrack -L -u SEEN_REPLY ; OK +# filter by TCP protocol state +conntrack -L -p tcp --state LISTEN ; OK +# update mark of dummy conntrack +conntrack -U -s 1.1.1.1 -m 1 ; OK +# filter by mark +conntrack -L -m 1 ; OK +# filter by layer 3 protocol +conntrack -L -f ipv4 ; OK +# delete dummy +conntrack -D -d 2.2.2.2 ; OK diff --git a/src/conntrack.c b/src/conntrack.c index 2dfb601..9ab4558 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -121,7 +121,7 @@ static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = /* Well, it's better than "Re: Linux vs FreeBSD" */ { /* s d r q p t u z e [ ] { } a m i f n g o c */ -/*CT_LIST*/ {2,2,2,2,2,0,0,2,0,0,0,0,0,0,2,2,2,2,2,2,2}, +/*CT_LIST*/ {2,2,2,2,2,0,2,2,0,0,0,0,0,0,2,0,2,2,2,2,2}, /*CT_CREATE*/ {2,2,2,2,1,1,1,0,0,0,0,0,0,2,2,0,0,2,2,0,2}, /*CT_UPDATE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,2}, /*CT_DELETE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,2}, @@ -130,7 +130,7 @@ static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = /*CT_EVENT*/ {2,2,2,2,2,0,0,0,2,0,0,0,0,0,2,0,0,2,2,2,2}, /*VERSION*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, /*HELP*/ {0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*EXP_LIST*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,0,0,0,0}, +/*EXP_LIST*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0}, /*EXP_CREATE*/{1,1,2,2,1,1,2,0,0,1,1,1,1,0,0,0,0,0,0,0,0}, /*EXP_DELETE*/{1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, /*EXP_GET*/ {1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, @@ -143,7 +143,7 @@ static LIST_HEAD(proto_list); static unsigned int options; #define CT_COMPARISON (CT_OPT_PROTO | CT_OPT_ORIG | CT_OPT_REPL | CT_OPT_MARK |\ - CT_OPT_SECMARK) + CT_OPT_SECMARK | CT_OPT_STATUS | CT_OPT_ID) void register_proto(struct ctproto_handler *h) { @@ -328,8 +328,8 @@ static struct parse_parameter { { {"ALL", "NEW", "UPDATES", "DESTROY"}, 4, {~0U, NF_NETLINK_CONNTRACK_NEW, NF_NETLINK_CONNTRACK_UPDATE, NF_NETLINK_CONNTRACK_DESTROY} }, - { {"xml", "extended", "timestamp" }, 3, - { _O_XML, _O_EXT, _O_TMS }, + { {"xml", "extended", "timestamp", "id" }, 4, + { _O_XML, _O_EXT, _O_TMS, _O_ID }, }, }; @@ -603,13 +603,13 @@ static int ignore_nat(const struct nf_conntrack *obj, return 0; } -static int events_counter; +static int counter; static void __attribute__((noreturn)) event_sighandler(int s) { fprintf(stderr, "%s v%s: ", PROGNAME, VERSION); - fprintf(stderr, "%d flow events has been shown.\n", events_counter); + fprintf(stderr, "%d flow events has been shown.\n", counter); nfct_close(cth); exit(0); } @@ -640,19 +640,19 @@ static int event_cb(enum nf_conntrack_msg_type type, printf("[%-8ld.%-6ld]\t", tv.tv_sec, tv.tv_usec); } else op_flags |= NFCT_OF_TIME; - } + } + if (output_mask & _O_ID) + op_flags |= NFCT_OF_ID; nfct_snprintf(buf, 1024, ct, type, op_type, op_flags); printf("%s\n", buf); fflush(stdout); - events_counter++; + counter++; return NFCT_CB_CONTINUE; } -static int list_counter; - static int dump_cb(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data) @@ -672,17 +672,17 @@ static int dump_cb(enum nf_conntrack_msg_type type, op_type = NFCT_O_XML; if (output_mask & _O_EXT) op_flags = NFCT_OF_SHOW_LAYER3; + if (output_mask & _O_ID) + op_flags |= NFCT_OF_ID; nfct_snprintf(buf, 1024, ct, NFCT_T_UNKNOWN, op_type, op_flags); printf("%s\n", buf); - list_counter++; + counter++; return NFCT_CB_CONTINUE; } -static int delete_counter; - static int delete_cb(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data) @@ -709,17 +709,17 @@ static int delete_cb(enum nf_conntrack_msg_type type, op_type = NFCT_O_XML; if (output_mask & _O_EXT) op_flags = NFCT_OF_SHOW_LAYER3; + if (output_mask & _O_ID) + op_flags |= NFCT_OF_ID; nfct_snprintf(buf, 1024, ct, NFCT_T_UNKNOWN, op_type, op_flags); printf("%s\n", buf); - delete_counter++; + counter++; return NFCT_CB_CONTINUE; } -static int update_counter; - static int update_cb(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data) @@ -737,6 +737,10 @@ static int update_cb(enum nf_conntrack_msg_type type, if (ignore_nat(tmp, ct)) return NFCT_CB_CONTINUE; + if (nfct_attr_is_set(obj, ATTR_ID) && nfct_attr_is_set(ct, ATTR_ID) && + nfct_get_attr_u32(obj, ATTR_ID) != nfct_get_attr_u32(ct, ATTR_ID)) + return NFCT_CB_CONTINUE; + if (options & CT_OPT_TUPLE_ORIG && !nfct_cmp(tmp, ct, NFCT_CMP_ORIG)) return NFCT_CB_CONTINUE; if (options & CT_OPT_TUPLE_REPL && !nfct_cmp(tmp, ct, NFCT_CMP_REPL)) @@ -754,11 +758,13 @@ static int update_cb(enum nf_conntrack_msg_type type, op_type = NFCT_O_XML; if (output_mask & _O_EXT) op_flags = NFCT_OF_SHOW_LAYER3; + if (output_mask & _O_ID) + op_flags |= NFCT_OF_ID; nfct_snprintf(buf, 1024, ct, NFCT_T_UNKNOWN, op_type, op_flags); printf("%s\n", buf); - update_counter++; + counter++; return NFCT_CB_CONTINUE; } @@ -801,6 +807,7 @@ static const int opt2type[] = { ['g'] = CT_OPT_DST_NAT, ['m'] = CT_OPT_MARK, ['c'] = CT_OPT_SECMARK, + ['i'] = CT_OPT_ID, }; static const int opt2family_attr[][2] = { @@ -821,6 +828,18 @@ static const int opt2attr[] = { ['q'] = ATTR_REPL_L3PROTO, ['m'] = ATTR_MARK, ['c'] = ATTR_SECMARK, + ['i'] = ATTR_ID, +}; + +static char exit_msg[][64] = { + [CT_LIST_BIT] = "%d flow entries has been shown.\n", + [CT_CREATE_BIT] = "%d flow entries has been created.\n", + [CT_UPDATE_BIT] = "%d flow entries has been updated.\n", + [CT_DELETE_BIT] = "%d flow entries has been deleted.\n", + [CT_GET_BIT] = "%d flow entries has been shown.\n", + [CT_EVENT_BIT] = "%d flow events has been shown.\n", + [EXP_LIST_BIT] = "%d expectations has been shown.\n", + [EXP_DELETE_BIT] = "%d expectations has been shown.\n", }; int main(int argc, char *argv[]) @@ -853,7 +872,7 @@ int main(int argc, char *argv[]) register_icmpv6(); while ((c = getopt_long(argc, argv, "L::I::U::D::G::E::F::hVs:d:r:q:" - "p:t:u:e:a:z[:]:{:}:m:i::f:o:n::" + "p:t:u:e:a:z[:]:{:}:m:i:f:o:n::" "g::c:", opts, NULL)) != -1) { switch(c) { @@ -999,6 +1018,7 @@ int main(int argc, char *argv[]) nat_parse(tmp, 1, obj, opt2type[c]); break; } + case 'i': case 'm': case 'c': options |= opt2type[c]; @@ -1006,9 +1026,10 @@ int main(int argc, char *argv[]) exit_error(PARAMETER_PROBLEM, "-%c requires value", c); - nfct_set_attr_u32(obj, opt2attr[c], atol(optarg)); + nfct_set_attr_u32(obj, + opt2attr[c], + strtoul(optarg, NULL, 0)); break; - case 'i': case 'a': fprintf(stderr, "WARNING: ignoring -%c, " "deprecated option.\n", c); @@ -1084,10 +1105,6 @@ int main(int argc, char *argv[]) res = nfct_query(cth, NFCT_Q_DUMP, &family); nfct_close(cth); - - fprintf(stderr, "%s v%s: ", PROGNAME, VERSION); - fprintf(stderr, "%d flow entries has been shown.\n", - list_counter); break; case EXP_LIST: @@ -1111,10 +1128,9 @@ int main(int argc, char *argv[]) exit_error(OTHER_PROBLEM, "Can't open handler"); res = nfct_query(cth, NFCT_Q_CREATE, obj); + if (res != -1) + counter++; nfct_close(cth); - fprintf(stderr, "%s v%s: ", PROGNAME, VERSION); - fprintf(stderr, "%d flow entry has been created.\n", - res == -1 ? 0 : 1); break; case EXP_CREATE: @@ -1142,10 +1158,6 @@ int main(int argc, char *argv[]) res = nfct_query(cth, NFCT_Q_DUMP, &family); nfct_close(ith); nfct_close(cth); - - fprintf(stderr, "%s v%s: ", PROGNAME, VERSION); - fprintf(stderr, "%d flow entries has been updated.\n", - update_counter); break; case CT_DELETE: @@ -1159,10 +1171,6 @@ int main(int argc, char *argv[]) res = nfct_query(cth, NFCT_Q_DUMP, &family); nfct_close(ith); nfct_close(cth); - - fprintf(stderr, "%s v%s: ", PROGNAME, VERSION); - fprintf(stderr, "%d flow entries has been deleted.\n", - delete_counter); break; case EXP_DELETE: @@ -1184,9 +1192,6 @@ int main(int argc, char *argv[]) nfct_callback_register(cth, NFCT_T_ALL, dump_cb, obj); res = nfct_query(cth, NFCT_Q_GET, obj); nfct_close(cth); - fprintf(stderr, "%s v%s: ", PROGNAME, VERSION); - fprintf(stderr, "%d flow entry has been shown.\n", - res == -1 ? 0 : 1); break; case EXP_GET: @@ -1268,5 +1273,12 @@ int main(int argc, char *argv[]) exit_error(OTHER_PROBLEM, "Operation failed: %s", err2str(errno, command)); - return 0; + if (exit_msg[cmd][0]) { + fprintf(stderr, "%s v%s: ", PROGNAME, VERSION); + fprintf(stderr, exit_msg[cmd], counter); + if (counter == 0 && !(command & (CT_LIST | EXP_LIST))) + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; } -- cgit v1.2.3 From 07a3a6fe92c98e251a464a5744421ce211030003 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Wed, 16 Apr 2008 15:37:39 +0000 Subject: add more verbose error notification when the injection of a conntrack fails --- ChangeLog | 1 + include/log.h | 2 +- src/cache_iterators.c | 2 ++ src/cache_wt.c | 13 ++++++++++--- src/log.c | 28 ++++++++++++++++++++-------- src/stats-mode.c | 2 +- 6 files changed, 35 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index d6fbe30..045988a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -23,6 +23,7 @@ o minor cleanups = conntrackd = o fix asymmetric path support (reported by Gary Richards) o improve netlink overrun handling +o add more verbose error notification when we fail to inject a conntrack version 0.9.6 (2008/03/08) ------------------------------ diff --git a/include/log.h b/include/log.h index b258633..f5c5b4f 100644 --- a/include/log.h +++ b/include/log.h @@ -7,7 +7,7 @@ struct nf_conntrack; int init_log(void); void dlog(int priority, const char *format, ...); -void dlog_ct(struct nf_conntrack *ct); +void dlog_ct(FILE *fd, struct nf_conntrack *ct, unsigned int type); void close_log(void); #endif diff --git a/src/cache_iterators.c b/src/cache_iterators.c index 92b7b7f..c26d349 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -98,6 +98,8 @@ static int do_commit(void *data1, void *data2) c->commit_exist++; break; default: + dlog(LOG_ERR, "commit: %s", strerror(errno)); + dlog_ct(STATE(log), u->ct, NFCT_O_PLAIN); c->commit_fail++; break; } diff --git a/src/cache_wt.c b/src/cache_wt.c index 65eb3fe..65a1fc4 100644 --- a/src/cache_wt.c +++ b/src/cache_wt.c @@ -35,16 +35,21 @@ static void add_wt(struct us_conntrack *u) switch (ret) { case -1: dlog(LOG_ERR, "cache_wt problem: %s", strerror(errno)); + dlog_ct(STATE(log), u->ct, NFCT_O_PLAIN); break; case 0: memcpy(ct, u->ct, nfct_maxsize()); - if (nl_create_conntrack(ct) == -1) + if (nl_create_conntrack(ct) == -1) { dlog(LOG_ERR, "cache_wt create: %s", strerror(errno)); + dlog_ct(STATE(log), u->ct, NFCT_O_PLAIN); + } break; case 1: memcpy(ct, u->ct, nfct_maxsize()); - if (nl_update_conntrack(ct) == -1) + if (nl_update_conntrack(ct) == -1) { dlog(LOG_ERR, "cache_wt crt-upd: %s", strerror(errno)); + dlog_ct(STATE(log), u->ct, NFCT_O_PLAIN); + } break; } } @@ -56,8 +61,10 @@ static void upd_wt(struct us_conntrack *u) memcpy(ct, u->ct, nfct_maxsize()); - if (nl_update_conntrack(ct) == -1) + if (nl_update_conntrack(ct) == -1) { dlog(LOG_ERR, "cache_wt update:%s", strerror(errno)); + dlog_ct(STATE(log), u->ct, NFCT_O_PLAIN); + } } static void writethrough_add(struct us_conntrack *u, void *data) diff --git a/src/log.c b/src/log.c index 51e757f..d97a69f 100644 --- a/src/log.c +++ b/src/log.c @@ -104,18 +104,30 @@ void dlog(int priority, const char *format, ...) } } -void dlog_ct(struct nf_conntrack *ct) +void dlog_ct(FILE *fd, struct nf_conntrack *ct, unsigned int type) { - FILE *fd = STATE(stats_log); time_t t; char buf[1024]; char *tmp; - - t = time(NULL); - ctime_r(&t, buf); - tmp = buf + strlen(buf); - buf[strlen(buf)-1]='\t'; - nfct_snprintf(buf+strlen(buf), 1024-strlen(buf), ct, 0, 0, 0); + unsigned int flags = 0; + + buf[0]='\0'; + + switch(type) { + case NFCT_O_PLAIN: + t = time(NULL); + ctime_r(&t, buf); + tmp = buf + strlen(buf); + buf[strlen(buf)-1]='\t'; + break; + case NFCT_O_XML: + tmp = buf; + flags |= NFCT_OF_TIME; + break; + default: + return; + } + nfct_snprintf(buf+strlen(buf), 1024-strlen(buf), ct, 0, type, flags); if (fd) { snprintf(buf+strlen(buf), 1024-strlen(buf), "\n"); diff --git a/src/stats-mode.c b/src/stats-mode.c index 3773feb..5808320 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -170,7 +170,7 @@ static int event_destroy_stats(struct nf_conntrack *ct) if (cache_del(STATE_STATS(cache), ct)) { debug_ct(ct, "cache destroy"); - dlog_ct(ct); + dlog_ct(STATE(stats_log), ct, NFCT_O_PLAIN); return 1; } else { debug_ct(ct, "can't destroy!"); -- cgit v1.2.3 From 96213d5f0821aee2fe52459ab2cd54569e50cf85 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Sat, 26 Apr 2008 16:07:00 +0000 Subject: rework of the FT-FW approach --- ChangeLog | 1 + include/network.h | 38 +++++---- src/network.c | 43 ++++++---- src/queue.c | 2 +- src/sync-ftfw.c | 237 ++++++++++++++++++++++++++++++++++++++++++------------ src/sync-mode.c | 46 +++++------ 6 files changed, 257 insertions(+), 110 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 045988a..db11bf3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -24,6 +24,7 @@ o minor cleanups o fix asymmetric path support (reported by Gary Richards) o improve netlink overrun handling o add more verbose error notification when we fail to inject a conntrack +o rework of the FT-FW approach version 0.9.6 (2008/03/08) ------------------------------ diff --git a/include/network.h b/include/network.h index e4ebec4..0fa7b71 100644 --- a/include/network.h +++ b/include/network.h @@ -26,20 +26,18 @@ struct nethdr_ack { #define NETHDR_ACK_SIZ sizeof(struct nethdr_ack) enum { - NET_F_HELLO_BIT = 0, - NET_F_HELLO = (1 << NET_F_HELLO_BIT), - - NET_F_RESYNC_BIT = 1, - NET_F_RESYNC = (1 << NET_F_RESYNC_BIT), - - NET_F_NACK_BIT = 2, - NET_F_NACK = (1 << NET_F_NACK_BIT), - - NET_F_ACK_BIT = 3, - NET_F_ACK = (1 << NET_F_ACK_BIT), + NET_F_UNUSED = (1 << 0), + NET_F_RESYNC = (1 << 1), + NET_F_NACK = (1 << 2), + NET_F_ACK = (1 << 3), + NET_F_ALIVE = (1 << 4), +}; - NET_F_ALIVE_BIT = 4, - NET_F_ALIVE = (1 << NET_F_ALIVE_BIT), +enum { + MSG_DATA, + MSG_CTL, + MSG_DROP, + MSG_BAD, }; #define BUILD_NETMSG(ct, query) \ @@ -57,7 +55,18 @@ void build_netmsg(struct nf_conntrack *ct, int query, struct nethdr *net); size_t prepare_send_netmsg(struct mcast_sock *m, void *data); int mcast_send_netmsg(struct mcast_sock *m, void *data); int handle_netmsg(struct nethdr *net); + +enum { + SEQ_UNKNOWN, + SEQ_UNSET, + SEQ_IN_SYNC, + SEQ_AFTER, + SEQ_BEFORE, +}; + int mcast_track_seq(uint32_t seq, uint32_t *exp_seq); +void mcast_track_update_seq(uint32_t seq); +int mcast_track_is_seq_set(void); struct mcast_conf; @@ -66,13 +75,12 @@ void mcast_buffered_destroy(void); int mcast_buffered_send_netmsg(struct mcast_sock *m, void *data, size_t len); ssize_t mcast_buffered_pending_netmsg(struct mcast_sock *m); -#define IS_DATA(x) ((x->flags & ~NET_F_HELLO) == 0) +#define IS_DATA(x) (x->flags == 0) #define IS_ACK(x) (x->flags & NET_F_ACK) #define IS_NACK(x) (x->flags & NET_F_NACK) #define IS_RESYNC(x) (x->flags & NET_F_RESYNC) #define IS_ALIVE(x) (x->flags & NET_F_ALIVE) #define IS_CTL(x) IS_ACK(x) || IS_NACK(x) || IS_RESYNC(x) || IS_ALIVE(x) -#define IS_HELLO(x) (x->flags & NET_F_HELLO) #define HDR_NETWORK2HOST(x) \ ({ \ diff --git a/src/network.c b/src/network.c index 92999a1..d7ab415 100644 --- a/src/network.c +++ b/src/network.c @@ -33,13 +33,14 @@ static size_t __do_send(struct mcast_sock *m, void *data, size_t len) #undef _TEST_DROP #ifdef _TEST_DROP - static int drop = 0; - if (++drop >= 10) { +#define DROP_RATE .25 + + /* simulate message omission with a certain probability */ + if ((random() & 0x7FFFFFFF) < 0x80000000 * DROP_RATE) { printf("drop sq: %u fl:%u len:%u\n", ntohl(net->seq), ntohs(net->flags), ntohs(net->len)); - drop = 0; return 0; } #endif @@ -57,7 +58,6 @@ static size_t __do_prepare(struct mcast_sock *m, void *data, size_t len) if (!seq_set) { seq_set = 1; cur_seq = time(NULL); - net->flags |= NET_F_HELLO; } net->len = len; net->seq = cur_seq++; @@ -181,9 +181,6 @@ int handle_netmsg(struct nethdr *net) HDR_NETWORK2HOST(net); - if (IS_HELLO(net)) - STATE_SYNC(last_seq_recv) = net->seq - 1; - if (IS_CTL(net)) return 0; @@ -198,37 +195,51 @@ int handle_netmsg(struct nethdr *net) return 0; } +static int local_seq_set = 0; + +/* this function only tracks, it does not update the last sequence received */ int mcast_track_seq(uint32_t seq, uint32_t *exp_seq) { - static int local_seq_set = 0; - int ret = 1; + int ret = SEQ_UNKNOWN; /* netlink sequence tracking initialization */ if (!local_seq_set) { - local_seq_set = 1; + ret = SEQ_UNSET; goto out; } /* fast path: we received the correct sequence */ - if (seq == STATE_SYNC(last_seq_recv)+1) + if (seq == STATE_SYNC(last_seq_recv)+1) { + ret = SEQ_IN_SYNC; goto out; + } /* out of sequence: some messages got lost */ if (after(seq, STATE_SYNC(last_seq_recv)+1)) { STATE_SYNC(packets_lost) += seq-STATE_SYNC(last_seq_recv)+1; - ret = 0; + ret = SEQ_AFTER; goto out; } /* out of sequence: replayed/delayed packet? */ if (before(seq, STATE_SYNC(last_seq_recv)+1)) - dlog(LOG_WARNING, "delayed packet? exp=%u rcv=%u", - STATE_SYNC(last_seq_recv)+1, seq); + ret = SEQ_BEFORE; out: *exp_seq = STATE_SYNC(last_seq_recv)+1; - /* update expected sequence */ - STATE_SYNC(last_seq_recv) = seq; return ret; } + +void mcast_track_update_seq(uint32_t seq) +{ + if (!local_seq_set) + local_seq_set = 1; + + STATE_SYNC(last_seq_recv) = seq; +} + +int mcast_track_is_seq_set() +{ + return local_seq_set; +} diff --git a/src/queue.c b/src/queue.c index 7b20e83..cdd70ae 100644 --- a/src/queue.c +++ b/src/queue.c @@ -93,7 +93,7 @@ retry: goto err; } - list_add(&n->head, &b->head); + list_add_tail(&n->head, &b->head); b->cur_size += size; b->num_elems++; diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index cac25d0..0b98513 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -34,11 +34,26 @@ #define dp(...) #endif +#if 0 +#define dprint printf +#else +#define dprint(...) +#endif + static LIST_HEAD(rs_list); static LIST_HEAD(tx_list); +static unsigned int rs_list_len; static unsigned int tx_list_len; static struct queue *rs_queue; static struct queue *tx_queue; +static uint32_t exp_seq; +static uint32_t window; +static uint32_t ack_from; +static int ack_from_set = 0; +static struct alarm_block alive_alarm; + +/* XXX: alive message expiration configurable */ +#define ALIVE_INT 1 struct cache_ftfw { struct list_head rs_list; @@ -64,6 +79,7 @@ static void cache_ftfw_del(struct us_conntrack *u, void *data) /* no need for list_del_init since the entry is destroyed */ list_del(&cn->rs_list); + rs_list_len--; } static struct cache_extra cache_ftfw_extra = { @@ -83,15 +99,57 @@ static void tx_queue_add_ctlmsg(uint32_t flags, uint32_t from, uint32_t to) queue_add(tx_queue, &ack, NETHDR_ACK_SIZ); } -static struct alarm_block alive_alarm; +static void ftfw_run(void); +/* this function is called from the alarm framework */ static void do_alive_alarm(struct alarm_block *a, void *data) { - tx_queue_add_ctlmsg(NET_F_ALIVE, 0, 0); + if (ack_from_set && mcast_track_is_seq_set()) { + /* exp_seq contains the last update received */ + dprint("send ALIVE ACK (from=%u, to=%u)\n", + ack_from, STATE_SYNC(last_seq_recv)); + tx_queue_add_ctlmsg(NET_F_ACK, + ack_from, + STATE_SYNC(last_seq_recv)); + ack_from_set = 0; + } else + tx_queue_add_ctlmsg(NET_F_ALIVE, 0, 0); + + /* TODO: no need for buffered send, extracted from run_sync() */ + ftfw_run(); + mcast_buffered_pending_netmsg(STATE_SYNC(mcast_client)); +} - add_alarm(&alive_alarm, 1, 0); +#undef _SIGNAL_DEBUG +#ifdef _SIGNAL_DEBUG + +static int rs_dump(void *data1, const void *data2) +{ + struct nethdr_ack *net = data1; + + dprint("in RS queue -> seq:%u flags:%u\n", net->seq, net->flags); + + return 0; } +#include + +static void my_dump(int foo) +{ + struct cache_ftfw *cn, *tmp; + + list_for_each_entry_safe(cn, tmp, &rs_list, rs_list) { + struct us_conntrack *u; + + u = cache_get_conntrack(STATE_SYNC(internal), cn); + dprint("in RS list -> seq:%u\n", cn->seq); + } + + queue_iterate(rs_queue, NULL, rs_dump); +} + +#endif + static int ftfw_init(void) { tx_queue = queue_create(CONFIG(resend_queue_size)); @@ -106,12 +164,15 @@ static int ftfw_init(void) return -1; } - INIT_LIST_HEAD(&tx_list); - INIT_LIST_HEAD(&rs_list); - - /* XXX: alive message expiration configurable */ init_alarm(&alive_alarm, NULL, do_alive_alarm); - add_alarm(&alive_alarm, 1, 0); + add_alarm(&alive_alarm, ALIVE_INT, 0); + + /* set ack window size */ + window = CONFIG(window_size); + +#ifdef _SIGNAL_DEBUG + signal(SIGUSR1, my_dump); +#endif return 0; } @@ -128,7 +189,7 @@ static int do_cache_to_tx(void *data1, void *data2) struct cache_ftfw *cn = cache_get_extra(STATE_SYNC(internal), u); /* add to tx list */ - list_add(&cn->tx_list, &tx_list); + list_add_tail(&cn->tx_list, &tx_list); tx_list_len++; return 0; @@ -157,13 +218,14 @@ static int ftfw_local(int fd, int type, void *data) static int rs_queue_to_tx(void *data1, const void *data2) { - struct nethdr *net = data1; + struct nethdr_ack *net = data1; const struct nethdr_ack *nack = data2; if (between(net->seq, nack->from, nack->to)) { dp("rs_queue_to_tx sq: %u fl:%u len:%u\n", net->seq, net->flags, net->len); queue_add(tx_queue, net, net->len); + queue_del(rs_queue, net); } return 0; } @@ -182,18 +244,20 @@ static int rs_queue_empty(void *data1, const void *data2) static void rs_list_to_tx(struct cache *c, unsigned int from, unsigned int to) { - struct cache_ftfw *cn; + struct cache_ftfw *cn, *tmp; - list_for_each_entry(cn, &rs_list, rs_list) { + list_for_each_entry_safe(cn, tmp, &rs_list, rs_list) { struct us_conntrack *u; u = cache_get_conntrack(STATE_SYNC(internal), cn); if (between(cn->seq, from, to)) { dp("resending nack'ed (oldseq=%u)\n", cn->seq); - list_add(&cn->tx_list, &tx_list); + list_del_init(&cn->rs_list); + rs_list_len--; + list_add_tail(&cn->tx_list, &tx_list); tx_list_len++; - } - } + } + } } static void rs_list_empty(struct cache *c, unsigned int from, unsigned int to) @@ -207,54 +271,113 @@ static void rs_list_empty(struct cache *c, unsigned int from, unsigned int to) if (between(cn->seq, from, to)) { dp("queue: deleting from queue (seq=%u)\n", cn->seq); list_del_init(&cn->rs_list); - } + rs_list_len--; + } } } -static int ftfw_recv(const struct nethdr *net) +static int digest_msg(const struct nethdr *net) { - static unsigned int window = 0; - unsigned int exp_seq; + if (IS_DATA(net)) + return MSG_DATA; - if (window == 0) - window = CONFIG(window_size); + else if (IS_ACK(net)) { + const struct nethdr_ack *h = (const struct nethdr_ack *) net; - if (!mcast_track_seq(net->seq, &exp_seq)) { - dp("OOS: sending nack (seq=%u)\n", exp_seq); - tx_queue_add_ctlmsg(NET_F_NACK, exp_seq, net->seq-1); - window = CONFIG(window_size); - } else { - /* received a window, send an acknowledgement */ - if (--window == 0) { - dp("sending ack (seq=%u)\n", net->seq); - tx_queue_add_ctlmsg(NET_F_ACK, - net->seq - CONFIG(window_size), - net->seq); - } - } + dprint("ACK(%u): from seq=%u to seq=%u\n", + h->seq, h->from, h->to); + rs_list_empty(STATE_SYNC(internal), h->from, h->to); + queue_iterate(rs_queue, h, rs_queue_empty); + return MSG_CTL; - if (IS_NACK(net)) { + } else if (IS_NACK(net)) { const struct nethdr_ack *nack = (const struct nethdr_ack *) net; - dp("NACK: from seq=%u to seq=%u\n", nack->from, nack->to); + dprint("NACK(%u): from seq=%u to seq=%u\n", + nack->seq, nack->from, nack->to); rs_list_to_tx(STATE_SYNC(internal), nack->from, nack->to); queue_iterate(rs_queue, nack, rs_queue_to_tx); - return 1; + return MSG_CTL; + } else if (IS_RESYNC(net)) { dp("RESYNC ALL\n"); cache_iterate(STATE_SYNC(internal), NULL, do_cache_to_tx); - return 1; - } else if (IS_ACK(net)) { - const struct nethdr_ack *h = (const struct nethdr_ack *) net; + return MSG_CTL; - dp("ACK: from seq=%u to seq=%u\n", h->from, h->to); - rs_list_empty(STATE_SYNC(internal), h->from, h->to); - queue_iterate(rs_queue, h, rs_queue_empty); - return 1; } else if (IS_ALIVE(net)) - return 1; + return MSG_CTL; - return 0; + return MSG_BAD; +} + +static int ftfw_recv(const struct nethdr *net) +{ + int ret = MSG_DATA; + + switch (mcast_track_seq(net->seq, &exp_seq)) { + case SEQ_AFTER: + ret = digest_msg(net); + if (ret == MSG_BAD) { + ret = MSG_BAD; + goto out; + } + + if (ack_from_set) { + tx_queue_add_ctlmsg(NET_F_ACK, ack_from, exp_seq-1); + dprint("OFS send half ACK: from seq=%u to seq=%u\n", + ack_from, exp_seq-1); + ack_from_set = 0; + } + + tx_queue_add_ctlmsg(NET_F_NACK, exp_seq, net->seq-1); + dprint("OFS send NACK: from seq=%u to seq=%u\n", + exp_seq, net->seq-1); + + /* count this message as part of the new window */ + window = CONFIG(window_size) - 1; + ack_from = net->seq; + ack_from_set = 1; + break; + + case SEQ_BEFORE: + /* we don't accept delayed packets */ + dlog(LOG_WARNING, "Received seq=%u before expected seq=%u", + net->seq, exp_seq); + dlog(LOG_WARNING, "Probably the other node has come back" + "to life but you forgot to add " + "conntrackd -r to your scripts"); + ret = MSG_DROP; + break; + + case SEQ_UNSET: + case SEQ_IN_SYNC: + ret = digest_msg(net); + if (ret == MSG_BAD) { + ret = MSG_BAD; + goto out; + } + + if (!ack_from_set) { + ack_from_set = 1; + ack_from = net->seq; + } + + if (--window <= 0) { + /* received a window, send an acknowledgement */ + dprint("OFS send ACK: from seq=%u to seq=%u\n", + ack_from, net->seq); + + tx_queue_add_ctlmsg(NET_F_ACK, ack_from, net->seq); + window = CONFIG(window_size); + ack_from_set = 0; + } + } + +out: + if ((ret == MSG_DATA || ret == MSG_CTL)) + mcast_track_update_seq(net->seq); + + return ret; } static void ftfw_send(struct nethdr *net, struct us_conntrack *u) @@ -270,11 +393,14 @@ static void ftfw_send(struct nethdr *net, struct us_conntrack *u) cn = (struct cache_ftfw *) cache_get_extra(STATE_SYNC(internal), u); - if (!list_empty(&cn->rs_list)) - list_del(&cn->rs_list); + if (!list_empty(&cn->rs_list)) { + list_del_init(&cn->rs_list); + rs_list_len--; + } cn->seq = net->seq; - list_add(&cn->rs_list, &rs_list); + list_add_tail(&cn->rs_list, &rs_list); + rs_list_len++; break; case NFCT_Q_DESTROY: queue_add(rs_queue, net, net->len); @@ -294,7 +420,7 @@ static int tx_queue_xmit(void *data1, const void *data2) HDR_NETWORK2HOST(net); if (IS_DATA(net) || IS_ACK(net) || IS_NACK(net)) { - dp("-> back_to_tx_queue sq: %u fl:%u len:%u\n", + dprint("tx_queue -> to_rs_queue sq: %u fl:%u len:%u\n", net->seq, net->flags, net->len); queue_add(rs_queue, net, net->len); } @@ -317,8 +443,7 @@ static int tx_list_xmit(struct list_head *i, struct us_conntrack *u) tx_list_len--; ret = mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); - if (STATE_SYNC(sync)->send) - STATE_SYNC(sync)->send(net, u); + ftfw_send(net, u); return ret; } @@ -337,6 +462,14 @@ static void ftfw_run(void) u = cache_get_conntrack(STATE_SYNC(internal), cn); tx_list_xmit(&cn->tx_list, u); } + + /* reset alive alarm */ + add_alarm(&alive_alarm, 1, 0); + + dprint("tx_list_len:%u tx_queue_len:%u " + "rs_list_len: %u rs_queue_len:%u\n", + tx_list_len, queue_len(tx_queue), + rs_list_len, queue_len(rs_queue)); } struct sync_mode sync_ftfw = { diff --git a/src/sync-mode.c b/src/sync-mode.c index 3851e4a..cbb4769 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -42,8 +42,18 @@ static void do_mcast_handler_step(struct nethdr *net) struct nf_conntrack *ct = (struct nf_conntrack *)(void*) __ct; struct us_conntrack *u; - if (STATE_SYNC(sync)->recv(net)) - return; + switch (STATE_SYNC(sync)->recv(net)) { + case MSG_DATA: + break; + case MSG_DROP: + case MSG_CTL: + return; + case MSG_BAD: + STATE(malformed)++; + return; + default: + break; + } memset(ct, 0, sizeof(__ct)); @@ -211,14 +221,15 @@ static int register_fds_sync(struct fds *fds) static void run_sync(fd_set *readfds) { /* multicast packet has been received */ - if (FD_ISSET(STATE_SYNC(mcast_server->fd), readfds)) + if (FD_ISSET(STATE_SYNC(mcast_server->fd), readfds)) { mcast_handler(); - if (STATE_SYNC(sync)->run) - STATE_SYNC(sync)->run(); + if (STATE_SYNC(sync)->run) + STATE_SYNC(sync)->run(); - /* flush pending messages */ - mcast_buffered_pending_netmsg(STATE_SYNC(mcast_client)); + /* flush pending messages */ + mcast_buffered_pending_netmsg(STATE_SYNC(mcast_client)); + } } static void kill_sync(void) @@ -358,16 +369,8 @@ static int purge_step(void *data1, void *data2) ret = nfct_query(h, NFCT_Q_GET, u->ct); if (ret == -1 && errno == ENOENT) { - size_t len; - struct nethdr *net = BUILD_NETMSG(u->ct, NFCT_Q_DESTROY); - debug_ct(u->ct, "overrun purge resync"); - - len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); - if (STATE_SYNC(sync)->send) - STATE_SYNC(sync)->send(net, u); - + mcast_send_sync(u, u->ct, NFCT_Q_DESTROY); cache_del(STATE_SYNC(internal), u->ct); } @@ -402,16 +405,8 @@ static int overrun_sync(enum nf_conntrack_msg_type type, if (!cache_test(STATE_SYNC(internal), ct)) { if ((u = cache_update_force(STATE_SYNC(internal), ct))) { - size_t len; - debug_ct(u->ct, "overrun resync"); - - struct nethdr *net = BUILD_NETMSG(u->ct, NFCT_Q_UPDATE); - len = prepare_send_netmsg(STATE_SYNC(mcast_client),net); - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), - net, len); - if (STATE_SYNC(sync)->send) - STATE_SYNC(sync)->send(net, u); + mcast_send_sync(u, u->ct, NFCT_Q_UPDATE); } } @@ -437,7 +432,6 @@ retry: } else { if (errno == EEXIST) { cache_del(STATE_SYNC(internal), ct); - mcast_send_sync(NULL, ct, NFCT_Q_DESTROY); goto retry; } -- cgit v1.2.3 From ace1f6a61b6842e2b49ec7a08f368a2d9f433be0 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Tue, 29 Apr 2008 14:18:17 +0000 Subject: Fix reorder possible reordering of destroy messages under message omission. This patch introduces the TimeoutDestroy clause to determine how long a conntrack remains in the internal cache once it has been destroy from the kernel table. --- include/cache.h | 1 + include/conntrackd.h | 1 + include/us-conntrack.h | 5 ++-- src/alarm.c | 5 ++-- src/cache.c | 81 ++++++++++++++++++++++++++++++++++---------------- src/cache_lifetime.c | 8 ++++- src/read_config_lex.l | 1 + src/read_config_yy.y | 12 +++++++- src/sync-ftfw.c | 13 ++++---- src/sync-mode.c | 27 +++++++++-------- 10 files changed, 105 insertions(+), 49 deletions(-) (limited to 'src') diff --git a/include/cache.h b/include/cache.h index f5afbe5..442a563 100644 --- a/include/cache.h +++ b/include/cache.h @@ -82,6 +82,7 @@ struct us_conntrack *cache_add(struct cache *c, struct nf_conntrack *ct); struct us_conntrack *cache_update(struct cache *c, struct nf_conntrack *ct); struct us_conntrack *cache_update_force(struct cache *c, struct nf_conntrack *ct); int cache_del(struct cache *c, struct nf_conntrack *ct); +struct us_conntrack *cache_del_timeout(struct cache *c, struct nf_conntrack *ct, int timeout); int cache_test(struct cache *c, struct nf_conntrack *ct); void cache_stats(const struct cache *c, int fd); struct us_conntrack *cache_get_conntrack(struct cache *, void *); diff --git a/include/conntrackd.h b/include/conntrackd.h index 57ac7e4..b266289 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -76,6 +76,7 @@ struct ct_conf { int refresh; int cache_timeout; /* cache entries timeout */ int commit_timeout; /* committed entries timeout */ + int del_timeout; unsigned int netlink_buffer_size; unsigned int netlink_buffer_size_max_grown; unsigned char ignore_protocol[IPPROTO_MAX]; diff --git a/include/us-conntrack.h b/include/us-conntrack.h index 3d71e22..9eafa3b 100644 --- a/include/us-conntrack.h +++ b/include/us-conntrack.h @@ -1,12 +1,13 @@ #ifndef _US_CONNTRACK_H_ #define _US_CONNTRACK_H_ +#include "alarm.h" #include -/* be careful, do not modify the layout */ struct us_conntrack { struct nf_conntrack *ct; - struct cache *cache; /* add new attributes here */ + struct cache *cache; + struct alarm_block alarm; char data[0]; }; diff --git a/src/alarm.c b/src/alarm.c index 91ee2ca..fe938a0 100644 --- a/src/alarm.c +++ b/src/alarm.c @@ -123,7 +123,7 @@ do_alarm_run(struct timeval *next_run) { struct list_head alarm_run_queue; struct rb_node *node; - struct alarm_block *this; + struct alarm_block *this, *tmp; struct timeval tv; gettimeofday(&tv, NULL); @@ -138,7 +138,8 @@ do_alarm_run(struct timeval *next_run) list_add(&this->list, &alarm_run_queue); } - list_for_each_entry(this, &alarm_run_queue, list) { + /* must be safe as entries can vanish from the callback */ + list_for_each_entry_safe(this, tmp, &alarm_run_queue, list) { rb_erase(&this->node, &alarm_root); RB_CLEAR_NODE(&this->node); this->function(this, this->data); diff --git a/src/cache.c b/src/cache.c index 73d539a..eac9a78 100644 --- a/src/cache.c +++ b/src/cache.c @@ -237,6 +237,8 @@ void cache_destroy(struct cache *c) free(c); } +static void __del_timeout(struct alarm_block *a, void *data); + static struct us_conntrack *__add(struct cache *c, struct nf_conntrack *ct) { unsigned i; @@ -258,6 +260,8 @@ static struct us_conntrack *__add(struct cache *c, struct nf_conntrack *ct) if (u) { char *data = u->data; + init_alarm(&u->alarm, u, __del_timeout); + for (i = 0; i < c->num_features; i++) { c->features[i]->add(u, data); data += c->features[i]->size; @@ -324,8 +328,7 @@ static struct us_conntrack *__update(struct cache *c, struct nf_conntrack *ct) return NULL; } -static struct us_conntrack * -__cache_update(struct cache *c, struct nf_conntrack *ct) +struct us_conntrack *cache_update(struct cache *c, struct nf_conntrack *ct) { struct us_conntrack *u; @@ -339,15 +342,6 @@ __cache_update(struct cache *c, struct nf_conntrack *ct) return NULL; } -struct us_conntrack *cache_update(struct cache *c, struct nf_conntrack *ct) -{ - struct us_conntrack *u; - - u = __cache_update(c, ct); - - return u; -} - struct us_conntrack *cache_update_force(struct cache *c, struct nf_conntrack *ct) { @@ -379,6 +373,24 @@ int cache_test(struct cache *c, struct nf_conntrack *ct) return ret != NULL; } +static void __del2(struct cache *c, struct us_conntrack *u) +{ + unsigned i; + char *data = u->data; + struct nf_conntrack *p = u->ct; + + for (i = 0; i < c->num_features; i++) { + c->features[i]->destroy(u, data); + data += c->features[i]->size; + } + + if (c->extra && c->extra->destroy) + c->extra->destroy(u, ((char *) u) + c->extra_offset); + + hashtable_del(c->h, u); + free(p); +} + static int __del(struct cache *c, struct nf_conntrack *ct) { size_t size = c->h->datasize; @@ -389,20 +401,8 @@ static int __del(struct cache *c, struct nf_conntrack *ct) u = (struct us_conntrack *) hashtable_test(c->h, u); if (u) { - unsigned i; - char *data = u->data; - struct nf_conntrack *p = u->ct; - - for (i = 0; i < c->num_features; i++) { - c->features[i]->destroy(u, data); - data += c->features[i]->size; - } - - if (c->extra && c->extra->destroy) - c->extra->destroy(u, ((char *) u) + c->extra_offset); - - hashtable_del(c->h, u); - free(p); + del_alarm(&u->alarm); + __del2(c, u); return 1; } return 0; @@ -419,6 +419,37 @@ int cache_del(struct cache *c, struct nf_conntrack *ct) return 0; } +static void __del_timeout(struct alarm_block *a, void *data) +{ + struct us_conntrack *u = (struct us_conntrack *) data; + struct cache *c = u->cache; + + __del2(u->cache, u); + c->del_ok++; +} + +struct us_conntrack * +cache_del_timeout(struct cache *c, struct nf_conntrack *ct, int timeout) +{ + size_t size = c->h->datasize; + char buf[size]; + struct us_conntrack *u = (struct us_conntrack *) buf; + + if (timeout <= 0) + cache_del(c, ct); + + u->ct = ct; + + u = (struct us_conntrack *) hashtable_test(c->h, u); + if (u) { + if (!alarm_pending(&u->alarm)) { + add_alarm(&u->alarm, timeout, 0); + return u; + } + } + return NULL; +} + struct us_conntrack *cache_get_conntrack(struct cache *c, void *data) { return (struct us_conntrack *)((char*)data - c->extra_offset); diff --git a/src/cache_lifetime.c b/src/cache_lifetime.c index ad3416a..cf84d20 100644 --- a/src/cache_lifetime.c +++ b/src/cache_lifetime.c @@ -53,7 +53,13 @@ static int lifetime_dump(struct us_conntrack *u, gettimeofday(&tv, NULL); - return sprintf(buf, " [active since %lds]", tv.tv_sec - *lifetime); + if (alarm_pending(&u->alarm)) + return sprintf(buf, " [active since %lds] [expires in %lds]", + tv.tv_sec - *lifetime, + u->alarm.tv.tv_sec - tv.tv_sec); + else + return sprintf(buf, " [active since %lds]", + tv.tv_sec - *lifetime); } struct cache_feature lifetime_feature = { diff --git a/src/read_config_lex.l b/src/read_config_lex.l index fe2090b..1350afc 100644 --- a/src/read_config_lex.l +++ b/src/read_config_lex.l @@ -103,6 +103,7 @@ ftfw [F|f][T|t][F|f][W|w] "CLOSE" { return T_CLOSE; } "LISTEN" { return T_LISTEN; } "LogFileBufferSize" { return T_STAT_BUFFER_SIZE; } +"DestroyTimeout" { return T_DESTROY_TIMEOUT; } {is_on} { return T_ON; } {is_off} { return T_OFF; } diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 86fee9b..0bc5e3c 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -52,7 +52,7 @@ struct ct_conf conf; %token T_REPLICATE T_FOR T_IFACE %token T_ESTABLISHED T_SYN_SENT T_SYN_RECV T_FIN_WAIT %token T_CLOSE_WAIT T_LAST_ACK T_TIME_WAIT T_CLOSE T_LISTEN -%token T_SYSLOG T_WRITE_THROUGH T_STAT_BUFFER_SIZE +%token T_SYSLOG T_WRITE_THROUGH T_STAT_BUFFER_SIZE T_DESTROY_TIMEOUT %token T_IP T_PATH_VAL @@ -429,6 +429,7 @@ sync_line: refreshtime | listen_to | state_replication | cache_writethrough + | destroy_timeout ; sync_mode_alarm: T_SYNC_MODE T_ALARM '{' sync_mode_alarm_list '}' @@ -469,6 +470,11 @@ window_size: T_WINDOWSIZE T_NUMBER conf.window_size = $2; }; +destroy_timeout: T_DESTROY_TIMEOUT T_NUMBER +{ + conf.del_timeout = $2; +}; + relax_transitions: T_RELAX_TRANSITIONS { fprintf(stderr, "Notice: RelaxTransitions clause is obsolete. " @@ -746,5 +752,9 @@ init_config(char *filename) if (CONFIG(window_size) == 0) CONFIG(window_size) = 20; + /* double of 120 seconds which is common timeout of a final state */ + if (conf.flags & CTD_SYNC_FTFW && CONFIG(del_timeout) == 0) + CONFIG(del_timeout) = 240; + return 0; } diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 0b98513..77f8fd4 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -390,6 +390,7 @@ static void ftfw_send(struct nethdr *net, struct us_conntrack *u) switch(ntohs(pld->query)) { case NFCT_Q_CREATE: case NFCT_Q_UPDATE: + case NFCT_Q_DESTROY: cn = (struct cache_ftfw *) cache_get_extra(STATE_SYNC(internal), u); @@ -402,9 +403,6 @@ static void ftfw_send(struct nethdr *net, struct us_conntrack *u) list_add_tail(&cn->rs_list, &rs_list); rs_list_len++; break; - case NFCT_Q_DESTROY: - queue_add(rs_queue, net, net->len); - break; } } @@ -429,10 +427,10 @@ static int tx_queue_xmit(void *data1, const void *data2) return 0; } -static int tx_list_xmit(struct list_head *i, struct us_conntrack *u) +static int tx_list_xmit(struct list_head *i, struct us_conntrack *u, int type) { int ret; - struct nethdr *net = BUILD_NETMSG(u->ct, NFCT_Q_UPDATE); + struct nethdr *net = BUILD_NETMSG(u->ct, type); size_t len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); dp("tx_list sq: %u fl:%u len:%u\n", @@ -460,7 +458,10 @@ static void ftfw_run(void) struct us_conntrack *u; u = cache_get_conntrack(STATE_SYNC(internal), cn); - tx_list_xmit(&cn->tx_list, u); + if (alarm_pending(&u->alarm)) + tx_list_xmit(&cn->tx_list, u, NFCT_Q_DESTROY); + else + tx_list_xmit(&cn->tx_list, u, NFCT_Q_UPDATE); } /* reset alive alarm */ diff --git a/src/sync-mode.c b/src/sync-mode.c index cbb4769..a952a5b 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -344,17 +344,15 @@ static void dump_sync(struct nf_conntrack *ct) debug_ct(ct, "resync"); } -static void mcast_send_sync(struct us_conntrack *u, - struct nf_conntrack *ct, - int query) +static void mcast_send_sync(struct us_conntrack *u, int query) { size_t len; struct nethdr *net; - if (!state_helper_verdict(query, ct)) + if (!state_helper_verdict(query, u->ct)) return; - net = BUILD_NETMSG(ct, query); + net = BUILD_NETMSG(u->ct, query); len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); if (STATE_SYNC(sync)->send) @@ -370,8 +368,10 @@ static int purge_step(void *data1, void *data2) ret = nfct_query(h, NFCT_Q_GET, u->ct); if (ret == -1 && errno == ENOENT) { debug_ct(u->ct, "overrun purge resync"); - mcast_send_sync(u, u->ct, NFCT_Q_DESTROY); - cache_del(STATE_SYNC(internal), u->ct); + if (cache_del_timeout(STATE_SYNC(internal), + u->ct, + CONFIG(del_timeout))) + mcast_send_sync(u, NFCT_Q_DESTROY); } return 0; @@ -406,7 +406,7 @@ static int overrun_sync(enum nf_conntrack_msg_type type, if (!cache_test(STATE_SYNC(internal), ct)) { if ((u = cache_update_force(STATE_SYNC(internal), ct))) { debug_ct(u->ct, "overrun resync"); - mcast_send_sync(u, u->ct, NFCT_Q_UPDATE); + mcast_send_sync(u, NFCT_Q_UPDATE); } } @@ -427,7 +427,7 @@ static void event_new_sync(struct nf_conntrack *ct) nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); retry: if ((u = cache_add(STATE_SYNC(internal), ct))) { - mcast_send_sync(u, ct, NFCT_Q_CREATE); + mcast_send_sync(u, NFCT_Q_CREATE); debug_ct(u->ct, "internal new"); } else { if (errno == EEXIST) { @@ -453,16 +453,19 @@ static void event_update_sync(struct nf_conntrack *ct) return; } debug_ct(u->ct, "internal update"); - mcast_send_sync(u, ct, NFCT_Q_UPDATE); + mcast_send_sync(u, NFCT_Q_UPDATE); } static int event_destroy_sync(struct nf_conntrack *ct) { + struct us_conntrack *u; + if (!CONFIG(cache_write_through)) nfct_attr_unset(ct, ATTR_TIMEOUT); - if (cache_del(STATE_SYNC(internal), ct)) { - mcast_send_sync(NULL, ct, NFCT_Q_DESTROY); + u = cache_del_timeout(STATE_SYNC(internal), ct, CONFIG(del_timeout)); + if (u != NULL) { + mcast_send_sync(u, NFCT_Q_DESTROY); debug_ct(ct, "internal destroy"); return 1; } else { -- cgit v1.2.3 From be2450f37f2ce56eadc78793efc4a54ced4315c6 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 16 May 2008 17:05:17 +0200 Subject: - remove (misleading) counters and use information from the statistics mode - use generic nfct_copy() from libnetfilter_conntrack to update objects - use generic nfct_cmp() to compare objects --- ChangeLog | 3 +++ configure.in | 4 +-- src/cache.c | 75 ++------------------------------------------------------ src/stats-mode.c | 5 ++++ 4 files changed, 12 insertions(+), 75 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 02ac75a..d67ad30 100644 --- a/ChangeLog +++ b/ChangeLog @@ -26,6 +26,9 @@ o improve netlink overrun handling o add more verbose error notification when we fail to inject a conntrack o rework of the FT-FW approach o minor fix of the manpage (Max Wilhelm) +o remove (misleading) counters and use information from the statistics mode +o use generic nfct_copy() from libnetfilter_conntrack to update objects +o use generic nfct_cmp() to compare objects version 0.9.6 (2008/03/08) ------------------------------ diff --git a/configure.in b/configure.in index 17101e9..f3b8785 100644 --- a/configure.in +++ b/configure.in @@ -17,8 +17,8 @@ case $target in esac dnl Dependencies -LIBNFNETLINK_REQUIRED=0.0.32 -LIBNETFILTER_CONNTRACK_REQUIRED=0.0.92 +LIBNFNETLINK_REQUIRED=0.0.33 +LIBNETFILTER_CONNTRACK_REQUIRED=0.0.94 AC_CHECK_PROG(HAVE_PKG_CONFIG, pkg-config, yes) if test "x$HAVE_PKG_CONFIG" = "x" diff --git a/src/cache.c b/src/cache.c index eac9a78..4162661 100644 --- a/src/cache.c +++ b/src/cache.c @@ -85,75 +85,12 @@ static uint32_t hash(const void *data, struct hashtable *table) return ret; } -static int __compare(const struct nf_conntrack *ct1, - const struct nf_conntrack *ct2) -{ - return ((nfct_get_attr_u8(ct1, ATTR_ORIG_L4PROTO) == - nfct_get_attr_u8(ct2, ATTR_ORIG_L4PROTO)) && - (nfct_get_attr_u16(ct1, ATTR_ORIG_PORT_SRC) == - nfct_get_attr_u16(ct2, ATTR_ORIG_PORT_SRC)) && - (nfct_get_attr_u16(ct1, ATTR_ORIG_PORT_DST) == - nfct_get_attr_u16(ct2, ATTR_ORIG_PORT_DST)) && - (nfct_get_attr_u16(ct1, ATTR_REPL_PORT_SRC) == - nfct_get_attr_u16(ct2, ATTR_REPL_PORT_SRC)) && - (nfct_get_attr_u16(ct1, ATTR_REPL_PORT_DST) == - nfct_get_attr_u16(ct2, ATTR_REPL_PORT_DST))); -} - -static int -__compare4(const struct us_conntrack *u1, const struct us_conntrack *u2) -{ - return ((nfct_get_attr_u32(u1->ct, ATTR_ORIG_IPV4_SRC) == - nfct_get_attr_u32(u2->ct, ATTR_ORIG_IPV4_SRC)) && - (nfct_get_attr_u32(u1->ct, ATTR_ORIG_IPV4_DST) == - nfct_get_attr_u32(u2->ct, ATTR_ORIG_IPV4_DST)) && - (nfct_get_attr_u32(u1->ct, ATTR_REPL_IPV4_SRC) == - nfct_get_attr_u32(u2->ct, ATTR_REPL_IPV4_SRC)) && - (nfct_get_attr_u32(u1->ct, ATTR_REPL_IPV4_DST) == - nfct_get_attr_u32(u2->ct, ATTR_REPL_IPV4_DST)) && - __compare(u1->ct, u2->ct)); -} - -static int -__compare6(const struct us_conntrack *u1, const struct us_conntrack *u2) -{ - return ((memcmp(nfct_get_attr(u1->ct, ATTR_ORIG_IPV6_SRC), - nfct_get_attr(u2->ct, ATTR_ORIG_IPV6_SRC), - sizeof(uint32_t)*4) == 0) && - (memcmp(nfct_get_attr(u1->ct, ATTR_ORIG_IPV6_DST), - nfct_get_attr(u2->ct, ATTR_ORIG_IPV6_DST), - sizeof(uint32_t)*4) == 0) && - (memcmp(nfct_get_attr(u1->ct, ATTR_REPL_IPV6_SRC), - nfct_get_attr(u2->ct, ATTR_REPL_IPV6_SRC), - sizeof(uint32_t)*4) == 0) && - (memcmp(nfct_get_attr(u1->ct, ATTR_REPL_IPV6_DST), - nfct_get_attr(u2->ct, ATTR_REPL_IPV6_DST), - sizeof(uint32_t)*4) == 0) && - __compare(u1->ct, u2->ct)); -} - static int compare(const void *data1, const void *data2) { - int ret = 0; const struct us_conntrack *u1 = data1; const struct us_conntrack *u2 = data2; - if (nfct_get_attr_u8(u1->ct, ATTR_L3PROTO) != - nfct_get_attr_u8(u2->ct, ATTR_L3PROTO)) - return ret; - - switch(nfct_get_attr_u8(u1->ct, ATTR_L3PROTO)) { - case AF_INET: - ret = __compare4(u1, u2); - break; - case AF_INET6: - ret = __compare6(u1, u2); - break; - default: - dlog(LOG_ERR, "unknown layer 3 in compare"); - break; - } - return ret; + return nfct_cmp(u1->ct, u2->ct, NFCT_CMP_ORIG | NFCT_CMP_REPL); } struct cache_feature *cache_feature[CACHE_MAX_FEATURE] = { @@ -305,15 +242,7 @@ static struct us_conntrack *__update(struct cache *c, struct nf_conntrack *ct) unsigned i; char *data = u->data; - if (nfct_attr_is_set(ct, ATTR_STATUS)) - nfct_set_attr_u32(u->ct, ATTR_STATUS, - nfct_get_attr_u32(ct, ATTR_STATUS)); - if (nfct_attr_is_set(ct, ATTR_TCP_STATE)) - nfct_set_attr_u8(u->ct, ATTR_TCP_STATE, - nfct_get_attr_u8(ct, ATTR_TCP_STATE)); - if (nfct_attr_is_set(ct, ATTR_TIMEOUT)) - nfct_set_attr_u32(u->ct, ATTR_TIMEOUT, - nfct_get_attr_u32(ct, ATTR_TIMEOUT)); + nfct_copy(u->ct, ct, NFCT_CP_META); for (i = 0; i < c->num_features; i++) { c->features[i]->update(u, data); diff --git a/src/stats-mode.c b/src/stats-mode.c index 5808320..1650d5d 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -89,7 +89,12 @@ static int local_handler_stats(int fd, int type, void *data) static void dump_stats(struct nf_conntrack *ct) { + nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES); + nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS); + nfct_attr_unset(ct, ATTR_REPL_COUNTER_BYTES); + nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); nfct_attr_unset(ct, ATTR_TIMEOUT); + nfct_attr_unset(ct, ATTR_USE); if (cache_update_force(STATE_STATS(cache), ct)) debug_ct(ct, "resync entry"); -- cgit v1.2.3 From db91cafe5b72f9f591dd8c168427005503186c01 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 18 May 2008 21:16:05 +0200 Subject: improve network message sanity checkings --- ChangeLog | 1 + include/network.h | 3 +-- include/sync.h | 1 + src/network.c | 24 ------------------------ src/parse.c | 30 +++++++++++++++++++++++++++--- src/sync-mode.c | 41 ++++++++++++++++++++++++++++++----------- 6 files changed, 60 insertions(+), 40 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index d67ad30..4458830 100644 --- a/ChangeLog +++ b/ChangeLog @@ -29,6 +29,7 @@ o minor fix of the manpage (Max Wilhelm) o remove (misleading) counters and use information from the statistics mode o use generic nfct_copy() from libnetfilter_conntrack to update objects o use generic nfct_cmp() to compare objects +o improve network message sanity checkings version 0.9.6 (2008/03/08) ------------------------------ diff --git a/include/network.h b/include/network.h index 0fa7b71..baa1eba 100644 --- a/include/network.h +++ b/include/network.h @@ -54,7 +54,6 @@ struct mcast_sock; void build_netmsg(struct nf_conntrack *ct, int query, struct nethdr *net); size_t prepare_send_netmsg(struct mcast_sock *m, void *data); int mcast_send_netmsg(struct mcast_sock *m, void *data); -int handle_netmsg(struct nethdr *net); enum { SEQ_UNKNOWN, @@ -175,6 +174,6 @@ struct netattr { void build_netpld(struct nf_conntrack *ct, struct netpld *pld, int query); -void parse_netpld(struct nf_conntrack *ct, struct netpld *pld, int *query); +int parse_netpld(struct nf_conntrack *ct, struct nethdr *net, int *query, size_t remain); #endif diff --git a/include/sync.h b/include/sync.h index 39e0f46..fc06c93 100644 --- a/include/sync.h +++ b/include/sync.h @@ -20,5 +20,6 @@ struct sync_mode { extern struct sync_mode sync_alarm; extern struct sync_mode sync_ftfw; +extern struct sync_mode sync_notrack; #endif diff --git a/src/network.c b/src/network.c index d7ab415..fb6ea90 100644 --- a/src/network.c +++ b/src/network.c @@ -171,30 +171,6 @@ void build_netmsg(struct nf_conntrack *ct, int query, struct nethdr *net) build_netpld(ct, pld, query); } -int handle_netmsg(struct nethdr *net) -{ - struct netpld *pld = NETHDR_DATA(net); - - /* message too small: no room for the header */ - if (ntohs(net->len) < NETHDR_ACK_SIZ) - return -1; - - HDR_NETWORK2HOST(net); - - if (IS_CTL(net)) - return 0; - - /* information received is too small */ - if (net->len < sizeof(struct netpld)) - return -1; - - /* size mismatch! */ - if (net->len < ntohs(pld->len) + NETHDR_SIZ) - return -1; - - return 0; -} - static int local_seq_set = 0; /* this function only tracks, it does not update the last sequence received */ diff --git a/src/parse.c b/src/parse.c index 8ef2e8d..645420d 100644 --- a/src/parse.c +++ b/src/parse.c @@ -20,6 +20,10 @@ #include +#ifndef ssizeof +#define ssizeof(x) (int)sizeof(x) +#endif + static void parse_u8(struct nf_conntrack *ct, int attr, void *data) { uint8_t *value = (uint8_t *) data; @@ -77,20 +81,40 @@ static parse h[ATTR_MAX] = { [ATTR_REPL_NAT_SEQ_OFFSET_AFTER] = parse_u32, }; -void parse_netpld(struct nf_conntrack *ct, struct netpld *pld, int *query) +int +parse_netpld(struct nf_conntrack *ct, + struct nethdr *net, + int *query, + size_t remain) { int len; struct netattr *attr; + struct netpld *pld; + + if (remain < NETHDR_SIZ + sizeof(struct netpld)) + return -1; + + pld = NETHDR_DATA(net); + + if (remain < NETHDR_SIZ + sizeof(struct netpld) + ntohs(pld->len)) + return -1; + + if (net->len < NETHDR_SIZ + sizeof(struct netpld) + ntohs(pld->len)) + return -1; PLD_NETWORK2HOST(pld); len = pld->len; attr = PLD_DATA(pld); - while (len > 0) { + while (len > ssizeof(struct netattr)) { ATTR_NETWORK2HOST(attr); - h[attr->nta_attr](ct, attr->nta_attr, NTA_DATA(attr)); + if (attr->nta_len > len) + return -1; + if (h[attr->nta_attr]) + h[attr->nta_attr](ct, attr->nta_attr, NTA_DATA(attr)); attr = NTA_NEXT(attr, len); } *query = pld->query; + return 0; } diff --git a/src/sync-mode.c b/src/sync-mode.c index a952a5b..7d73e2f 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -34,10 +34,9 @@ #include #include -static void do_mcast_handler_step(struct nethdr *net) +static void do_mcast_handler_step(struct nethdr *net, size_t remain) { int query; - struct netpld *pld = NETHDR_DATA(net); char __ct[nfct_maxsize()]; struct nf_conntrack *ct = (struct nf_conntrack *)(void*) __ct; struct us_conntrack *u; @@ -57,8 +56,11 @@ static void do_mcast_handler_step(struct nethdr *net) memset(ct, 0, sizeof(__ct)); - /* XXX: check for malformed */ - parse_netpld(ct, pld, &query); + if (parse_netpld(ct, net, &query, remain) == -1) { + STATE(malformed)++; + dlog(LOG_ERR, "parsing failed: malformed message"); + return; + } switch(query) { case NFCT_Q_CREATE: @@ -91,6 +93,7 @@ retry: debug_ct(ct, "can't destroy"); break; default: + STATE(malformed)++; dlog(LOG_ERR, "mcast unknown query %d\n", query); break; } @@ -113,24 +116,40 @@ static void mcast_handler(void) if (remain < NETHDR_SIZ) { STATE(malformed)++; + dlog(LOG_WARNING, "no room for header"); break; } if (ntohs(net->len) > remain) { - dlog(LOG_ERR, "fragmented messages"); + STATE(malformed)++; + dlog(LOG_WARNING, "fragmented message"); break; } + if (IS_CTL(net)) { + if (remain < NETHDR_ACK_SIZ) { + STATE(malformed)++; + dlog(LOG_WARNING, "no room for ctl message"); + } + + if (ntohs(net->len) < NETHDR_ACK_SIZ) { + STATE(malformed)++; + dlog(LOG_WARNING, "ctl header too small"); + } + } else { + if (ntohs(net->len) < NETHDR_SIZ) { + STATE(malformed)++; + dlog(LOG_WARNING, "header too small"); + } + } + debug("recv sq: %u fl:%u len:%u (rem:%d)\n", ntohl(net->seq), ntohs(net->flags), ntohs(net->len), remain); - /* sanity check and convert nethdr to host byte order */ - if (handle_netmsg(net) == -1) { - STATE(malformed)++; - return; - } - do_mcast_handler_step(net); + HDR_NETWORK2HOST(net); + + do_mcast_handler_step(net, remain); ptr += net->len; remain -= net->len; } -- cgit v1.2.3 From da8717a4bfa8884a411ae2445b9f1654b0550a64 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 20 May 2008 15:52:06 +0200 Subject: add Mcast[Snd|Rcv]SocketBuffer clauses to tune multicast socket buffers --- ChangeLog | 1 + doc/sync/alarm/node1/conntrackd.conf | 22 ++++++++++++++++++++++ doc/sync/alarm/node2/conntrackd.conf | 22 ++++++++++++++++++++++ doc/sync/ftfw/node1/conntrackd.conf | 22 ++++++++++++++++++++++ doc/sync/ftfw/node2/conntrackd.conf | 22 ++++++++++++++++++++++ include/mcast.h | 2 ++ src/mcast.c | 31 +++++++++++++++++++++++++++++++ src/read_config_lex.l | 2 ++ src/read_config_yy.y | 12 +++++++++++- src/sync-mode.c | 6 ++++++ 10 files changed, 141 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 4458830..0b30f4f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -30,6 +30,7 @@ o remove (misleading) counters and use information from the statistics mode o use generic nfct_copy() from libnetfilter_conntrack to update objects o use generic nfct_cmp() to compare objects o improve network message sanity checkings +o add Mcast[Snd|Rcv]SocketBuffer clauses to tune multicast socket buffers version 0.9.6 (2008/03/08) ------------------------------ diff --git a/doc/sync/alarm/node1/conntrackd.conf b/doc/sync/alarm/node1/conntrackd.conf index 3004d07..56bef0c 100644 --- a/doc/sync/alarm/node1/conntrackd.conf +++ b/doc/sync/alarm/node1/conntrackd.conf @@ -39,6 +39,28 @@ Sync { IPv4_interface 192.168.100.100 # IP of dedicated link Interface eth2 Group 3780 + + # The multicast sender uses a buffer to enqueue the packets + # that are going to be transmitted. The default size of this + # socket buffer is available at /proc/sys/net/core/wmem_default. + # This value determines the chances to have an overrun in the + # sender queue. The overrun results packet loss, thus, losing + # state information that would have to be retransmitted. If you + # notice some packet loss, you may want to increase the size + # of the sender buffer. + # + # McastSndSocketBuffer 1249280 + + # The multicast receiver uses a buffer to enqueue the packets + # that the socket is pending to handle. The default size of this + # socket buffer is available at /proc/sys/net/core/rmem_default. + # This value determines the chances to have an overrun in the + # receiver queue. The overrun results packet loss, thus, losing + # state information that would have to be retransmitted. If you + # notice some packet loss, you may want to increase the size of + # the receiver buffer. + # + # McastRcvSocketBuffer 1249280 } # Enable/Disable message checksumming diff --git a/doc/sync/alarm/node2/conntrackd.conf b/doc/sync/alarm/node2/conntrackd.conf index fb12130..e0cb375 100644 --- a/doc/sync/alarm/node2/conntrackd.conf +++ b/doc/sync/alarm/node2/conntrackd.conf @@ -39,6 +39,28 @@ Sync { IPv4_interface 192.168.100.200 # IP of dedicated link Interface eth2 Group 3780 + + # The multicast sender uses a buffer to enqueue the packets + # that are going to be transmitted. The default size of this + # socket buffer is available at /proc/sys/net/core/wmem_default. + # This value determines the chances to have an overrun in the + # sender queue. The overrun results packet loss, thus, losing + # state information that would have to be retransmitted. If you + # notice some packet loss, you may want to increase the size + # of the sender buffer. + # + # McastSndSocketBuffer 1249280 + + # The multicast receiver uses a buffer to enqueue the packets + # that the socket is pending to handle. The default size of this + # socket buffer is available at /proc/sys/net/core/rmem_default. + # This value determines the chances to have an overrun in the + # receiver queue. The overrun results packet loss, thus, losing + # state information that would have to be retransmitted. If you + # notice some packet loss, you may want to increase the size of + # the receiver buffer. + # + # McastRcvSocketBuffer 1249280 } # Enable/Disable message checksumming diff --git a/doc/sync/ftfw/node1/conntrackd.conf b/doc/sync/ftfw/node1/conntrackd.conf index fadeb9d..f3211db 100644 --- a/doc/sync/ftfw/node1/conntrackd.conf +++ b/doc/sync/ftfw/node1/conntrackd.conf @@ -34,6 +34,28 @@ Sync { IPv4_interface 192.168.100.100 # IP of dedicated link Interface eth2 Group 3780 + + # The multicast sender uses a buffer to enqueue the packets + # that are going to be transmitted. The default size of this + # socket buffer is available at /proc/sys/net/core/wmem_default. + # This value determines the chances to have an overrun in the + # sender queue. The overrun results packet loss, thus, losing + # state information that would have to be retransmitted. If you + # notice some packet loss, you may want to increase the size + # of the sender buffer. + # + # McastSndSocketBuffer 1249280 + # + # The multicast receiver uses a buffer to enqueue the packets + # that the socket is pending to handle. The default size of this + # socket buffer is available at /proc/sys/net/core/rmem_default. + # This value determines the chances to have an overrun in the + # receiver queue. The overrun results packet loss, thus, losing + # state information that would have to be retransmitted. If you + # notice some packet loss, you may want to increase the size of + # the receiver buffer. + # + # McastRcvSocketBuffer 1249280 } # Enable/Disable message checksumming diff --git a/doc/sync/ftfw/node2/conntrackd.conf b/doc/sync/ftfw/node2/conntrackd.conf index 59ffc4f..9c26ff5 100644 --- a/doc/sync/ftfw/node2/conntrackd.conf +++ b/doc/sync/ftfw/node2/conntrackd.conf @@ -33,6 +33,28 @@ Sync { IPv4_interface 192.168.100.200 # IP of dedicated link Interface eth2 Group 3780 + + # The multicast sender uses a buffer to enqueue the packets + # that are going to be transmitted. The default size of this + # socket buffer is available at /proc/sys/net/core/wmem_default. + # This value determines the chances to have an overrun in the + # sender queue. The overrun results packet loss, thus, losing + # state information that would have to be retransmitted. If you + # notice some packet loss, you may want to increase the size + # of the sender buffer. + # + # McastSndSocketBuffer 1249280 + # + # The multicast receiver uses a buffer to enqueue the packets + # that the socket is pending to handle. The default size of this + # socket buffer is available at /proc/sys/net/core/rmem_default. + # This value determines the chances to have an overrun in the + # receiver queue. The overrun results packet loss, thus, losing + # state information that would have to be retransmitted. If you + # notice some packet loss, you may want to increase the size of + # the receiver buffer. + # + # McastRcvSocketBuffer 1249280 } # Enable/Disable message checksumming diff --git a/include/mcast.h b/include/mcast.h index c2fd3ec..7c4b1d6 100644 --- a/include/mcast.h +++ b/include/mcast.h @@ -19,6 +19,8 @@ struct mcast_conf { unsigned int interface_index6; } ifa; int mtu; + int sndbuf; + int rcvbuf; char iface[IFNAMSIZ]; }; diff --git a/src/mcast.c b/src/mcast.c index f945511..16d8856 100644 --- a/src/mcast.c +++ b/src/mcast.c @@ -28,6 +28,7 @@ #include #include #include +#include struct mcast_sock *mcast_server_create(struct mcast_conf *conf) { @@ -37,6 +38,7 @@ struct mcast_sock *mcast_server_create(struct mcast_conf *conf) struct ipv6_mreq ipv6; } mreq; struct mcast_sock *m; + socklen_t socklen = sizeof(int); m = (struct mcast_sock *) malloc(sizeof(struct mcast_sock)); if (!m) @@ -96,6 +98,20 @@ struct mcast_sock *mcast_server_create(struct mcast_conf *conf) return NULL; } + if (conf->rcvbuf && + setsockopt(m->fd, SOL_SOCKET, SO_RCVBUFFORCE, &conf->rcvbuf, + sizeof(int)) == -1) { + /* not supported in linux kernel < 2.6.14 */ + if (errno != ENOPROTOOPT) { + debug("mcast_sock_server_create:setsockopt2"); + close(m->fd); + free(m); + return NULL; + } + } + + getsockopt(m->fd, SOL_SOCKET, SO_RCVBUF, &conf->rcvbuf, &socklen); + if (bind(m->fd, (struct sockaddr *) &m->addr, m->sockaddr_len) == -1) { debug("mcast_sock_server_create:bind"); close(m->fd); @@ -195,6 +211,7 @@ struct mcast_sock *mcast_client_create(struct mcast_conf *conf) { int ret; struct mcast_sock *m; + socklen_t socklen = sizeof(int); m = (struct mcast_sock *) malloc(sizeof(struct mcast_sock)); if (!m) @@ -215,6 +232,20 @@ struct mcast_sock *mcast_client_create(struct mcast_conf *conf) return NULL; } + if (conf->sndbuf && + setsockopt(m->fd, SOL_SOCKET, SO_SNDBUFFORCE, &conf->sndbuf, + sizeof(int)) == -1) { + /* not supported in linux kernel < 2.6.14 */ + if (errno != ENOPROTOOPT) { + debug("mcast_sock_server_create:setsockopt2"); + close(m->fd); + free(m); + return NULL; + } + } + + getsockopt(m->fd, SOL_SOCKET, SO_SNDBUF, &conf->sndbuf, &socklen); + switch(conf->ipproto) { case AF_INET: ret = __mcast_client_create_ipv4(m, conf); diff --git a/src/read_config_lex.l b/src/read_config_lex.l index 1350afc..eb3368a 100644 --- a/src/read_config_lex.l +++ b/src/read_config_lex.l @@ -104,6 +104,8 @@ ftfw [F|f][T|t][F|f][W|w] "LISTEN" { return T_LISTEN; } "LogFileBufferSize" { return T_STAT_BUFFER_SIZE; } "DestroyTimeout" { return T_DESTROY_TIMEOUT; } +"McastSndSocketBuffer" { return T_MCAST_SNDBUFF; } +"McastRcvSocketBuffer" { return T_MCAST_RCVBUFF; } {is_on} { return T_ON; } {is_off} { return T_OFF; } diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 0bc5e3c..7fb3d5b 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -53,7 +53,7 @@ struct ct_conf conf; %token T_ESTABLISHED T_SYN_SENT T_SYN_RECV T_FIN_WAIT %token T_CLOSE_WAIT T_LAST_ACK T_TIME_WAIT T_CLOSE T_LISTEN %token T_SYSLOG T_WRITE_THROUGH T_STAT_BUFFER_SIZE T_DESTROY_TIMEOUT - +%token T_MCAST_RCVBUFF T_MCAST_SNDBUFF %token T_IP T_PATH_VAL %token T_NUMBER @@ -344,6 +344,16 @@ multicast_option : T_GROUP T_NUMBER conf.mcast.port = $2; }; +multicast_option: T_MCAST_SNDBUFF T_NUMBER +{ + conf.mcast.sndbuf = $2; +}; + +multicast_option: T_MCAST_RCVBUFF T_NUMBER +{ + conf.mcast.rcvbuf = $2; +}; + hashsize : T_HASHSIZE T_NUMBER { conf.hashsize = $2; diff --git a/src/sync-mode.c b/src/sync-mode.c index 7d73e2f..ad55adc 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -211,6 +211,9 @@ static int init_sync(void) return -1; } + dlog(LOG_NOTICE, "multicast server socket receiver queue " + "has been set to %d bytes", CONFIG(mcast).rcvbuf); + /* multicast client to send events on the wire */ STATE_SYNC(mcast_client) = mcast_client_create(&CONFIG(mcast)); if (STATE_SYNC(mcast_client) == NULL) { @@ -219,6 +222,9 @@ static int init_sync(void) return -1; } + dlog(LOG_NOTICE, "multicast client socket sender queue " + "has been set to %d bytes", CONFIG(mcast).sndbuf); + if (mcast_buffered_init(&CONFIG(mcast)) == -1) { dlog(LOG_ERR, "can't init tx buffer!"); mcast_server_destroy(STATE_SYNC(mcast_server)); -- cgit v1.2.3 From 768a0835e47472a99af14707ec84ea9184b6577d Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 20 May 2008 18:12:34 +0200 Subject: Updates (-U) show the effect of the operation in the conntrack entry --- src/conntrack.c | 47 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index 9ab4558..8ce1dae 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -720,17 +720,35 @@ static int delete_cb(enum nf_conntrack_msg_type type, return NFCT_CB_CONTINUE; } +static int print_cb(enum nf_conntrack_msg_type type, + struct nf_conntrack *ct, + void *data) +{ + char buf[1024]; + unsigned int op_type = NFCT_O_DEFAULT; + unsigned int op_flags = 0; + + if (output_mask & _O_XML) + op_type = NFCT_O_XML; + if (output_mask & _O_EXT) + op_flags = NFCT_OF_SHOW_LAYER3; + if (output_mask & _O_ID) + op_flags |= NFCT_OF_ID; + + nfct_snprintf(buf, 1024, ct, NFCT_T_UNKNOWN, op_type, op_flags); + printf("%s\n", buf); + + return NFCT_CB_CONTINUE; +} + static int update_cb(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data) { int res; - char buf[1024]; struct nf_conntrack *obj = data; char __tmp[nfct_maxsize()]; struct nf_conntrack *tmp = (struct nf_conntrack *) (void *)__tmp; - unsigned int op_type = NFCT_O_DEFAULT; - unsigned int op_flags = 0; memcpy(tmp, obj, sizeof(__tmp)); @@ -754,15 +772,22 @@ static int update_cb(enum nf_conntrack_msg_type type, "Operation failed: %s", err2str(errno, CT_UPDATE)); - if (output_mask & _O_XML) - op_type = NFCT_O_XML; - if (output_mask & _O_EXT) - op_flags = NFCT_OF_SHOW_LAYER3; - if (output_mask & _O_ID) - op_flags |= NFCT_OF_ID; + nfct_callback_register(ith, NFCT_T_ALL, print_cb, NULL); - nfct_snprintf(buf, 1024, ct, NFCT_T_UNKNOWN, op_type, op_flags); - printf("%s\n", buf); + res = nfct_query(ith, NFCT_Q_GET, tmp); + if (res < 0) { + /* the entry has vanish in middle of the update */ + if (errno == ENOENT) { + nfct_callback_unregister(ith); + return NFCT_CB_CONTINUE; + } + + exit_error(OTHER_PROBLEM, + "Operation failed: %s", + err2str(errno, CT_UPDATE)); + } + + nfct_callback_unregister(ith); counter++; -- cgit v1.2.3 From 599e63ea72995ff36d445cd5bd9849ecdd4590ae Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 21 May 2008 13:21:49 +0200 Subject: check for missing IPv6 address before hashing --- src/cache.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src') diff --git a/src/cache.c b/src/cache.c index 4162661..ed76680 100644 --- a/src/cache.c +++ b/src/cache.c @@ -75,6 +75,14 @@ static uint32_t hash(const void *data, struct hashtable *table) ret = __hash4(u->ct, table); break; case AF_INET6: + if (!nfct_attr_is_set(u->ct, ATTR_ORIG_IPV6_SRC) || + !nfct_attr_is_set(u->ct, ATTR_ORIG_IPV6_DST)) { + dlog(LOG_ERR, "missing IPv6 address. " + "You forgot to load " + "nf_conntrack_ipv6?"); + return 0; + } + ret = __hash6(u->ct, table); break; default: -- cgit v1.2.3 From 5f19f9a20d4bde74e2f95a670d766fc98c7d8684 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 22 May 2008 14:32:05 +0200 Subject: only allow the use of --secmark for listing (filtering) add missing string.h required by strdup in config parsing --- ChangeLog | 2 ++ src/conntrack.c | 6 +++--- src/read_config_lex.l | 2 ++ 3 files changed, 7 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 0b30f4f..e0a02a7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -15,6 +15,7 @@ o check for missing source/address IP/ports in creation and get operations o way more flexible conntrack updates and deletions o fix NAT filtering via --src-nat and --dst-nat (reported by K.Oledzki) o recover the ID support +o only allow the use of --secmark for listing (filtering) o show display counters to stderr o enable filtering by status and ID o update manpage @@ -31,6 +32,7 @@ o use generic nfct_copy() from libnetfilter_conntrack to update objects o use generic nfct_cmp() to compare objects o improve network message sanity checkings o add Mcast[Snd|Rcv]SocketBuffer clauses to tune multicast socket buffers +o add missing string.h required by strdup in config parsing version 0.9.6 (2008/03/08) ------------------------------ diff --git a/src/conntrack.c b/src/conntrack.c index 8ce1dae..25a3a57 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -122,9 +122,9 @@ static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = { /* s d r q p t u z e [ ] { } a m i f n g o c */ /*CT_LIST*/ {2,2,2,2,2,0,2,2,0,0,0,0,0,0,2,0,2,2,2,2,2}, -/*CT_CREATE*/ {2,2,2,2,1,1,1,0,0,0,0,0,0,2,2,0,0,2,2,0,2}, -/*CT_UPDATE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,2}, -/*CT_DELETE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,2}, +/*CT_CREATE*/ {2,2,2,2,1,1,1,0,0,0,0,0,0,2,2,0,0,2,2,0,0}, +/*CT_UPDATE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,0}, +/*CT_DELETE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,0}, /*CT_GET*/ {2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,2,0,0,0,2,0}, /*CT_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, /*CT_EVENT*/ {2,2,2,2,2,0,0,0,2,0,0,0,0,0,2,0,0,2,2,2,2}, diff --git a/src/read_config_lex.l b/src/read_config_lex.l index eb3368a..7daaeab 100644 --- a/src/read_config_lex.l +++ b/src/read_config_lex.l @@ -19,6 +19,8 @@ * Description: configuration file syntax */ +#include + #include "read_config_yy.h" %} -- cgit v1.2.3 From ed49d60424a18635c31dafc77e2cb720f75cc4ff Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 25 May 2008 15:14:31 +0200 Subject: add eventfd emulation to communicate receiver -> sender --- ChangeLog | 1 + include/Makefile.am | 2 +- include/conntrackd.h | 1 + include/event.h | 14 ++++++++++ src/Makefile.am | 2 +- src/event.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/sync-ftfw.c | 5 ++++ src/sync-mode.c | 28 +++++++++++++++----- 8 files changed, 117 insertions(+), 9 deletions(-) create mode 100644 include/event.h create mode 100644 src/event.c (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 2d4f332..dec7537 100644 --- a/ChangeLog +++ b/ChangeLog @@ -34,6 +34,7 @@ o use generic nfct_cmp() to compare objects o improve network message sanity checkings o add Mcast[Snd|Rcv]SocketBuffer clauses to tune multicast socket buffers o add missing string.h required by strdup in config parsing +o add eventfd emulation to communicate receiver -> sender version 0.9.6 (2008/03/08) ------------------------------ diff --git a/include/Makefile.am b/include/Makefile.am index 92ebbcc..d68f10a 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -3,5 +3,5 @@ noinst_HEADERS = alarm.h jhash.h slist.h cache.h linux_list.h linux_rbtree.h \ sync.h conntrackd.h local.h us-conntrack.h \ debug.h log.h hash.h mcast.h conntrack.h \ state_helper.h network.h ignore.h queue.h \ - traffic_stats.h netlink.h fds.h + traffic_stats.h netlink.h fds.h eventfd.h diff --git a/include/conntrackd.h b/include/conntrackd.h index b266289..c7a65be 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -125,6 +125,7 @@ struct ct_sync_state { struct mcast_sock *mcast_server; /* multicast socket: incoming */ struct mcast_sock *mcast_client; /* multicast socket: outgoing */ + struct evfd *evfd; /* event fd */ struct sync_mode *sync; /* sync mode */ diff --git a/include/event.h b/include/event.h new file mode 100644 index 0000000..b6bff5a --- /dev/null +++ b/include/event.h @@ -0,0 +1,14 @@ +#ifndef _EVENT_H_ +#define _EVENT_H_ + +struct evfd *create_evfd(void); + +void destroy_evfd(struct evfd *e); + +int get_read_evfd(struct evfd *evfd); + +int write_evfd(struct evfd *evfd); + +int read_evfd(struct evfd *evfd); + +#endif diff --git a/src/Makefile.am b/src/Makefile.am index d3fc020..554074f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -12,7 +12,7 @@ conntrack_LDFLAGS = $(all_libraries) @LIBNETFILTER_CONNTRACK_LIBS@ conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c rbtree.c \ local.c log.c mcast.c netlink.c \ - ignore_pool.c fds.c \ + ignore_pool.c fds.c event.c \ cache.c cache_iterators.c \ cache_lifetime.c cache_timer.c cache_wt.c \ sync-mode.c sync-alarm.c sync-ftfw.c \ diff --git a/src/event.c b/src/event.c new file mode 100644 index 0000000..ed78835 --- /dev/null +++ b/src/event.c @@ -0,0 +1,73 @@ +/* + * (C) 2006-2007 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include + +#include "event.h" + +struct evfd { + int read; + int fds[2]; +}; + +struct evfd *create_evfd(void) +{ + struct evfd *e; + + e = calloc(1, sizeof(struct evfd)); + if (e == NULL) + return NULL; + + if (pipe(e->fds) == -1) { + free(e); + return NULL; + } + + return e; +} + +void destroy_evfd(struct evfd *e) +{ + close(e->fds[0]); + close(e->fds[1]); + free(e); +} + +int get_read_evfd(struct evfd *evfd) +{ + return evfd->fds[0]; +} + +int write_evfd(struct evfd *evfd) +{ + int data = 0; + + if (evfd->read) + return 0; + + evfd->read = 1; + return write(evfd->fds[1], &data, sizeof(data)); +} + +int read_evfd(struct evfd *evfd) +{ + int data; + + evfd->read = 0; + return read(evfd->fds[0], &data, sizeof(data)); +} diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 77f8fd4..adfdda9 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -25,6 +25,7 @@ #include "alarm.h" #include "log.h" #include "cache.h" +#include "event.h" #include @@ -97,6 +98,7 @@ static void tx_queue_add_ctlmsg(uint32_t flags, uint32_t from, uint32_t to) }; queue_add(tx_queue, &ack, NETHDR_ACK_SIZ); + write_evfd(STATE_SYNC(evfd)); } static void ftfw_run(void); @@ -191,6 +193,7 @@ static int do_cache_to_tx(void *data1, void *data2) /* add to tx list */ list_add_tail(&cn->tx_list, &tx_list); tx_list_len++; + write_evfd(STATE_SYNC(evfd)); return 0; } @@ -225,6 +228,7 @@ static int rs_queue_to_tx(void *data1, const void *data2) dp("rs_queue_to_tx sq: %u fl:%u len:%u\n", net->seq, net->flags, net->len); queue_add(tx_queue, net, net->len); + write_evfd(STATE_SYNC(evfd)); queue_del(rs_queue, net); } return 0; @@ -256,6 +260,7 @@ static void rs_list_to_tx(struct cache *c, unsigned int from, unsigned int to) rs_list_len--; list_add_tail(&cn->tx_list, &tx_list); tx_list_len++; + write_evfd(STATE_SYNC(evfd)); } } } diff --git a/src/sync-mode.c b/src/sync-mode.c index ad55adc..2fe7406 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -26,6 +26,7 @@ #include "us-conntrack.h" #include "network.h" #include "fds.h" +#include "event.h" #include "debug.h" #include @@ -232,6 +233,12 @@ static int init_sync(void) return -1; } + STATE_SYNC(evfd) = create_evfd(); + if (STATE_SYNC(evfd) == NULL) { + dlog(LOG_ERR, "cannot open evfd"); + return -1; + } + /* initialization of multicast sequence generation */ STATE_SYNC(last_seq_sent) = time(NULL); @@ -240,21 +247,26 @@ static int init_sync(void) static int register_fds_sync(struct fds *fds) { - return register_fd(STATE_SYNC(mcast_server->fd), fds); + if (register_fd(STATE_SYNC(mcast_server->fd), fds) == -1) + return -1; + + return register_fd(get_read_evfd(STATE_SYNC(evfd)), fds); } static void run_sync(fd_set *readfds) { /* multicast packet has been received */ - if (FD_ISSET(STATE_SYNC(mcast_server->fd), readfds)) { + if (FD_ISSET(STATE_SYNC(mcast_server->fd), readfds)) mcast_handler(); - if (STATE_SYNC(sync)->run) - STATE_SYNC(sync)->run(); - - /* flush pending messages */ - mcast_buffered_pending_netmsg(STATE_SYNC(mcast_client)); + if (FD_ISSET(get_read_evfd(STATE_SYNC(evfd)), readfds) && + STATE_SYNC(sync)->run) { + read_evfd(STATE_SYNC(evfd)); + STATE_SYNC(sync)->run(); } + + /* flush pending messages */ + mcast_buffered_pending_netmsg(STATE_SYNC(mcast_client)); } static void kill_sync(void) @@ -265,6 +277,8 @@ static void kill_sync(void) mcast_server_destroy(STATE_SYNC(mcast_server)); mcast_client_destroy(STATE_SYNC(mcast_client)); + destroy_evfd(STATE_SYNC(evfd)); + mcast_buffered_destroy(); if (STATE_SYNC(sync)->kill) -- cgit v1.2.3 From f152340a26912d090b5fd15be10208605929816b Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 25 May 2008 20:36:54 +0200 Subject: add best effort replication protocol (aka NOTRACK) --- ChangeLog | 1 + doc/sync/notrack/README | 2 + doc/sync/notrack/node1/conntrackd.conf | 150 +++++++++++++++++++++++++++ doc/sync/notrack/node1/keepalived.conf | 39 +++++++ doc/sync/notrack/node2/conntrackd.conf | 149 ++++++++++++++++++++++++++ doc/sync/notrack/node2/keepalived.conf | 39 +++++++ doc/sync/notrack/script_backup.sh | 3 + doc/sync/notrack/script_master.sh | 5 + include/conntrackd.h | 1 + src/Makefile.am | 2 +- src/read_config_lex.l | 2 + src/read_config_yy.y | 15 ++- src/sync-mode.c | 2 + src/sync-notrack.c | 184 +++++++++++++++++++++++++++++++++ 14 files changed, 592 insertions(+), 2 deletions(-) create mode 100644 doc/sync/notrack/README create mode 100644 doc/sync/notrack/node1/conntrackd.conf create mode 100644 doc/sync/notrack/node1/keepalived.conf create mode 100644 doc/sync/notrack/node2/conntrackd.conf create mode 100644 doc/sync/notrack/node2/keepalived.conf create mode 100644 doc/sync/notrack/script_backup.sh create mode 100644 doc/sync/notrack/script_master.sh create mode 100644 src/sync-notrack.c (limited to 'src') diff --git a/ChangeLog b/ChangeLog index dec7537..597206a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -35,6 +35,7 @@ o improve network message sanity checkings o add Mcast[Snd|Rcv]SocketBuffer clauses to tune multicast socket buffers o add missing string.h required by strdup in config parsing o add eventfd emulation to communicate receiver -> sender +o add best effort replication protocol (aka NOTRACK) version 0.9.6 (2008/03/08) ------------------------------ diff --git a/doc/sync/notrack/README b/doc/sync/notrack/README new file mode 100644 index 0000000..99b2f33 --- /dev/null +++ b/doc/sync/notrack/README @@ -0,0 +1,2 @@ +This directory contains the files for the NOTRACK replication protocol. This +protocol provides best effort delivery. Therefore, it is unreliable. diff --git a/doc/sync/notrack/node1/conntrackd.conf b/doc/sync/notrack/node1/conntrackd.conf new file mode 100644 index 0000000..1185351 --- /dev/null +++ b/doc/sync/notrack/node1/conntrackd.conf @@ -0,0 +1,150 @@ +# +# Synchronizer settings +# +Sync { + Mode NOTRACK { + # + # Entries committed to the connection tracking table + # starts with a limited timeout of N seconds until the + # takeover process is completed. + # + CommitTimeout 180 + } + + # + # Multicast IP and interface where messages are + # broadcasted (dedicated link). IMPORTANT: Make sure + # that iptables accepts traffic for destination + # 225.0.0.50, eg: + # + # iptables -I INPUT -d 225.0.0.50 -j ACCEPT + # iptables -I OUTPUT -d 225.0.0.50 -j ACCEPT + # + Multicast { + IPv4_address 225.0.0.50 + IPv4_interface 192.168.100.100 # IP of dedicated link + Interface eth2 + Group 3780 + + # The multicast sender uses a buffer to enqueue the packets + # that are going to be transmitted. The default size of this + # socket buffer is available at /proc/sys/net/core/wmem_default. + # This value determines the chances to have an overrun in the + # sender queue. The overrun results packet loss, thus, losing + # state information that would have to be retransmitted. If you + # notice some packet loss, you may want to increase the size + # of the sender buffer. Note: This protocol is best effort, + # really recommended to increase the buffer size. + + McastSndSocketBuffer 1249280 + + # The multicast receiver uses a buffer to enqueue the packets + # that the socket is pending to handle. The default size of this + # socket buffer is available at /proc/sys/net/core/rmem_default. + # This value determines the chances to have an overrun in the + # receiver queue. The overrun results packet loss, thus, losing + # state information that would have to be retransmitted. If you + # notice some packet loss, you may want to increase the size of + # the receiver buffer. Note: This protocol is best effort, + # really recommended to increase the buffer size. + + McastRcvSocketBuffer 1249280 + } + + # Enable/Disable message checksumming + Checksum on + + # Uncomment this if you want to replicate just certain TCP states. + # This option introduces a tradeoff in the replication: it reduces + # CPU consumption and lost messages rate at the cost of having + # backup replicas that don't contain the current state that the active + # replica holds. TCP states are: SYN_SENT, SYN_RECV, ESTABLISHED, + # FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN. + # + # Replicate ESTABLISHED TIME_WAIT for TCP + + # If you have a multiprimary setup (active-active) without connection + # persistency, ie. you can't know which firewall handles a packet + # that is part of a connection, then you need direct commit of + # conntrack entries to the kernel conntrack table. OSPF setups must + # set on this option. Default is Off. + # + # CacheWriteThrough On +} + +# +# General settings +# +General { + # + # Number of buckets in the caches: hash table + # + HashSize 8192 + + # + # Maximum number of conntracks: + # it must be >= $ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max + # + HashLimit 65535 + + # + # Logfile: on, off, or a filename + # Default: on (/var/log/conntrackd.log) + # + #LogFile off + + # + # Syslog: on, off or a facility name (daemon (default) or local0..7) + # Default: off + # + #Syslog on + + # + # Lockfile + # + LockFile /var/lock/conntrack.lock + + # + # Unix socket configuration + # + UNIX { + Path /tmp/sync.sock + Backlog 20 + } + + # + # Netlink socket buffer size + # + SocketBufferSize 262142 + + # + # Increase the socket buffer up to maximum if required + # + SocketBufferSizeMaxGrown 655355 +} + +# +# Ignore traffic for a certain set of IP's: Usually +# all the IP assigned to the firewall since local +# traffic must be ignored, just forwarded connections +# are worth to replicate +# +IgnoreTrafficFor { + IPv4_address 127.0.0.1 # loopback + IPv4_address 192.168.0.1 + IPv4_address 192.168.1.1 + IPv4_address 192.168.100.100 # dedicated link ip + IPv4_address 192.168.0.100 # virtual IP 1 + IPv4_address 192.168.1.100 # virtual IP 2 +} + +# +# Do not replicate certain protocol traffic +# +IgnoreProtocol { + UDP + ICMP + IGMP + VRRP + # numeric numbers also valid +} diff --git a/doc/sync/notrack/node1/keepalived.conf b/doc/sync/notrack/node1/keepalived.conf new file mode 100644 index 0000000..f937467 --- /dev/null +++ b/doc/sync/notrack/node1/keepalived.conf @@ -0,0 +1,39 @@ +vrrp_sync_group G1 { # must be before vrrp_instance declaration + group { + VI_1 + VI_2 + } + notify_master /etc/conntrackd/script_master.sh + notify_backup /etc/conntrackd/script_backup.sh +# notify_fault /etc/conntrackd/script_fault.sh +} + +vrrp_instance VI_1 { + interface eth1 + state SLAVE + virtual_router_id 61 + priority 80 + advert_int 3 + authentication { + auth_type PASS + auth_pass papas_con_tomate + } + virtual_ipaddress { + 192.168.0.100 # default CIDR mask is /32 + } +} + +vrrp_instance VI_2 { + interface eth0 + state SLAVE + virtual_router_id 62 + priority 80 + advert_int 3 + authentication { + auth_type PASS + auth_pass papas_con_tomate + } + virtual_ipaddress { + 192.168.1.100 + } +} diff --git a/doc/sync/notrack/node2/conntrackd.conf b/doc/sync/notrack/node2/conntrackd.conf new file mode 100644 index 0000000..7881d46 --- /dev/null +++ b/doc/sync/notrack/node2/conntrackd.conf @@ -0,0 +1,149 @@ +# +# Synchronizer settings +# +Sync { + Mode NOTRACK { + # Entries committed to the connection tracking table + # starts with a limited timeout of N seconds until the + # takeover process is completed. + # + CommitTimeout 180 + } + + # + # Multicast IP and interface where messages are + # broadcasted (dedicated link). IMPORTANT: Make sure + # that iptables accepts traffic for destination + # 225.0.0.50, eg: + # + # iptables -I INPUT -d 225.0.0.50 -j ACCEPT + # iptables -I OUTPUT -d 225.0.0.50 -j ACCEPT + # + Multicast { + IPv4_address 225.0.0.50 + IPv4_interface 192.168.100.200 # IP of dedicated link + Interface eth2 + Group 3780 + + # The multicast sender uses a buffer to enqueue the packets + # that are going to be transmitted. The default size of this + # socket buffer is available at /proc/sys/net/core/wmem_default. + # This value determines the chances to have an overrun in the + # sender queue. The overrun results packet loss, thus, losing + # state information that would have to be retransmitted. If you + # notice some packet loss, you may want to increase the size + # of the sender buffer. Note: This protocol is best effort, + # really recommended to increase the buffer size. + + McastSndSocketBuffer 1249280 + + # The multicast receiver uses a buffer to enqueue the packets + # that the socket is pending to handle. The default size of this + # socket buffer is available at /proc/sys/net/core/rmem_default. + # This value determines the chances to have an overrun in the + # receiver queue. The overrun results packet loss, thus, losing + # state information that would have to be retransmitted. If you + # notice some packet loss, you may want to increase the size of + # the receiver buffer. Note: This protocol is best effort, + # really recommended to increase the buffer size. + + McastRcvSocketBuffer 1249280 + } + + # Enable/Disable message checksumming + Checksum on + + # Uncomment this if you want to replicate just certain TCP states. + # This option introduces a tradeoff in the replication: it reduces + # CPU consumption and lost messages rate at the cost of having + # backup replicas that don't contain the current state that the active + # replica holds. TCP states are: SYN_SENT, SYN_RECV, ESTABLISHED, + # FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSE, LISTEN. + # + # Replicate ESTABLISHED TIME_WAIT for TCP + + # If you have a multiprimary setup (active-active) without connection + # persistency, ie. you can't know which firewall handles a packet + # that is part of a connection, then you need direct commit of + # conntrack entries to the kernel conntrack table. OSPF setups must + # set on this option. Default is Off. + # + # CacheWriteThrough On +} + +# +# General settings +# +General { + # + # Number of buckets in the caches: hash table + # + HashSize 8192 + + # + # Maximum number of conntracks: + # it must be >= $ cat /proc/sys/net/ipv4/netfilter/ip_conntrack_max + # + HashLimit 65535 + + # + # Logfile: on, off, or a filename + # Default: on (/var/log/conntrackd.log) + # + #LogFile off + + # + # Syslog: on, off or a facility name (daemon (default) or local0..7) + # Default: off + # + #Syslog on + + # + # Lockfile + # + LockFile /var/lock/conntrack.lock + + # + # Unix socket configuration + # + UNIX { + Path /tmp/sync.sock + Backlog 20 + } + + # + # Netlink socket buffer size + # + SocketBufferSize 262142 + + # + # Increase the socket buffer up to maximum if required + # + SocketBufferSizeMaxGrown 655355 +} + +# +# Ignore traffic for a certain set of IP's: Usually +# all the IP assigned to the firewall since local +# traffic must be ignored, just forwarded connections +# are worth to replicate +# +IgnoreTrafficFor { + IPv4_address 127.0.0.1 # loopback + IPv4_address 192.168.0.2 + IPv4_address 192.168.1.2 + IPv4_address 192.168.100.200 # dedicated link ip + IPv4_address 192.168.0.200 # virtual IP 1 + IPv4_address 192.168.1.200 # virtual IP 2 +} + +# +# Do not replicate certain protocol traffic +# +IgnoreProtocol { + UDP + ICMP + IGMP + VRRP + # numeric numbers also valid +} diff --git a/doc/sync/notrack/node2/keepalived.conf b/doc/sync/notrack/node2/keepalived.conf new file mode 100644 index 0000000..f937467 --- /dev/null +++ b/doc/sync/notrack/node2/keepalived.conf @@ -0,0 +1,39 @@ +vrrp_sync_group G1 { # must be before vrrp_instance declaration + group { + VI_1 + VI_2 + } + notify_master /etc/conntrackd/script_master.sh + notify_backup /etc/conntrackd/script_backup.sh +# notify_fault /etc/conntrackd/script_fault.sh +} + +vrrp_instance VI_1 { + interface eth1 + state SLAVE + virtual_router_id 61 + priority 80 + advert_int 3 + authentication { + auth_type PASS + auth_pass papas_con_tomate + } + virtual_ipaddress { + 192.168.0.100 # default CIDR mask is /32 + } +} + +vrrp_instance VI_2 { + interface eth0 + state SLAVE + virtual_router_id 62 + priority 80 + advert_int 3 + authentication { + auth_type PASS + auth_pass papas_con_tomate + } + virtual_ipaddress { + 192.168.1.100 + } +} diff --git a/doc/sync/notrack/script_backup.sh b/doc/sync/notrack/script_backup.sh new file mode 100644 index 0000000..813e375 --- /dev/null +++ b/doc/sync/notrack/script_backup.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +/usr/sbin/conntrackd -n # request a resync from other nodes via multicast diff --git a/doc/sync/notrack/script_master.sh b/doc/sync/notrack/script_master.sh new file mode 100644 index 0000000..ff1dbc0 --- /dev/null +++ b/doc/sync/notrack/script_master.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +/usr/sbin/conntrackd -c # commit the cache +/usr/sbin/conntrackd -f # flush the caches +/usr/sbin/conntrackd -R # resync with kernel conntrack table diff --git a/include/conntrackd.h b/include/conntrackd.h index c7a65be..8a6e8d2 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -51,6 +51,7 @@ enum { #define CTD_STATS_MODE (1UL << 1) #define CTD_SYNC_FTFW (1UL << 2) #define CTD_SYNC_ALARM (1UL << 3) +#define CTD_SYNC_NOTRACK (1UL << 4) /* FILENAME_MAX is 4096 on my system, perhaps too much? */ #ifndef FILENAME_MAXLEN diff --git a/src/Makefile.am b/src/Makefile.am index 554074f..69ddcfd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -15,7 +15,7 @@ conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c rbtree.c \ ignore_pool.c fds.c event.c \ cache.c cache_iterators.c \ cache_lifetime.c cache_timer.c cache_wt.c \ - sync-mode.c sync-alarm.c sync-ftfw.c \ + sync-mode.c sync-alarm.c sync-ftfw.c sync-notrack.c \ traffic_stats.c stats-mode.c \ network.c \ state_helper.c state_helper_tcp.c \ diff --git a/src/read_config_lex.l b/src/read_config_lex.l index 7daaeab..bdde3b6 100644 --- a/src/read_config_lex.l +++ b/src/read_config_lex.l @@ -49,6 +49,7 @@ persistent [P|p][E|e][R|r][S|s][I|i][S|s][T|t][E|e][N|n][T|T] nack [N|n][A|a][C|c][K|k] alarm [A|a][L|l][A|a][R|r][M|m] ftfw [F|f][T|t][F|f][W|w] +notrack [N|n][O|o][T|t][R|r][A|a][C|c][K|k] %% "UNIX" { return T_UNIX; } @@ -125,6 +126,7 @@ ftfw [F|f][T|t][F|f][W|w] "is called `ftfw'. Please, update " "your conntrackd.conf file.\n"); return T_FTFW; } +{notrack} { return T_NOTRACK; } {string} { yylval.string = strdup(yytext); return T_STRING; } {comment} ; diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 7fb3d5b..b9c53be 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -53,7 +53,7 @@ struct ct_conf conf; %token T_ESTABLISHED T_SYN_SENT T_SYN_RECV T_FIN_WAIT %token T_CLOSE_WAIT T_LAST_ACK T_TIME_WAIT T_CLOSE T_LISTEN %token T_SYSLOG T_WRITE_THROUGH T_STAT_BUFFER_SIZE T_DESTROY_TIMEOUT -%token T_MCAST_RCVBUFF T_MCAST_SNDBUFF +%token T_MCAST_RCVBUFF T_MCAST_SNDBUFF T_NOTRACK %token T_IP T_PATH_VAL %token T_NUMBER @@ -436,6 +436,7 @@ sync_line: refreshtime | delay_destroy_msgs | sync_mode_alarm | sync_mode_ftfw + | sync_mode_notrack | listen_to | state_replication | cache_writethrough @@ -452,6 +453,11 @@ sync_mode_ftfw: T_SYNC_MODE T_FTFW '{' sync_mode_ftfw_list '}' conf.flags |= CTD_SYNC_FTFW; }; +sync_mode_notrack: T_SYNC_MODE T_NOTRACK '{' sync_mode_notrack_list '}' +{ + conf.flags |= CTD_SYNC_NOTRACK; +}; + sync_mode_alarm_list: | sync_mode_alarm_list sync_mode_alarm_line; @@ -470,6 +476,13 @@ sync_mode_ftfw_line: resend_queue_size | window_size ; +sync_mode_notrack_list: + | sync_mode_notrack_list sync_mode_notrack_line; + +sync_mode_notrack_line: timeout + ; + + resend_queue_size: T_RESEND_BUFFER_SIZE T_NUMBER { conf.resend_queue_size = $2; diff --git a/src/sync-mode.c b/src/sync-mode.c index 2fe7406..16cc70d 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -169,6 +169,8 @@ static int init_sync(void) STATE_SYNC(sync) = &sync_ftfw; else if (CONFIG(flags) & CTD_SYNC_ALARM) STATE_SYNC(sync) = &sync_alarm; + else if (CONFIG(flags) & CTD_SYNC_NOTRACK) + STATE_SYNC(sync) = &sync_notrack; else { fprintf(stderr, "WARNING: No synchronization mode specified. " "Defaulting to FT-FW mode.\n"); diff --git a/src/sync-notrack.c b/src/sync-notrack.c new file mode 100644 index 0000000..2b1bc13 --- /dev/null +++ b/src/sync-notrack.c @@ -0,0 +1,184 @@ +/* + * (C) 2008 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "conntrackd.h" +#include "sync.h" +#include "us-conntrack.h" +#include "queue.h" +#include "debug.h" +#include "network.h" +#include "log.h" +#include "cache.h" +#include "event.h" + +#include + +static LIST_HEAD(tx_list); +static unsigned int tx_list_len; +static struct queue *tx_queue; + +struct cache_notrack { + struct list_head tx_list; +}; + +static struct cache_extra cache_notrack_extra = { + .size = sizeof(struct cache_notrack), +}; + +static void tx_queue_add_ctlmsg(uint32_t flags, uint32_t from, uint32_t to) +{ + struct nethdr_ack ack = { + .flags = flags, + .from = from, + .to = to, + }; + + queue_add(tx_queue, &ack, NETHDR_ACK_SIZ); + write_evfd(STATE_SYNC(evfd)); +} + +static int notrack_init(void) +{ + tx_queue = queue_create(~0U); + if (tx_queue == NULL) { + dlog(LOG_ERR, "cannot create tx queue"); + return -1; + } + + return 0; +} + +static void notrack_kill(void) +{ + queue_destroy(tx_queue); +} + +static int do_cache_to_tx(void *data1, void *data2) +{ + struct us_conntrack *u = data2; + struct cache_notrack *cn = cache_get_extra(STATE_SYNC(internal), u); + + /* add to tx list */ + list_add_tail(&cn->tx_list, &tx_list); + tx_list_len++; + + write_evfd(STATE_SYNC(evfd)); + + return 0; +} + +static int notrack_local(int fd, int type, void *data) +{ + int ret = 1; + + switch(type) { + case REQUEST_DUMP: + dlog(LOG_NOTICE, "request resync"); + tx_queue_add_ctlmsg(NET_F_RESYNC, 0, 0); + break; + case SEND_BULK: + dlog(LOG_NOTICE, "sending bulk update"); + cache_iterate(STATE_SYNC(internal), NULL, do_cache_to_tx); + break; + default: + ret = 0; + break; + } + + return ret; +} + +static int digest_msg(const struct nethdr *net) +{ + if (IS_DATA(net)) + return MSG_DATA; + + if (IS_RESYNC(net)) { + cache_iterate(STATE_SYNC(internal), NULL, do_cache_to_tx); + return MSG_CTL; + } + + return MSG_BAD; +} + +static int notrack_recv(const struct nethdr *net) +{ + int ret; + unsigned int exp_seq; + + mcast_track_seq(net->seq, &exp_seq); + + ret = digest_msg(net); + + if (ret != MSG_BAD) + mcast_track_update_seq(net->seq); + + return ret; +} + +static int tx_queue_xmit(void *data1, const void *data2) +{ + struct nethdr *net = data1; + size_t len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); + + mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); + queue_del(tx_queue, net); + + return 0; +} + +static int tx_list_xmit(struct list_head *i, struct us_conntrack *u, int type) +{ + int ret; + struct nethdr *net = BUILD_NETMSG(u->ct, type); + size_t len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); + + list_del_init(i); + tx_list_len--; + + ret = mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); + + return ret; +} + +static void notrack_run(void) +{ + struct cache_notrack *cn, *tmp; + + /* send messages in the tx_queue */ + queue_iterate(tx_queue, NULL, tx_queue_xmit); + + /* send conntracks in the tx_list */ + list_for_each_entry_safe(cn, tmp, &tx_list, tx_list) { + struct us_conntrack *u; + + u = cache_get_conntrack(STATE_SYNC(internal), cn); + tx_list_xmit(&cn->tx_list, u, NFCT_Q_UPDATE); + } +} + +struct sync_mode sync_notrack = { + .internal_cache_flags = LIFETIME, + .external_cache_flags = LIFETIME, + .internal_cache_extra = &cache_notrack_extra, + .init = notrack_init, + .kill = notrack_kill, + .local = notrack_local, + .recv = notrack_recv, + .run = notrack_run, +}; -- cgit v1.2.3 From e877faf2c1c557399a57a884a21133e607909b16 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 26 May 2008 02:24:03 +0200 Subject: rework the HELLO logic inside FT-FW --- ChangeLog | 1 + include/network.h | 12 +++++++++++- src/sync-ftfw.c | 50 ++++++++++++++++++++++++++++++++++++++++++++------ src/sync-mode.c | 4 +++- 4 files changed, 59 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 597206a..14ba054 100644 --- a/ChangeLog +++ b/ChangeLog @@ -36,6 +36,7 @@ o add Mcast[Snd|Rcv]SocketBuffer clauses to tune multicast socket buffers o add missing string.h required by strdup in config parsing o add eventfd emulation to communicate receiver -> sender o add best effort replication protocol (aka NOTRACK) +o rework the HELLO logic inside FT-FW version 0.9.6 (2008/03/08) ------------------------------ diff --git a/include/network.h b/include/network.h index baa1eba..777be11 100644 --- a/include/network.h +++ b/include/network.h @@ -31,6 +31,8 @@ enum { NET_F_NACK = (1 << 2), NET_F_ACK = (1 << 3), NET_F_ALIVE = (1 << 4), + NET_F_HELLO = (1 << 5), + NET_F_HELLO_BACK= (1 << 6), }; enum { @@ -63,6 +65,12 @@ enum { SEQ_BEFORE, }; +enum { + SAY_HELLO, + HELLO_BACK, + HELLO_DONE, +}; + int mcast_track_seq(uint32_t seq, uint32_t *exp_seq); void mcast_track_update_seq(uint32_t seq); int mcast_track_is_seq_set(void); @@ -74,12 +82,14 @@ void mcast_buffered_destroy(void); int mcast_buffered_send_netmsg(struct mcast_sock *m, void *data, size_t len); ssize_t mcast_buffered_pending_netmsg(struct mcast_sock *m); -#define IS_DATA(x) (x->flags == 0) +#define IS_DATA(x) ((x->flags & ~(NET_F_HELLO | NET_F_HELLO_BACK)) == 0) #define IS_ACK(x) (x->flags & NET_F_ACK) #define IS_NACK(x) (x->flags & NET_F_NACK) #define IS_RESYNC(x) (x->flags & NET_F_RESYNC) #define IS_ALIVE(x) (x->flags & NET_F_ALIVE) #define IS_CTL(x) IS_ACK(x) || IS_NACK(x) || IS_RESYNC(x) || IS_ALIVE(x) +#define IS_HELLO(x) (x->flags & NET_F_HELLO) +#define IS_HELLO_BACK(x)(x->flags & NET_F_HELLO_BACK) #define HDR_NETWORK2HOST(x) \ ({ \ diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index adfdda9..42005c4 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -52,6 +52,7 @@ static uint32_t window; static uint32_t ack_from; static int ack_from_set = 0; static struct alarm_block alive_alarm; +static int hello_state = SAY_HELLO; /* XXX: alive message expiration configurable */ #define ALIVE_INT 1 @@ -97,6 +98,16 @@ static void tx_queue_add_ctlmsg(uint32_t flags, uint32_t from, uint32_t to) .to = to, }; + switch(hello_state) { + case SAY_HELLO: + ack.flags |= NET_F_HELLO; + break; + case HELLO_BACK: + ack.flags |= NET_F_HELLO_BACK; + hello_state = HELLO_DONE; + break; + } + queue_add(tx_queue, &ack, NETHDR_ACK_SIZ); write_evfd(STATE_SYNC(evfd)); } @@ -315,10 +326,29 @@ static int digest_msg(const struct nethdr *net) return MSG_BAD; } +static int digest_hello(const struct nethdr *net) +{ + int ret = 0; + + if (IS_HELLO(net)) { + dlog(LOG_NOTICE, "The other node says HELLO"); + hello_state = HELLO_BACK; + ret = 1; + } else if (IS_HELLO_BACK(net)) { + dlog(LOG_NOTICE, "The other node says HELLO BACK"); + hello_state = HELLO_DONE; + } + + return ret; +} + static int ftfw_recv(const struct nethdr *net) { int ret = MSG_DATA; + if (digest_hello(net)) + goto bypass; + switch (mcast_track_seq(net->seq, &exp_seq)) { case SEQ_AFTER: ret = digest_msg(net); @@ -348,14 +378,12 @@ static int ftfw_recv(const struct nethdr *net) /* we don't accept delayed packets */ dlog(LOG_WARNING, "Received seq=%u before expected seq=%u", net->seq, exp_seq); - dlog(LOG_WARNING, "Probably the other node has come back" - "to life but you forgot to add " - "conntrackd -r to your scripts"); ret = MSG_DROP; break; case SEQ_UNSET: case SEQ_IN_SYNC: +bypass: ret = digest_msg(net); if (ret == MSG_BAD) { ret = MSG_BAD; @@ -390,8 +418,6 @@ static void ftfw_send(struct nethdr *net, struct us_conntrack *u) struct netpld *pld = NETHDR_DATA(net); struct cache_ftfw *cn; - HDR_NETWORK2HOST(net); - switch(ntohs(pld->query)) { case NFCT_Q_CREATE: case NFCT_Q_UPDATE: @@ -404,7 +430,19 @@ static void ftfw_send(struct nethdr *net, struct us_conntrack *u) rs_list_len--; } - cn->seq = net->seq; + switch(hello_state) { + case SAY_HELLO: + net->flags = ntohs(net->flags) | NET_F_HELLO; + net->flags = htons(net->flags); + break; + case HELLO_BACK: + net->flags = ntohs(net->flags) | NET_F_HELLO_BACK; + net->flags = htons(net->flags); + hello_state = HELLO_DONE; + break; + } + + cn->seq = ntohl(net->seq); list_add_tail(&cn->rs_list, &rs_list); rs_list_len++; break; diff --git a/src/sync-mode.c b/src/sync-mode.c index 16cc70d..4b36935 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -395,9 +395,11 @@ static void mcast_send_sync(struct us_conntrack *u, int query) net = BUILD_NETMSG(u->ct, query); len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); + if (STATE_SYNC(sync)->send) STATE_SYNC(sync)->send(net, u); + + mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); } static int purge_step(void *data1, void *data2) -- cgit v1.2.3 From 5b6627353e2bda89aa506b4573b3fc0d0aa28668 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 26 May 2008 02:31:24 +0200 Subject: fix leak in cache_destroy(): release objects before destroying the cache --- ChangeLog | 1 + src/cache.c | 1 + 2 files changed, 2 insertions(+) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 14ba054..2713ac7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -37,6 +37,7 @@ o add missing string.h required by strdup in config parsing o add eventfd emulation to communicate receiver -> sender o add best effort replication protocol (aka NOTRACK) o rework the HELLO logic inside FT-FW +o fix leak in cache_destroy(): release objects before destroying the cache version 0.9.6 (2008/03/08) ------------------------------ diff --git a/src/cache.c b/src/cache.c index ed76680..fe5fd27 100644 --- a/src/cache.c +++ b/src/cache.c @@ -176,6 +176,7 @@ struct cache *cache_create(const char *name, void cache_destroy(struct cache *c) { + cache_flush(c); hashtable_destroy(c->h); free(c->features); free(c->feature_offset); -- cgit v1.2.3 From 9f0533cd09b9483aff53b340aded88d0cab32d8c Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 27 May 2008 18:21:40 +0200 Subject: remove secmark support for conntrackd --- src/build.c | 2 -- src/parse.c | 1 - 2 files changed, 3 deletions(-) (limited to 'src') diff --git a/src/build.c b/src/build.c index 6363458..be33c86 100644 --- a/src/build.c +++ b/src/build.c @@ -109,8 +109,6 @@ void build_netpld(struct nf_conntrack *ct, struct netpld *pld, int query) __build_u32(ct, pld, ATTR_TIMEOUT); if (nfct_attr_is_set(ct, ATTR_MARK)) __build_u32(ct, pld, ATTR_MARK); - if (nfct_attr_is_set(ct, ATTR_SECMARK)) - __build_u32(ct, pld, ATTR_SECMARK); if (nfct_attr_is_set(ct, ATTR_STATUS)) __build_u32(ct, pld, ATTR_STATUS); diff --git a/src/parse.c b/src/parse.c index 645420d..b14e487 100644 --- a/src/parse.c +++ b/src/parse.c @@ -66,7 +66,6 @@ static parse h[ATTR_MAX] = { [ATTR_TIMEOUT] = parse_u32, [ATTR_MARK] = parse_u32, [ATTR_STATUS] = parse_u32, - [ATTR_SECMARK] = parse_u32, [ATTR_MASTER_IPV4_SRC] = parse_u32, [ATTR_MASTER_IPV4_DST] = parse_u32, [ATTR_MASTER_L3PROTO] = parse_u8, -- cgit v1.2.3 From 96fad1b1ca9e6e34e439cdb9eaecb765fb107ea8 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 27 May 2008 20:23:19 +0200 Subject: define SO_[RCV|SND]BUFFORCE if not set --- src/mcast.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src') diff --git a/src/mcast.c b/src/mcast.c index 16d8856..2bb8743 100644 --- a/src/mcast.c +++ b/src/mcast.c @@ -98,6 +98,10 @@ struct mcast_sock *mcast_server_create(struct mcast_conf *conf) return NULL; } +#ifndef SO_RCVBUFFORCE +#define SO_RCVBUFFORCE 33 +#endif + if (conf->rcvbuf && setsockopt(m->fd, SOL_SOCKET, SO_RCVBUFFORCE, &conf->rcvbuf, sizeof(int)) == -1) { @@ -232,6 +236,10 @@ struct mcast_sock *mcast_client_create(struct mcast_conf *conf) return NULL; } +#ifndef SO_SNDBUFFORCE +#define SO_SNDBUFFORCE 32 +#endif + if (conf->sndbuf && setsockopt(m->fd, SOL_SOCKET, SO_SNDBUFFORCE, &conf->sndbuf, sizeof(int)) == -1) { -- cgit v1.2.3 From db4f1eb7b2c6cfa32ef76ba6be05d5ff9a2fca87 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 31 May 2008 16:58:58 +0200 Subject: increase deletion stats when the timer is scheduled in cache_del_timeout() --- src/cache.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/cache.c b/src/cache.c index fe5fd27..c72afd8 100644 --- a/src/cache.c +++ b/src/cache.c @@ -360,10 +360,8 @@ int cache_del(struct cache *c, struct nf_conntrack *ct) static void __del_timeout(struct alarm_block *a, void *data) { struct us_conntrack *u = (struct us_conntrack *) data; - struct cache *c = u->cache; __del2(u->cache, u); - c->del_ok++; } struct us_conntrack * @@ -382,6 +380,13 @@ cache_del_timeout(struct cache *c, struct nf_conntrack *ct, int timeout) if (u) { if (!alarm_pending(&u->alarm)) { add_alarm(&u->alarm, timeout, 0); + /* + * increase stats even if this entry was not really + * removed yet. We do not want to make people think + * that the replication protocol does not work + * properly. + */ + c->del_ok++; return u; } } -- cgit v1.2.3 From 2a838790b8a545e95841cb216a7623b3d9560bce Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 31 May 2008 17:11:40 +0200 Subject: delay the closure of the dump descriptor to fix assertion with cache_wt --- ChangeLog | 1 + src/run.c | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/ChangeLog b/ChangeLog index 2713ac7..25d8a6f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -38,6 +38,7 @@ o add eventfd emulation to communicate receiver -> sender o add best effort replication protocol (aka NOTRACK) o rework the HELLO logic inside FT-FW o fix leak in cache_destroy(): release objects before destroying the cache +o delay the closure of the dump descriptor to fix assertion with cache_wt version 0.9.6 (2008/03/08) ------------------------------ diff --git a/src/run.c b/src/run.c index 63761b4..cadcb4d 100644 --- a/src/run.c +++ b/src/run.c @@ -38,11 +38,13 @@ void killer(int foo) sigprocmask(SIG_BLOCK, &STATE(block), NULL); nfct_close(STATE(event)); - nfct_close(STATE(dump)); ignore_pool_destroy(STATE(ignore_pool)); local_server_destroy(&STATE(local)); STATE(mode)->kill(); + + nfct_close(STATE(dump)); /* cache_wt needs this here */ + unlink(CONFIG(lockfile)); dlog(LOG_NOTICE, "---- shutdown received ----"); close_log(); -- cgit v1.2.3 From 5dee97536258d3334b9c0ffeb59ec4ad076dc6c3 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 15 Jun 2008 02:33:28 +0200 Subject: check if entries already exist in kernel before injection --- src/cache_iterators.c | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/cache_iterators.c b/src/cache_iterators.c index c26d349..562d9a2 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -91,20 +91,29 @@ static int do_commit(void *data1, void *data2) */ nfct_set_attr_u32(ct, ATTR_TIMEOUT, CONFIG(commit_timeout)); - ret = nl_create_conntrack(ct); - if (ret == -1) { - switch(errno) { - case EEXIST: - c->commit_exist++; - break; - default: - dlog(LOG_ERR, "commit: %s", strerror(errno)); - dlog_ct(STATE(log), u->ct, NFCT_O_PLAIN); - c->commit_fail++; - break; - } - } else { - c->commit_ok++; + ret = nl_exist_conntrack(ct); + switch (ret) { + case -1: + dlog(LOG_ERR, "commit-exist: %s", strerror(errno)); + dlog_ct(STATE(log), ct, NFCT_O_PLAIN); + break; + case 0: + if (nl_create_conntrack(ct) == -1) { + dlog(LOG_ERR, "commit-create: %s", strerror(errno)); + dlog_ct(STATE(log), ct, NFCT_O_PLAIN); + c->commit_fail++; + } else + c->commit_ok++; + break; + case 1: + c->commit_exist++; + if (nl_update_conntrack(ct) == -1) { + dlog(LOG_ERR, "commit-update: %s", strerror(errno)); + dlog_ct(STATE(log), ct, NFCT_O_PLAIN); + c->commit_fail++; + } else + c->commit_ok++; + break; } /* keep iterating even if we have found errors */ @@ -128,7 +137,7 @@ void cache_commit(struct cache *c) dlog(LOG_NOTICE, "Committed %u new entries", commit_ok); if (commit_exist) - dlog(LOG_NOTICE, "%u entries ignored, " + dlog(LOG_NOTICE, "%u entries updated, " "already exist", commit_exist); if (commit_fail) dlog(LOG_NOTICE, "%u entries can't be " -- cgit v1.2.3 From dbd1a5ced2d144f330faba448e639b8dc9d6b009 Mon Sep 17 00:00:00 2001 From: Albin Tonerre Date: Sun, 15 Jun 2008 22:01:52 +0200 Subject: fix unsecure usage of printf and include limits.h (PATH_MAX and INT_MAX) --- src/ignore_pool.c | 1 + src/local.c | 2 +- src/main.c | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/ignore_pool.c b/src/ignore_pool.c index 027d628..2f951e8 100644 --- a/src/ignore_pool.c +++ b/src/ignore_pool.c @@ -25,6 +25,7 @@ #include #include #include +#include /* XXX: These should be configurable, better use a rb-tree */ #define IGNORE_POOL_SIZE 128 diff --git a/src/local.c b/src/local.c index e2c3599..4739e56 100644 --- a/src/local.c +++ b/src/local.c @@ -132,7 +132,7 @@ int do_local_client_step(int fd, void (*process)(char *buf)) void local_step(char *buf) { - printf(buf); + printf("%s", buf); } int do_local_request(int request, diff --git a/src/main.c b/src/main.c index 2e1ccd8..084643c 100644 --- a/src/main.c +++ b/src/main.c @@ -26,6 +26,7 @@ #include #include #include +#include struct ct_general_state st; union ct_state state; -- cgit v1.2.3 From 807f1e477baf2eb7a642e65017ede0a079ebeb4d Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 16 Jun 2008 01:43:11 +0200 Subject: use only the original tuple to check if a conntrack is present --- src/netlink.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/netlink.c b/src/netlink.c index 10c4643..387062d 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -23,6 +23,7 @@ #include "log.h" #include "debug.h" +#include #include int ignore_conntrack(struct nf_conntrack *ct) @@ -219,8 +220,15 @@ int nl_overrun_request_resync(void) int nl_exist_conntrack(struct nf_conntrack *ct) { int ret; + char __tmp[nfct_maxsize()]; + struct nf_conntrack *tmp = (struct nf_conntrack *) (void *)__tmp; - ret = nfct_query(STATE(dump), NFCT_Q_GET, ct); + memset(__tmp, 0, sizeof(__tmp)); + + /* use the original tuple to check if it is there */ + nfct_copy(tmp, ct, NFCT_CP_ORIG); + + ret = nfct_query(STATE(dump), NFCT_Q_GET, tmp); if (ret == -1) return errno == ENOENT ? 0 : -1; -- cgit v1.2.3 From 2de606c2458067c48e72058a31af384574cf9c70 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 22 Jun 2008 22:00:36 +0200 Subject: fix xml output: wrap output with one root element --- include/conntrack.h | 6 ++++++ src/conntrack.c | 48 ++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 50 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/include/conntrack.h b/include/conntrack.h index 2e17475..dc30c13 100644 --- a/include/conntrack.h +++ b/include/conntrack.h @@ -189,4 +189,10 @@ extern void register_udp(void); extern void register_icmp(void); extern void register_icmpv6(void); +#define BUFFER_SIZE(ret, len, offset) \ + if (ret > len) \ + ret = len; \ + offset += ret; \ + len -= ret; + #endif diff --git a/src/conntrack.c b/src/conntrack.c index 25a3a57..1ee98e3 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -604,10 +604,16 @@ static int ignore_nat(const struct nf_conntrack *obj, } static int counter; +static int dump_xml_header_done = 1; static void __attribute__((noreturn)) event_sighandler(int s) { + if (dump_xml_header_done == 0) { + printf("\n"); + fflush(stdout); + } + fprintf(stderr, "%s v%s: ", PROGNAME, VERSION); fprintf(stderr, "%d flow events has been shown.\n", counter); nfct_close(cth); @@ -619,6 +625,7 @@ static int event_cb(enum nf_conntrack_msg_type type, void *data) { char buf[1024]; + int ret, offset = 0, len = sizeof(buf); struct nf_conntrack *obj = data; unsigned int op_type = NFCT_O_DEFAULT; unsigned int op_flags = 0; @@ -629,8 +636,21 @@ static int event_cb(enum nf_conntrack_msg_type type, if (options & CT_COMPARISON && !nfct_cmp(obj, ct, NFCT_CMP_ALL)) return NFCT_CB_CONTINUE; - if (output_mask & _O_XML) + if (output_mask & _O_XML) { op_type = NFCT_O_XML; + if (dump_xml_header_done) { + dump_xml_header_done = 0; + ret = snprintf(buf, len, "\n" + "\n"); + if (ret == -1) { + fprintf(stderr, "evil! snprintf fails\n"); + return NFCT_CB_CONTINUE; + } + + BUFFER_SIZE(ret, len, offset); + } + } if (output_mask & _O_EXT) op_flags = NFCT_OF_SHOW_LAYER3; if (output_mask & _O_TMS) { @@ -644,7 +664,8 @@ static int event_cb(enum nf_conntrack_msg_type type, if (output_mask & _O_ID) op_flags |= NFCT_OF_ID; - nfct_snprintf(buf, 1024, ct, type, op_type, op_flags); + nfct_snprintf(buf+offset, len, ct, type, op_type, op_flags); + printf("%s\n", buf); fflush(stdout); @@ -658,6 +679,7 @@ static int dump_cb(enum nf_conntrack_msg_type type, void *data) { char buf[1024]; + int ret, offset = 0, len = sizeof(buf); struct nf_conntrack *obj = data; unsigned int op_type = NFCT_O_DEFAULT; unsigned int op_flags = 0; @@ -668,14 +690,27 @@ static int dump_cb(enum nf_conntrack_msg_type type, if (options & CT_COMPARISON && !nfct_cmp(obj, ct, NFCT_CMP_ALL)) return NFCT_CB_CONTINUE; - if (output_mask & _O_XML) + if (output_mask & _O_XML) { op_type = NFCT_O_XML; + if (dump_xml_header_done) { + dump_xml_header_done = 0; + ret = snprintf(buf, len, "\n" + "\n"); + if (ret == -1) { + fprintf(stderr, "evil! snprintf fails\n"); + return NFCT_CB_CONTINUE; + } + + BUFFER_SIZE(ret, len, offset); + } + } if (output_mask & _O_EXT) op_flags = NFCT_OF_SHOW_LAYER3; if (output_mask & _O_ID) op_flags |= NFCT_OF_ID; - nfct_snprintf(buf, 1024, ct, NFCT_T_UNKNOWN, op_type, op_flags); + nfct_snprintf(buf+offset, len, ct, NFCT_T_UNKNOWN, op_type, op_flags); printf("%s\n", buf); counter++; @@ -1129,6 +1164,11 @@ int main(int argc, char *argv[]) else res = nfct_query(cth, NFCT_Q_DUMP, &family); + if (dump_xml_header_done == 0) { + printf("\n"); + fflush(stdout); + } + nfct_close(cth); break; -- cgit v1.2.3 From 77b1fdb824eb45213df4f57224e8e799fed43ded Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 22 Jul 2008 12:13:43 +0200 Subject: Major rework of the user-space event filtering This patch reworks the user-space filtering. Although we have kernel-space filtering since Linux kernel >= 2.6.26, we keep userspace filtering to ensure backward compatibility. Moreover, this patch prepares the implementation of the kernel-space filtering via libnetfilter_conntrack's high-level berkeley socket filter API. Signed-off-by: Pablo Neira Ayuso --- doc/stats/conntrackd.conf | 54 ++++--- doc/sync/alarm/node1/conntrackd.conf | 65 +++++---- doc/sync/alarm/node2/conntrackd.conf | 65 +++++---- doc/sync/ftfw/node1/conntrackd.conf | 65 +++++---- doc/sync/ftfw/node2/conntrackd.conf | 65 +++++---- doc/sync/notrack/node1/conntrackd.conf | 65 +++++---- doc/sync/notrack/node2/conntrackd.conf | 65 +++++---- include/Makefile.am | 4 +- include/bitops.h | 36 +++++ include/conntrackd.h | 4 +- include/filter.h | 31 ++++ include/ignore.h | 18 --- include/state_helper.h | 22 --- src/Makefile.am | 3 +- src/filter.c | 250 ++++++++++++++++++++++++++++++++ src/ignore_pool.c | 155 -------------------- src/netlink.c | 16 +-- src/read_config_lex.l | 14 +- src/read_config_yy.y | 255 +++++++++++++++++++++++++-------- src/run.c | 4 +- src/state_helper.c | 44 ------ src/state_helper_tcp.c | 35 ----- src/sync-mode.c | 4 - 23 files changed, 807 insertions(+), 532 deletions(-) create mode 100644 include/bitops.h create mode 100644 include/filter.h delete mode 100644 include/ignore.h delete mode 100644 include/state_helper.h create mode 100644 src/filter.c delete mode 100644 src/ignore_pool.c delete mode 100644 src/state_helper.c delete mode 100644 src/state_helper_tcp.c (limited to 'src') diff --git a/doc/stats/conntrackd.conf b/doc/stats/conntrackd.conf index 4bc5642..b63c2c3 100644 --- a/doc/stats/conntrackd.conf +++ b/doc/stats/conntrackd.conf @@ -47,6 +47,39 @@ General { # Increase the socket buffer up to maximun if required # SocketBufferSizeMaxGrown 655355 + + # + # Event filtering: This clause allows you to filter certain traffic, + # There are currently three filter-sets: Protocol, Address and + # State. The filter is attached to an action that can be: Accept or + # Ignore. Thus, you can define the event filtering policy of the + # filter-sets in positive or negative logic depending on your needs. + # + Filter { + # + # Accept only certain protocols: You may want to log the + # state of flows depending on their layer 4 protocol. + # + Protocol Accept { + TCP + } + + # + # Ignore traffic for a certain set of IP's. + # + Address Ignore { + IPv4_address 127.0.0.1 # loopback + } + + # + # Uncomment this line below if you want to filter by flow state. + # The existing TCP states are: SYN_SENT, SYN_RECV, ESTABLISHED, + # FIN_WAIT, CLOSE_WAIT, LAST_ACK, TIME_WAIT, CLOSED, LISTEN. + # + # State Accept { + # ESTABLISHED CLOSED TIME_WAIT CLOSE_WAIT for TCP + # } + } } Stats { @@ -66,24 +99,3 @@ Stats { # #Syslog on } - -# -# Ignore traffic for a certain set of IP's: Usually -# all the IP assigned to the firewall since local -# traffic must be ignored, just forwarded connections -# are worth to replicate -# -IgnoreTrafficFor { - IPv4_address 127.0.0.1 # loopback -} - -# -# Do not replicate certain protocol traffic -# -IgnoreProtocol { - UDP -# ICMP -# IGMP -# VRRP - # numeric numbers also valid -} diff --git a/doc/sync/alarm/node1/conntrackd.conf b/doc/sync/alarm/node1/conntrackd.conf index 56bef0c..c3c4da4 100644 --- a/doc/sync/alarm/node1/conntrackd.conf +++ b/doc/sync/alarm/node1/conntrackd.conf @@ -133,30 +133,47 @@ General { # Increase the socket buffer up to maximum if required # SocketBufferSizeMaxGrown 655355 -} -# -# Ignore traffic for a certain set of IP's: Usually -# all the IP assigned to the firewall since local -# traffic must be ignored, just forwarded connections -# are worth to replicate -# -IgnoreTrafficFor { - IPv4_address 127.0.0.1 # loopback - IPv4_address 192.168.0.1 - IPv4_address 192.168.1.1 - IPv4_address 192.168.100.100 # dedicated link ip - IPv4_address 192.168.0.100 # virtual IP 1 - IPv4_address 192.168.1.100 # virtual IP 2 -} + # + # Event filtering: This clause allows you to filter certain traffic, + # There are currently three filter-sets: Protocol, Address and + # State. The filter is attached to an action that can be: Accept or + # Ignore. Thus, you can define the event filtering policy of the + # filter-sets in positive or negative logic depending on your needs. + # + Filter { + # + # Accept only certain protocols: You may want to replicate + # the state of flows depending on their layer 4 protocol. + # + Protocol Accept { + TCP + } -# -# Do not replicate certain protocol traffic -# -IgnoreProtocol { - UDP - ICMP - IGMP - VRRP - # numeric numbers also valid + # + # Ignore traffic for a certain set of IP's: Usually all the + # IP assigned to the firewall since local traffic must be + # ignored, only forwarded connections are worth to replicate. + # + Address Ignore { + IPv4_address 127.0.0.1 # loopback + IPv4_address 192.168.0.1 + IPv4_address 192.168.1.1 + IPv4_address 192.168.100.100 # dedicated link ip + IPv4_address 192.168.0.100 # virtual IP 1 + IPv4_address 192.168.1.100 # virtual IP 2 + } + + # + # Uncomment this line below if you want to filter by flow state. + # This option introduces a trade-off in the replication: it + # reduces CPU consumption at the cost of having lazy backup + # firewall replicas. The existing TCP states are: SYN_SENT, + # SYN_RECV, ESTABLISHED, FIN_WAIT, CLOSE_WAIT, LAST_ACK, + # TIME_WAIT, CLOSED, LISTEN. + # + # State Accept { + # ESTABLISHED CLOSED TIME_WAIT CLOSE_WAIT for TCP + # } + } } diff --git a/doc/sync/alarm/node2/conntrackd.conf b/doc/sync/alarm/node2/conntrackd.conf index e0cb375..e61e76a 100644 --- a/doc/sync/alarm/node2/conntrackd.conf +++ b/doc/sync/alarm/node2/conntrackd.conf @@ -133,30 +133,47 @@ General { # Increase the socket buffer up to maximum if required # SocketBufferSizeMaxGrown 655355 -} -# -# Ignore traffic for a certain set of IP's: Usually -# all the IP assigned to the firewall since local -# traffic must be ignored, just forwarded connections -# are worth to replicate -# -IgnoreTrafficFor { - IPv4_address 127.0.0.1 # loopback - IPv4_address 192.168.0.2 - IPv4_address 192.168.1.2 - IPv4_address 192.168.100.200 # dedicated link ip - IPv4_address 192.168.0.200 # virtual IP 1 - IPv4_address 192.168.1.200 # virtual IP 2 -} + # + # Event filtering: This clause allows you to filter certain traffic, + # There are currently three filter-sets: Protocol, Address and + # State. The filter is attached to an action that can be: Accept or + # Ignore. Thus, you can define the event filtering policy of the + # filter-sets in positive or negative logic depending on your needs. + # + Filter { + # + # Accept only certain protocols: You may want to replicate + # the state of flows depending on their layer 4 protocol. + # + Protocol Accept { + TCP + } -# -# Do not replicate certain protocol traffic -# -IgnoreProtocol { - UDP - ICMP - IGMP - VRRP - # numeric numbers also valid + # + # Ignore traffic for a certain set of IP's: Usually all the + # IP assigned to the firewall since local traffic must be + # ignored, only forwarded connections are worth to replicate. + # + Address Ignore { + IPv4_address 127.0.0.1 # loopback + IPv4_address 192.168.0.2 + IPv4_address 192.168.1.2 + IPv4_address 192.168.100.200 # dedicated link ip + IPv4_address 192.168.0.100 # virtual IP 1 + IPv4_address 192.168.1.100 # virtual IP 2 + } + + # + # Uncomment this line below if you want to filter by flow state. + # This option introduces a trade-off in the replication: it + # reduces CPU consumption at the cost of having lazy backup + # firewall replicas. The existing TCP states are: SYN_SENT, + # SYN_RECV, ESTABLISHED, FIN_WAIT, CLOSE_WAIT, LAST_ACK, + # TIME_WAIT, CLOSED, LISTEN. + # + # State Accept { + # ESTABLISHED CLOSED TIME_WAIT CLOSE_WAIT for TCP + # } + } } diff --git a/doc/sync/ftfw/node1/conntrackd.conf b/doc/sync/ftfw/node1/conntrackd.conf index f3211db..98ad581 100644 --- a/doc/sync/ftfw/node1/conntrackd.conf +++ b/doc/sync/ftfw/node1/conntrackd.conf @@ -128,30 +128,47 @@ General { # Increase the socket buffer up to maximum if required # SocketBufferSizeMaxGrown 655355 -} -# -# Ignore traffic for a certain set of IP's: Usually -# all the IP assigned to the firewall since local -# traffic must be ignored, just forwarded connections -# are worth to replicate -# -IgnoreTrafficFor { - IPv4_address 127.0.0.1 # loopback - IPv4_address 192.168.0.1 - IPv4_address 192.168.1.1 - IPv4_address 192.168.100.100 # dedicated link ip - IPv4_address 192.168.0.100 # virtual IP 1 - IPv4_address 192.168.1.100 # virtual IP 2 -} + # + # Event filtering: This clause allows you to filter certain traffic, + # There are currently three filter-sets: Protocol, Address and + # State. The filter is attached to an action that can be: Accept or + # Ignore. Thus, you can define the event filtering policy of the + # filter-sets in positive or negative logic depending on your needs. + # + Filter { + # + # Accept only certain protocols: You may want to replicate + # the state of flows depending on their layer 4 protocol. + # + Protocol Accept { + TCP + } -# -# Do not replicate certain protocol traffic -# -IgnoreProtocol { - UDP - ICMP - IGMP - VRRP - # numeric numbers also valid + # + # Ignore traffic for a certain set of IP's: Usually all the + # IP assigned to the firewall since local traffic must be + # ignored, only forwarded connections are worth to replicate. + # + Address Ignore { + IPv4_address 127.0.0.1 # loopback + IPv4_address 192.168.0.1 + IPv4_address 192.168.1.1 + IPv4_address 192.168.100.100 # dedicated link ip + IPv4_address 192.168.0.100 # virtual IP 1 + IPv4_address 192.168.1.100 # virtual IP 2 + } + + # + # Uncomment this line below if you want to filter by flow state. + # This option introduces a trade-off in the replication: it + # reduces CPU consumption at the cost of having lazy backup + # firewall replicas. The existing TCP states are: SYN_SENT, + # SYN_RECV, ESTABLISHED, FIN_WAIT, CLOSE_WAIT, LAST_ACK, + # TIME_WAIT, CLOSED, LISTEN. + # + # State Accept { + # ESTABLISHED CLOSED TIME_WAIT CLOSE_WAIT for TCP + # } + } } diff --git a/doc/sync/ftfw/node2/conntrackd.conf b/doc/sync/ftfw/node2/conntrackd.conf index 9c26ff5..2fab830 100644 --- a/doc/sync/ftfw/node2/conntrackd.conf +++ b/doc/sync/ftfw/node2/conntrackd.conf @@ -127,30 +127,47 @@ General { # Increase the socket buffer up to maximum if required # SocketBufferSizeMaxGrown 655355 -} -# -# Ignore traffic for a certain set of IP's: Usually -# all the IP assigned to the firewall since local -# traffic must be ignored, just forwarded connections -# are worth to replicate -# -IgnoreTrafficFor { - IPv4_address 127.0.0.1 # loopback - IPv4_address 192.168.0.2 - IPv4_address 192.168.1.2 - IPv4_address 192.168.100.200 # dedicated link ip - IPv4_address 192.168.0.200 # virtual IP 1 - IPv4_address 192.168.1.200 # virtual IP 2 -} + # + # Event filtering: This clause allows you to filter certain traffic, + # There are currently three filter-sets: Protocol, Address and + # State. The filter is attached to an action that can be: Accept or + # Ignore. Thus, you can define the event filtering policy of the + # filter-sets in positive or negative logic depending on your needs. + # + Filter { + # + # Accept only certain protocols: You may want to replicate + # the state of flows depending on their layer 4 protocol. + # + Protocol Accept { + TCP + } -# -# Do not replicate certain protocol traffic -# -IgnoreProtocol { - UDP - ICMP - IGMP - VRRP - # numeric numbers also valid + # + # Ignore traffic for a certain set of IP's: Usually all the + # IP assigned to the firewall since local traffic must be + # ignored, only forwarded connections are worth to replicate. + # + Address Ignore { + IPv4_address 127.0.0.1 # loopback + IPv4_address 192.168.0.2 + IPv4_address 192.168.1.2 + IPv4_address 192.168.100.200 # dedicated link ip + IPv4_address 192.168.0.100 # virtual IP 1 + IPv4_address 192.168.1.100 # virtual IP 2 + } + + # + # Uncomment this line below if you want to filter by flow state. + # This option introduces a trade-off in the replication: it + # reduces CPU consumption at the cost of having lazy backup + # firewall replicas. The existing TCP states are: SYN_SENT, + # SYN_RECV, ESTABLISHED, FIN_WAIT, CLOSE_WAIT, LAST_ACK, + # TIME_WAIT, CLOSED, LISTEN. + # + # State Accept { + # ESTABLISHED CLOSED TIME_WAIT CLOSE_WAIT for TCP + # } + } } diff --git a/doc/sync/notrack/node1/conntrackd.conf b/doc/sync/notrack/node1/conntrackd.conf index 1185351..724183a 100644 --- a/doc/sync/notrack/node1/conntrackd.conf +++ b/doc/sync/notrack/node1/conntrackd.conf @@ -121,30 +121,47 @@ General { # Increase the socket buffer up to maximum if required # SocketBufferSizeMaxGrown 655355 -} -# -# Ignore traffic for a certain set of IP's: Usually -# all the IP assigned to the firewall since local -# traffic must be ignored, just forwarded connections -# are worth to replicate -# -IgnoreTrafficFor { - IPv4_address 127.0.0.1 # loopback - IPv4_address 192.168.0.1 - IPv4_address 192.168.1.1 - IPv4_address 192.168.100.100 # dedicated link ip - IPv4_address 192.168.0.100 # virtual IP 1 - IPv4_address 192.168.1.100 # virtual IP 2 -} + # + # Event filtering: This clause allows you to filter certain traffic, + # There are currently three filter-sets: Protocol, Address and + # State. The filter is attached to an action that can be: Accept or + # Ignore. Thus, you can define the event filtering policy of the + # filter-sets in positive or negative logic depending on your needs. + # + Filter { + # + # Accept only certain protocols: You may want to replicate + # the state of flows depending on their layer 4 protocol. + # + Protocol Accept { + TCP + } -# -# Do not replicate certain protocol traffic -# -IgnoreProtocol { - UDP - ICMP - IGMP - VRRP - # numeric numbers also valid + # + # Ignore traffic for a certain set of IP's: Usually all the + # IP assigned to the firewall since local traffic must be + # ignored, only forwarded connections are worth to replicate. + # + Address Ignore { + IPv4_address 127.0.0.1 # loopback + IPv4_address 192.168.0.1 + IPv4_address 192.168.1.1 + IPv4_address 192.168.100.100 # dedicated link ip + IPv4_address 192.168.0.100 # virtual IP 1 + IPv4_address 192.168.1.100 # virtual IP 2 + } + + # + # Uncomment this line below if you want to filter by flow state. + # This option introduces a trade-off in the replication: it + # reduces CPU consumption at the cost of having lazy backup + # firewall replicas. The existing TCP states are: SYN_SENT, + # SYN_RECV, ESTABLISHED, FIN_WAIT, CLOSE_WAIT, LAST_ACK, + # TIME_WAIT, CLOSED, LISTEN. + # + # State Accept { + # ESTABLISHED CLOSED TIME_WAIT CLOSE_WAIT for TCP + # } + } } diff --git a/doc/sync/notrack/node2/conntrackd.conf b/doc/sync/notrack/node2/conntrackd.conf index 7881d46..cbf5cee 100644 --- a/doc/sync/notrack/node2/conntrackd.conf +++ b/doc/sync/notrack/node2/conntrackd.conf @@ -120,30 +120,47 @@ General { # Increase the socket buffer up to maximum if required # SocketBufferSizeMaxGrown 655355 -} -# -# Ignore traffic for a certain set of IP's: Usually -# all the IP assigned to the firewall since local -# traffic must be ignored, just forwarded connections -# are worth to replicate -# -IgnoreTrafficFor { - IPv4_address 127.0.0.1 # loopback - IPv4_address 192.168.0.2 - IPv4_address 192.168.1.2 - IPv4_address 192.168.100.200 # dedicated link ip - IPv4_address 192.168.0.200 # virtual IP 1 - IPv4_address 192.168.1.200 # virtual IP 2 -} + # + # Event filtering: This clause allows you to filter certain traffic, + # There are currently three filter-sets: Protocol, Address and + # State. The filter is attached to an action that can be: Accept or + # Ignore. Thus, you can define the event filtering policy of the + # filter-sets in positive or negative logic depending on your needs. + # + Filter { + # + # Accept only certain protocols: You may want to replicate + # the state of flows depending on their layer 4 protocol. + # + Protocol Accept { + TCP + } -# -# Do not replicate certain protocol traffic -# -IgnoreProtocol { - UDP - ICMP - IGMP - VRRP - # numeric numbers also valid + # + # Ignore traffic for a certain set of IP's: Usually all the + # IP assigned to the firewall since local traffic must be + # ignored, only forwarded connections are worth to replicate. + # + Address Ignore { + IPv4_address 127.0.0.1 # loopback + IPv4_address 192.168.0.2 + IPv4_address 192.168.1.2 + IPv4_address 192.168.100.200 # dedicated link ip + IPv4_address 192.168.0.100 # virtual IP 1 + IPv4_address 192.168.1.100 # virtual IP 2 + } + + # + # Uncomment this line below if you want to filter by flow state. + # This option introduces a trade-off in the replication: it + # reduces CPU consumption at the cost of having lazy backup + # firewall replicas. The existing TCP states are: SYN_SENT, + # SYN_RECV, ESTABLISHED, FIN_WAIT, CLOSE_WAIT, LAST_ACK, + # TIME_WAIT, CLOSED, LISTEN. + # + # State Accept { + # ESTABLISHED CLOSED TIME_WAIT CLOSE_WAIT for TCP + # } + } } diff --git a/include/Makefile.am b/include/Makefile.am index 01be0df..3287a0c 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -2,6 +2,6 @@ noinst_HEADERS = alarm.h jhash.h slist.h cache.h linux_list.h linux_rbtree.h \ sync.h conntrackd.h local.h us-conntrack.h \ debug.h log.h hash.h mcast.h conntrack.h \ - state_helper.h network.h ignore.h queue.h \ - traffic_stats.h netlink.h fds.h event.h + network.h filter.h queue.h \ + traffic_stats.h netlink.h fds.h event.h bitops.h diff --git a/include/bitops.h b/include/bitops.h new file mode 100644 index 0000000..51f4289 --- /dev/null +++ b/include/bitops.h @@ -0,0 +1,36 @@ +#ifndef _BITOPS_H_ +#define _BITOPS_H_ + +#include + +static inline void set_bit_u32(int nr, u_int32_t *addr) +{ + addr[nr >> 5] |= (1UL << (nr & 31)); +} + +static inline void unset_bit_u32(int nr, u_int32_t *addr) +{ + addr[nr >> 5] &= ~(1UL << (nr & 31)); +} + +static inline int test_bit_u32(int nr, const u_int32_t *addr) +{ + return ((1UL << (nr & 31)) & (addr[nr >> 5])) != 0; +} + +static inline void set_bit_u16(int nr, u_int16_t *addr) +{ + addr[nr >> 4] |= (1UL << (nr & 15)); +} + +static inline void unset_bit_u16(int nr, u_int16_t *addr) +{ + addr[nr >> 4] &= ~(1UL << (nr & 15)); +} + +static inline int test_bit_u16(int nr, const u_int16_t *addr) +{ + return ((1UL << (nr & 15)) & (addr[nr >> 4])) != 0; +} + +#endif diff --git a/include/conntrackd.h b/include/conntrackd.h index 8a6e8d2..cd02f1f 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -4,6 +4,7 @@ #include "mcast.h" #include "local.h" #include "alarm.h" +#include "filter.h" #include #include @@ -80,7 +81,6 @@ struct ct_conf { int del_timeout; unsigned int netlink_buffer_size; unsigned int netlink_buffer_size_max_grown; - unsigned char ignore_protocol[IPPROTO_MAX]; union inet_address *listen_to; unsigned int listen_to_len; unsigned int flags; @@ -103,7 +103,7 @@ struct ct_general_state { FILE *stats_log; struct local_server local; struct ct_mode *mode; - struct ignore_pool *ignore_pool; + struct ct_filter *us_filter; struct nfct_handle *event; /* event handler */ struct nfct_handle *dump; /* dump handler */ diff --git a/include/filter.h b/include/filter.h new file mode 100644 index 0000000..de0754e --- /dev/null +++ b/include/filter.h @@ -0,0 +1,31 @@ +#ifndef _FILTER_H_ +#define _FILTER_H_ + +#include + +enum ct_filter_type { + CT_FILTER_L4PROTO, + CT_FILTER_STATE, + CT_FILTER_ADDRESS, + CT_FILTER_MAX +}; + +enum ct_filter_logic { + CT_FILTER_NEGATIVE = 0, + CT_FILTER_POSITIVE = 1, +}; + +struct nf_conntrack; +struct ct_filter; + +struct ct_filter *ct_filter_create(void); +void ct_filter_destroy(struct ct_filter *filter); +int ct_filter_add_ip(struct ct_filter *filter, void *data, uint8_t family); +void ct_filter_add_proto(struct ct_filter *filter, int protonum); +void ct_filter_add_state(struct ct_filter *f, int protonum, int state); +void ct_filter_set_logic(struct ct_filter *f, + enum ct_filter_type type, + enum ct_filter_logic logic); +int ct_filter_check(struct ct_filter *filter, struct nf_conntrack *ct); + +#endif diff --git a/include/ignore.h b/include/ignore.h deleted file mode 100644 index e5e96ff..0000000 --- a/include/ignore.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef _IGNORE_H_ -#define _IGNORE_H_ - -#include - -struct nf_conntrack; - -struct ignore_pool { - struct hashtable *h; - struct hashtable *h6; -}; - -struct ignore_pool *ignore_pool_create(void); -void ignore_pool_destroy(struct ignore_pool *ip); -int ignore_pool_add(struct ignore_pool *ip, void *data, uint8_t family); -int ignore_pool_test(struct ignore_pool *ip, struct nf_conntrack *ct); - -#endif diff --git a/include/state_helper.h b/include/state_helper.h deleted file mode 100644 index 1a68b04..0000000 --- a/include/state_helper.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef _STATE_HELPER_H_ -#define _STATE_HELPER_H_ - -#include - -enum { - ST_H_SKIP, - ST_H_REPLICATE -}; - -struct state_replication_helper { - uint8_t proto; - unsigned int state; - - int (*verdict)(const struct state_replication_helper *h, - const struct nf_conntrack *ct); -}; - -int state_helper_verdict(int type, struct nf_conntrack *ct); -void state_helper_register(struct state_replication_helper *h, int h_state); - -#endif diff --git a/src/Makefile.am b/src/Makefile.am index 69ddcfd..805e50d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -12,13 +12,12 @@ conntrack_LDFLAGS = $(all_libraries) @LIBNETFILTER_CONNTRACK_LIBS@ conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c rbtree.c \ local.c log.c mcast.c netlink.c \ - ignore_pool.c fds.c event.c \ + filter.c fds.c event.c \ cache.c cache_iterators.c \ cache_lifetime.c cache_timer.c cache_wt.c \ sync-mode.c sync-alarm.c sync-ftfw.c sync-notrack.c \ traffic_stats.c stats-mode.c \ network.c \ - state_helper.c state_helper_tcp.c \ build.c parse.c \ read_config_yy.y read_config_lex.l diff --git a/src/filter.c b/src/filter.c new file mode 100644 index 0000000..6e4d64a --- /dev/null +++ b/src/filter.c @@ -0,0 +1,250 @@ +/* + * (C) 2006-2008 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "filter.h" +#include "bitops.h" +#include "jhash.h" +#include "hash.h" +#include "conntrackd.h" +#include "log.h" + +#include +#include +#include +#include + +struct ct_filter { + int logic[CT_FILTER_MAX]; + u_int32_t l4protomap[IPPROTO_MAX/32]; + u_int16_t statemap[IPPROTO_MAX]; + struct hashtable *h; + struct hashtable *h6; +}; + +/* XXX: These should be configurable, better use a rb-tree */ +#define FILTER_POOL_SIZE 128 +#define FILTER_POOL_LIMIT INT_MAX + +static uint32_t hash(const void *data, struct hashtable *table) +{ + const uint32_t *f = data; + + return jhash_1word(*f, 0) % table->hashsize; +} + +static uint32_t hash6(const void *data, struct hashtable *table) +{ + return jhash(data, sizeof(uint32_t)*4, 0) % table->hashsize; +} + +static int compare(const void *data1, const void *data2) +{ + const uint32_t *f1 = data1; + const uint32_t *f2 = data2; + + return *f1 == *f2; +} + +static int compare6(const void *data1, const void *data2) +{ + return memcmp(data1, data2, sizeof(uint32_t)*4) == 0; +} + +struct ct_filter *ct_filter_create(void) +{ + int i; + struct ct_filter *filter; + + filter = calloc(sizeof(struct ct_filter), 1); + if (!filter) + return NULL; + + filter->h = hashtable_create(FILTER_POOL_SIZE, + FILTER_POOL_LIMIT, + sizeof(uint32_t), + hash, + compare); + if (!filter->h) { + free(filter); + return NULL; + } + + filter->h6 = hashtable_create(FILTER_POOL_SIZE, + FILTER_POOL_LIMIT, + sizeof(uint32_t)*4, + hash6, + compare6); + if (!filter->h6) { + free(filter->h); + free(filter); + return NULL; + } + + for (i=0; ilogic[i] = -1; + + return filter; +} + +void ct_filter_destroy(struct ct_filter *filter) +{ + hashtable_destroy(filter->h); + hashtable_destroy(filter->h6); + free(filter); +} + +/* this is ugly, but it simplifies read_config_yy.y */ +static struct ct_filter *__filter_alloc(struct ct_filter *filter) +{ + if (!STATE(us_filter)) { + STATE(us_filter) = ct_filter_create(); + if (!STATE(us_filter)) { + fprintf(stderr, "Can't create ignore pool!\n"); + exit(EXIT_FAILURE); + } + } + + return STATE(us_filter); +} + +void ct_filter_set_logic(struct ct_filter *filter, + enum ct_filter_type type, + enum ct_filter_logic logic) +{ + filter = __filter_alloc(filter); + filter->logic[type] = logic; +} + +int ct_filter_add_ip(struct ct_filter *filter, void *data, uint8_t family) +{ + filter = __filter_alloc(filter); + + switch(family) { + case AF_INET: + if (!hashtable_add(filter->h, data)) + return 0; + break; + case AF_INET6: + if (!hashtable_add(filter->h6, data)) + return 0; + break; + } + return 1; +} + +void ct_filter_add_proto(struct ct_filter *f, int protonum) +{ + f = __filter_alloc(f); + + set_bit_u32(protonum, f->l4protomap); +} + +void ct_filter_add_state(struct ct_filter *f, int protonum, int val) +{ + f = __filter_alloc(f); + + set_bit_u16(val, &f->statemap[protonum]); +} + +static int +__ct_filter_test_ipv4(struct ct_filter *f, struct nf_conntrack *ct) +{ + if (!f->h) + return 0; + + return (hashtable_test(f->h, nfct_get_attr(ct, ATTR_ORIG_IPV4_SRC)) || + hashtable_test(f->h, nfct_get_attr(ct, ATTR_ORIG_IPV4_DST)) || + hashtable_test(f->h, nfct_get_attr(ct, ATTR_REPL_IPV4_SRC)) || + hashtable_test(f->h, nfct_get_attr(ct, ATTR_REPL_IPV4_DST))); +} + +static int +__ct_filter_test_ipv6(struct ct_filter *f, struct nf_conntrack *ct) +{ + if (!f->h6) + return 0; + + return (hashtable_test(f->h6, nfct_get_attr(ct, ATTR_ORIG_IPV6_SRC)) || + hashtable_test(f->h6, nfct_get_attr(ct, ATTR_ORIG_IPV6_DST)) || + hashtable_test(f->h6, nfct_get_attr(ct, ATTR_REPL_IPV6_SRC)) || + hashtable_test(f->h6, nfct_get_attr(ct, ATTR_REPL_IPV6_DST))); +} + +static int __ct_filter_test_state(struct ct_filter *f, struct nf_conntrack *ct) +{ + uint16_t val = 0; + uint8_t protonum = nfct_get_attr_u8(ct, ATTR_L4PROTO); + + switch(protonum) { + case IPPROTO_TCP: + val = nfct_get_attr_u8(ct, ATTR_TCP_STATE); + break; + default: + return -1; + } + + return test_bit_u16(val, &f->statemap[protonum]); +} + +int ct_filter_check(struct ct_filter *f, struct nf_conntrack *ct) +{ + int ret, protonum = nfct_get_attr_u8(ct, ATTR_L4PROTO); + + /* no event filtering at all */ + if (f == NULL) + return 1; + + if (f->logic[CT_FILTER_L4PROTO] != -1) { + ret = test_bit_u32(protonum, f->l4protomap); + if (ret == 0 && f->logic[CT_FILTER_L4PROTO]) + return 0; + else if (ret == 1 && !f->logic[CT_FILTER_L4PROTO]) + return 0; + } + + if (f->logic[CT_FILTER_ADDRESS] != -1) { + switch(nfct_get_attr_u8(ct, ATTR_L3PROTO)) { + case AF_INET: + ret = __ct_filter_test_ipv4(f, ct); + if (ret == 0 && f->logic[CT_FILTER_ADDRESS]) + return 0; + else if (ret == 1 && !f->logic[CT_FILTER_ADDRESS]) + return 0; + break; + case AF_INET6: + ret = __ct_filter_test_ipv6(f, ct); + if (ret == 0 && f->logic[CT_FILTER_ADDRESS]) + return 0; + else if (ret == 1 && !f->logic[CT_FILTER_ADDRESS]) + return 0; + break; + default: + break; + } + } + + if (f->logic[CT_FILTER_STATE] != -1) { + ret = __ct_filter_test_state(f, ct); + if (ret == 0 && f->logic[CT_FILTER_STATE]) + return 0; + else if (ret == 1 && !f->logic[CT_FILTER_STATE]) + return 0; + } + + return 1; +} diff --git a/src/ignore_pool.c b/src/ignore_pool.c deleted file mode 100644 index 2f951e8..0000000 --- a/src/ignore_pool.c +++ /dev/null @@ -1,155 +0,0 @@ -/* - * (C) 2006-2007 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "ignore.h" -#include "jhash.h" -#include "hash.h" -#include "conntrackd.h" -#include "log.h" - -#include -#include -#include -#include - -/* XXX: These should be configurable, better use a rb-tree */ -#define IGNORE_POOL_SIZE 128 -#define IGNORE_POOL_LIMIT INT_MAX - -static uint32_t hash(const void *data, struct hashtable *table) -{ - const uint32_t *ip = data; - - return jhash_1word(*ip, 0) % table->hashsize; -} - -static uint32_t hash6(const void *data, struct hashtable *table) -{ - return jhash(data, sizeof(uint32_t)*4, 0) % table->hashsize; -} - -static int compare(const void *data1, const void *data2) -{ - const uint32_t *ip1 = data1; - const uint32_t *ip2 = data2; - - return *ip1 == *ip2; -} - -static int compare6(const void *data1, const void *data2) -{ - return memcmp(data1, data2, sizeof(uint32_t)*4) == 0; -} - -struct ignore_pool *ignore_pool_create(void) -{ - struct ignore_pool *ip; - - ip = malloc(sizeof(struct ignore_pool)); - if (!ip) - return NULL; - memset(ip, 0, sizeof(struct ignore_pool)); - - ip->h = hashtable_create(IGNORE_POOL_SIZE, - IGNORE_POOL_LIMIT, - sizeof(uint32_t), - hash, - compare); - if (!ip->h) { - free(ip); - return NULL; - } - - ip->h6 = hashtable_create(IGNORE_POOL_SIZE, - IGNORE_POOL_LIMIT, - sizeof(uint32_t)*4, - hash6, - compare6); - if (!ip->h6) { - free(ip->h); - free(ip); - return NULL; - } - - return ip; -} - -void ignore_pool_destroy(struct ignore_pool *ip) -{ - hashtable_destroy(ip->h); - hashtable_destroy(ip->h6); - free(ip); -} - -int ignore_pool_add(struct ignore_pool *ip, void *data, uint8_t family) -{ - switch(family) { - case AF_INET: - if (!hashtable_add(ip->h, data)) - return 0; - break; - case AF_INET6: - if (!hashtable_add(ip->h6, data)) - return 0; - break; - } - return 1; -} - -static int -__ignore_pool_test_ipv4(struct ignore_pool *ip, struct nf_conntrack *ct) -{ - if (!ip->h) - return 0; - - return (hashtable_test(ip->h, nfct_get_attr(ct, ATTR_ORIG_IPV4_SRC)) || - hashtable_test(ip->h, nfct_get_attr(ct, ATTR_ORIG_IPV4_DST)) || - hashtable_test(ip->h, nfct_get_attr(ct, ATTR_REPL_IPV4_SRC)) || - hashtable_test(ip->h, nfct_get_attr(ct, ATTR_REPL_IPV4_DST))); -} - -static int -__ignore_pool_test_ipv6(struct ignore_pool *ip, struct nf_conntrack *ct) -{ - if (!ip->h6) - return 0; - - return (hashtable_test(ip->h6, nfct_get_attr(ct, ATTR_ORIG_IPV6_SRC)) || - hashtable_test(ip->h6, nfct_get_attr(ct, ATTR_ORIG_IPV6_DST)) || - hashtable_test(ip->h6, nfct_get_attr(ct, ATTR_REPL_IPV6_SRC)) || - hashtable_test(ip->h6, nfct_get_attr(ct, ATTR_REPL_IPV6_DST))); -} - -int ignore_pool_test(struct ignore_pool *ip, struct nf_conntrack *ct) -{ - int ret = 0; - - switch(nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO)) { - case AF_INET: - ret = __ignore_pool_test_ipv4(ip, ct); - break; - case AF_INET6: - ret = __ignore_pool_test_ipv6(ip, ct); - break; - default: - dlog(LOG_WARNING, "unknown layer 3 protocol?"); - break; - } - - return ret; -} diff --git a/src/netlink.c b/src/netlink.c index 387062d..1823280 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -19,7 +19,7 @@ #include "netlink.h" #include "conntrackd.h" #include "traffic_stats.h" -#include "ignore.h" +#include "filter.h" #include "log.h" #include "debug.h" @@ -28,10 +28,6 @@ int ignore_conntrack(struct nf_conntrack *ct) { - /* ignore a certain protocol */ - if (CONFIG(ignore_protocol)[nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO)]) - return 1; - /* Accept DNAT'ed traffic: not really coming to the local machine */ if (nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) { debug_ct(ct, "DNAT"); @@ -45,7 +41,7 @@ int ignore_conntrack(struct nf_conntrack *ct) } /* Ignore traffic */ - if (ignore_pool_test(STATE(ignore_pool), ct)) { + if (!ct_filter_check(STATE(us_filter), ct)) { debug_ct(ct, "ignore traffic"); return 1; } @@ -57,10 +53,6 @@ static int event_handler(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data) { - /* - * Ignore this conntrack: it talks about a - * connection that is not interesting for us. - */ if (ignore_conntrack(ct)) return NFCT_CB_STOP; @@ -125,10 +117,6 @@ static int dump_handler(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data) { - /* - * Ignore this conntrack: it talks about a - * connection that is not interesting for us. - */ if (ignore_conntrack(ct)) return NFCT_CB_CONTINUE; diff --git a/src/read_config_lex.l b/src/read_config_lex.l index bdde3b6..584a4a3 100644 --- a/src/read_config_lex.l +++ b/src/read_config_lex.l @@ -68,11 +68,6 @@ notrack [N|n][O|o][T|t][R|r][A|a][C|c][K|k] "HashLimit" { return T_HASHLIMIT; } "Path" { return T_PATH; } "IgnoreProtocol" { return T_IGNORE_PROTOCOL; } -"UDP" { return T_UDP; } -"ICMP" { return T_ICMP; } -"VRRP" { return T_VRRP; } -"IGMP" { return T_IGMP; } -"TCP" { return T_TCP; } "IgnoreTrafficFor" { return T_IGNORE_TRAFFIC; } "StripNAT" { return T_STRIP_NAT; } "Backlog" { return T_BACKLOG; } @@ -103,12 +98,19 @@ notrack [N|n][O|o][T|t][R|r][A|a][C|c][K|k] "CLOSE_WAIT" { return T_CLOSE_WAIT; } "LAST_ACK" { return T_LAST_ACK; } "TIME_WAIT" { return T_TIME_WAIT; } -"CLOSE" { return T_CLOSE; } +"CLOSE" { return T_CLOSE; /* alias of CLOSED */ } +"CLOSED" { return T_CLOSE; } "LISTEN" { return T_LISTEN; } "LogFileBufferSize" { return T_STAT_BUFFER_SIZE; } "DestroyTimeout" { return T_DESTROY_TIMEOUT; } "McastSndSocketBuffer" { return T_MCAST_SNDBUFF; } "McastRcvSocketBuffer" { return T_MCAST_RCVBUFF; } +"Filter" { return T_FILTER; } +"Protocol" { return T_PROTOCOL; } +"Address" { return T_ADDRESS; } +"State" { return T_STATE; } +"Accept" { return T_ACCEPT; } +"Ignore" { return T_IGNORE; } {is_on} { return T_ON; } {is_off} { return T_OFF; } diff --git a/src/read_config_yy.y b/src/read_config_yy.y index b9c53be..2a1c88c 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -22,14 +22,13 @@ #include #include #include +#include #include #include "conntrackd.h" -#include "ignore.h" +#include "bitops.h" #include #include -extern struct state_replication_helper tcp_state_helper; - extern char *yytext; extern int yylineno; @@ -44,7 +43,7 @@ struct ct_conf conf; %token T_IPV4_ADDR T_IPV4_IFACE T_PORT T_HASHSIZE T_HASHLIMIT T_MULTICAST %token T_PATH T_UNIX T_REFRESH T_IPV6_ADDR T_IPV6_IFACE %token T_IGNORE_UDP T_IGNORE_ICMP T_IGNORE_TRAFFIC T_BACKLOG T_GROUP -%token T_LOG T_UDP T_ICMP T_IGMP T_VRRP T_TCP T_IGNORE_PROTOCOL +%token T_LOG T_UDP T_ICMP T_IGMP T_VRRP T_IGNORE_PROTOCOL %token T_LOCK T_STRIP_NAT T_BUFFER_SIZE_MAX_GROWN T_EXPIRE T_TIMEOUT %token T_GENERAL T_SYNC T_STATS T_RELAX_TRANSITIONS T_BUFFER_SIZE T_DELAY %token T_SYNC_MODE T_LISTEN_TO T_FAMILY T_RESEND_BUFFER_SIZE @@ -54,6 +53,7 @@ struct ct_conf conf; %token T_CLOSE_WAIT T_LAST_ACK T_TIME_WAIT T_CLOSE T_LISTEN %token T_SYSLOG T_WRITE_THROUGH T_STAT_BUFFER_SIZE T_DESTROY_TIMEOUT %token T_MCAST_RCVBUFF T_MCAST_SNDBUFF T_NOTRACK +%token T_FILTER T_ADDRESS T_PROTOCOL T_STATE T_ACCEPT T_IGNORE %token T_IP T_PATH_VAL %token T_NUMBER @@ -169,7 +169,15 @@ checksum: T_CHECKSUM T_OFF conf.mcast.checksum = 1; }; -ignore_traffic : T_IGNORE_TRAFFIC '{' ignore_traffic_options '}'; +ignore_traffic : T_IGNORE_TRAFFIC '{' ignore_traffic_options '}' +{ + ct_filter_set_logic(STATE(us_filter), + CT_FILTER_ADDRESS, + CT_FILTER_NEGATIVE); + + fprintf(stderr, "WARNING: The clause `IgnoreTrafficFor' is obsolete. " + "Use `Filter' instead.\n"); +}; ignore_traffic_options : | ignore_traffic_options ignore_traffic_option; @@ -185,15 +193,7 @@ ignore_traffic_option : T_IPV4_ADDR T_IP break; } - if (!STATE(ignore_pool)) { - STATE(ignore_pool) = ignore_pool_create(); - if (!STATE(ignore_pool)) { - fprintf(stderr, "Can't create ignore pool!\n"); - exit(EXIT_FAILURE); - } - } - - if (!ignore_pool_add(STATE(ignore_pool), &ip, AF_INET)) { + if (!ct_filter_add_ip(STATE(us_filter), &ip, AF_INET)) { if (errno == EEXIST) fprintf(stderr, "IP %s is repeated " "in the ignore pool\n", $2); @@ -218,15 +218,7 @@ ignore_traffic_option : T_IPV6_ADDR T_IP break; #endif - if (!STATE(ignore_pool)) { - STATE(ignore_pool) = ignore_pool_create(); - if (!STATE(ignore_pool)) { - fprintf(stderr, "Can't create ignore pool!\n"); - exit(EXIT_FAILURE); - } - } - - if (!ignore_pool_add(STATE(ignore_pool), &ip, AF_INET6)) { + if (!ct_filter_add_ip(STATE(us_filter), &ip, AF_INET6)) { if (errno == EEXIST) fprintf(stderr, "IP %s is repeated " "in the ignore pool\n", $2); @@ -380,7 +372,15 @@ unix_option : T_BACKLOG T_NUMBER conf.local.backlog = $2; }; -ignore_protocol: T_IGNORE_PROTOCOL '{' ignore_proto_list '}'; +ignore_protocol: T_IGNORE_PROTOCOL '{' ignore_proto_list '}' +{ + ct_filter_set_logic(STATE(us_filter), + CT_FILTER_L4PROTO, + CT_FILTER_NEGATIVE); + + fprintf(stderr, "WARNING: The clause `IgnoreProtocol' is obsolete. " + "Use `Filter' instead.\n"); +}; ignore_proto_list: | ignore_proto_list ignore_proto @@ -389,29 +389,22 @@ ignore_proto_list: ignore_proto: T_NUMBER { if ($1 < IPPROTO_MAX) - conf.ignore_protocol[$1] = 1; + ct_filter_add_proto(STATE(us_filter), $1); else fprintf(stderr, "Protocol number `%d' is freak\n", $1); }; -ignore_proto: T_UDP +ignore_proto: T_STRING { - conf.ignore_protocol[IPPROTO_UDP] = 1; -}; + struct protoent *pent; -ignore_proto: T_ICMP -{ - conf.ignore_protocol[IPPROTO_ICMP] = 1; -}; - -ignore_proto: T_VRRP -{ - conf.ignore_protocol[IPPROTO_VRRP] = 1; -}; - -ignore_proto: T_IGMP -{ - conf.ignore_protocol[IPPROTO_IGMP] = 1; + pent = getprotobyname($1); + if (pent == NULL) { + fprintf(stderr, "getprotobyname() cannot find " + "protocol `%s' in /etc/protocols.\n", $1); + break; + } + ct_filter_add_proto(STATE(us_filter), pent->p_proto); }; sync: T_SYNC '{' sync_list '}' @@ -538,49 +531,81 @@ listen_to: T_LISTEN_TO T_IP } }; -state_replication: T_REPLICATE states T_FOR state_proto; +state_replication: T_REPLICATE states T_FOR state_proto +{ + ct_filter_set_logic(STATE(us_filter), + CT_FILTER_STATE, + CT_FILTER_POSITIVE); + + fprintf(stderr, "WARNING: The clause `Replicate' is obsolete. " + "Use `Filter' instead.\n"); +}; states: | states state; -state_proto: T_TCP; +state_proto: T_STRING +{ + if (strncmp($1, "TCP", strlen("TCP")) != 0) { + fprintf(stderr, "Unsupported protocol `%s' in line %d.\n", + $1, yylineno); + } +}; state: tcp_state; tcp_state: T_SYN_SENT { - state_helper_register(&tcp_state_helper, TCP_CONNTRACK_SYN_SENT); + ct_filter_add_state(STATE(us_filter), + IPPROTO_TCP, + TCP_CONNTRACK_SYN_SENT); }; tcp_state: T_SYN_RECV { - state_helper_register(&tcp_state_helper, TCP_CONNTRACK_SYN_RECV); + ct_filter_add_state(STATE(us_filter), + IPPROTO_TCP, + TCP_CONNTRACK_SYN_RECV); }; tcp_state: T_ESTABLISHED { - state_helper_register(&tcp_state_helper, TCP_CONNTRACK_ESTABLISHED); + ct_filter_add_state(STATE(us_filter), + IPPROTO_TCP, + TCP_CONNTRACK_ESTABLISHED); }; tcp_state: T_FIN_WAIT { - state_helper_register(&tcp_state_helper, TCP_CONNTRACK_FIN_WAIT); + ct_filter_add_state(STATE(us_filter), + IPPROTO_TCP, + TCP_CONNTRACK_FIN_WAIT); }; tcp_state: T_CLOSE_WAIT { - state_helper_register(&tcp_state_helper, TCP_CONNTRACK_CLOSE_WAIT); + ct_filter_add_state(STATE(us_filter), + IPPROTO_TCP, + TCP_CONNTRACK_CLOSE_WAIT); }; tcp_state: T_LAST_ACK { - state_helper_register(&tcp_state_helper, TCP_CONNTRACK_LAST_ACK); + ct_filter_add_state(STATE(us_filter), + IPPROTO_TCP, + TCP_CONNTRACK_LAST_ACK); }; tcp_state: T_TIME_WAIT { - state_helper_register(&tcp_state_helper, TCP_CONNTRACK_TIME_WAIT); + ct_filter_add_state(STATE(us_filter), + IPPROTO_TCP, + TCP_CONNTRACK_TIME_WAIT); }; tcp_state: T_CLOSE { - state_helper_register(&tcp_state_helper, TCP_CONNTRACK_CLOSE); + ct_filter_add_state(STATE(us_filter), + IPPROTO_TCP, + TCP_CONNTRACK_CLOSE); }; tcp_state: T_LISTEN { - state_helper_register(&tcp_state_helper, TCP_CONNTRACK_LISTEN); + ct_filter_add_state(STATE(us_filter), + IPPROTO_TCP, + TCP_CONNTRACK_LISTEN); }; cache_writethrough: T_WRITE_THROUGH T_ON @@ -610,6 +635,7 @@ general_line: hashsize | netlink_buffer_size | netlink_buffer_size_max_grown | family + | filter ; netlink_buffer_size: T_BUFFER_SIZE T_NUMBER @@ -630,6 +656,122 @@ family : T_FAMILY T_STRING conf.family = AF_INET; }; +filter : T_FILTER '{' filter_list '}'; + +filter_list : + | filter_list filter_item; + +filter_item : T_PROTOCOL T_ACCEPT '{' filter_protocol_list '}' +{ + ct_filter_set_logic(STATE(us_filter), + CT_FILTER_L4PROTO, + CT_FILTER_POSITIVE); +}; + +filter_item : T_PROTOCOL T_IGNORE '{' filter_protocol_list '}' +{ + ct_filter_set_logic(STATE(us_filter), + CT_FILTER_L4PROTO, + CT_FILTER_NEGATIVE); +}; + +filter_protocol_list : + | filter_protocol_list filter_protocol_item; + +filter_protocol_item : T_STRING +{ + struct protoent *pent; + + pent = getprotobyname($1); + if (pent == NULL) { + fprintf(stderr, "getprotobyname() cannot find " + "protocol `%s' in /etc/protocols.\n", $1); + break; + } + ct_filter_add_proto(STATE(us_filter), pent->p_proto); +}; + +filter_item : T_ADDRESS T_ACCEPT '{' filter_address_list '}' +{ + ct_filter_set_logic(STATE(us_filter), + CT_FILTER_ADDRESS, + CT_FILTER_POSITIVE); +}; + +filter_item : T_ADDRESS T_IGNORE '{' filter_address_list '}' +{ + ct_filter_set_logic(STATE(us_filter), + CT_FILTER_ADDRESS, + CT_FILTER_NEGATIVE); +}; + +filter_address_list : + | filter_address_list filter_address_item; + +filter_address_item : T_IPV4_ADDR T_IP +{ + union inet_address ip; + + memset(&ip, 0, sizeof(union inet_address)); + + if (!inet_aton($2, &ip.ipv4)) { + fprintf(stderr, "%s is not a valid IPv4, ignoring", $2); + break; + } + + if (!ct_filter_add_ip(STATE(us_filter), &ip, AF_INET)) { + if (errno == EEXIST) + fprintf(stderr, "IP %s is repeated " + "in the ignore pool\n", $2); + if (errno == ENOSPC) + fprintf(stderr, "Too many IP in the ignore pool!\n"); + } +}; + +filter_address_item : T_IPV6_ADDR T_IP +{ + union inet_address ip; + + memset(&ip, 0, sizeof(union inet_address)); + +#ifdef HAVE_INET_PTON_IPV6 + if (inet_pton(AF_INET6, $2, &ip.ipv6) <= 0) { + fprintf(stderr, "%s is not a valid IPv6, ignoring", $2); + break; + } +#else + fprintf(stderr, "Cannot find inet_pton(), IPv6 unsupported!"); + break; +#endif + + if (!ct_filter_add_ip(STATE(us_filter), &ip, AF_INET6)) { + if (errno == EEXIST) + fprintf(stderr, "IP %s is repeated " + "in the ignore pool\n", $2); + if (errno == ENOSPC) + fprintf(stderr, "Too many IP in the ignore pool!\n"); + } +}; + +filter_item : T_STATE T_ACCEPT '{' filter_state_list '}' +{ + ct_filter_set_logic(STATE(us_filter), + CT_FILTER_STATE, + CT_FILTER_POSITIVE); +}; + +filter_item : T_STATE T_IGNORE '{' filter_state_list '}' +{ + ct_filter_set_logic(STATE(us_filter), + CT_FILTER_STATE, + CT_FILTER_NEGATIVE); +}; + +filter_state_list : + | filter_state_list filter_state_item; + +filter_state_item : states T_FOR state_proto ; + stats: T_STATS '{' stats_list '}' { if (conf.flags & CTD_SYNC_MODE) { @@ -762,15 +904,6 @@ init_config(char *filename) if (CONFIG(resend_queue_size) == 0) CONFIG(resend_queue_size) = 262144; - /* create empty pool */ - if (!STATE(ignore_pool)) { - STATE(ignore_pool) = ignore_pool_create(); - if (!STATE(ignore_pool)) { - fprintf(stderr, "Can't create ignore pool!\n"); - exit(EXIT_FAILURE); - } - } - /* default to a window size of 20 packets */ if (CONFIG(window_size) == 0) CONFIG(window_size) = 20; diff --git a/src/run.c b/src/run.c index cadcb4d..cf570d8 100644 --- a/src/run.c +++ b/src/run.c @@ -20,7 +20,7 @@ #include "conntrackd.h" #include "netlink.h" -#include "ignore.h" +#include "filter.h" #include "log.h" #include "alarm.h" #include "fds.h" @@ -39,7 +39,7 @@ void killer(int foo) nfct_close(STATE(event)); - ignore_pool_destroy(STATE(ignore_pool)); + ct_filter_destroy(STATE(us_filter)); local_server_destroy(&STATE(local)); STATE(mode)->kill(); diff --git a/src/state_helper.c b/src/state_helper.c deleted file mode 100644 index 9034864..0000000 --- a/src/state_helper.c +++ /dev/null @@ -1,44 +0,0 @@ -/* - * (C) 2006-2007 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "conntrackd.h" -#include "state_helper.h" - -static struct state_replication_helper *helper[IPPROTO_MAX]; - -int state_helper_verdict(int type, struct nf_conntrack *ct) -{ - uint8_t l4proto; - - if (type == NFCT_Q_DESTROY) - return ST_H_REPLICATE; - - l4proto = nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO); - if (helper[l4proto]) - return helper[l4proto]->verdict(helper[l4proto], ct); - - return ST_H_REPLICATE; -} - -void state_helper_register(struct state_replication_helper *h, int h_state) -{ - if (helper[h->proto] == NULL) - helper[h->proto] = h; - - helper[h->proto]->state |= (1 << h_state); -} diff --git a/src/state_helper_tcp.c b/src/state_helper_tcp.c deleted file mode 100644 index 88af35e..0000000 --- a/src/state_helper_tcp.c +++ /dev/null @@ -1,35 +0,0 @@ -/* - * (C) 2006-2007 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "conntrackd.h" -#include "state_helper.h" - -static int tcp_verdict(const struct state_replication_helper *h, - const struct nf_conntrack *ct) -{ - uint8_t t_state = nfct_get_attr_u8(ct, ATTR_TCP_STATE); - if (h->state & (1 << t_state)) - return ST_H_REPLICATE; - - return ST_H_SKIP; -} - -struct state_replication_helper tcp_state_helper = { - .proto = IPPROTO_TCP, - .verdict = tcp_verdict, -}; diff --git a/src/sync-mode.c b/src/sync-mode.c index 4b36935..0f3760e 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -20,7 +20,6 @@ #include "netlink.h" #include "traffic_stats.h" #include "log.h" -#include "state_helper.h" #include "cache.h" #include "conntrackd.h" #include "us-conntrack.h" @@ -390,9 +389,6 @@ static void mcast_send_sync(struct us_conntrack *u, int query) size_t len; struct nethdr *net; - if (!state_helper_verdict(query, u->ct)) - return; - net = BUILD_NETMSG(u->ct, query); len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); -- cgit v1.2.3 From 167a57cb822eb6ce3759f5de3a11c59849b494e4 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 23 Jul 2008 16:51:39 +0200 Subject: add support for kernel-space filtering via BSF This patch adds support for kernel-space filtering via BSF by means of the libnetfilter_conntrack's BSF high-level API. Signed-off-by: Pablo Neira Ayuso --- configure.in | 2 +- include/conntrackd.h | 2 ++ src/netlink.c | 14 ++++++++ src/read_config_yy.y | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 107 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/configure.in b/configure.in index 0a6b8fe..30eaba1 100644 --- a/configure.in +++ b/configure.in @@ -18,7 +18,7 @@ esac dnl Dependencies LIBNFNETLINK_REQUIRED=0.0.33 -LIBNETFILTER_CONNTRACK_REQUIRED=0.0.94 +LIBNETFILTER_CONNTRACK_REQUIRED=0.0.97 AC_CHECK_PROG(HAVE_PKG_CONFIG, pkg-config, yes) if test "x$HAVE_PKG_CONFIG" = "x" diff --git a/include/conntrackd.h b/include/conntrackd.h index cd02f1f..d2c8931 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -106,6 +106,8 @@ struct ct_general_state { struct ct_filter *us_filter; struct nfct_handle *event; /* event handler */ + struct nfct_filter *filter; /* event filter */ + struct nfct_handle *dump; /* dump handler */ struct nfct_handle *overrun; /* overrun handler */ struct alarm_block overrun_alarm; diff --git a/src/netlink.c b/src/netlink.c index 1823280..1287454 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -85,6 +85,20 @@ int nl_init_event_handler(void) if (!STATE(event)) return -1; + if (STATE(filter)) { + if (nfct_filter_attach(nfct_fd(STATE(event)), + STATE(filter)) == -1) { + dlog(LOG_NOTICE, "cannot set netlink kernel-space " + "event filtering, defaulting to " + "user-space. We suggest you to " + "upgrade your Linux kernel to " + ">= 2.6.26. Operation returns: %s", + strerror(errno)); + /* don't fail here, old kernels don't support this */ + } + nfct_filter_destroy(STATE(filter)); + } + fcntl(nfct_fd(STATE(event)), F_SETFL, O_NONBLOCK); /* set up socket buffer size */ diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 2a1c88c..33a435c 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -27,12 +27,16 @@ #include "conntrackd.h" #include "bitops.h" #include +#include #include extern char *yytext; extern int yylineno; struct ct_conf conf; + +static void __kernel_filter_start(void); +static void __kernel_filter_add_state(int value); %} %union { @@ -558,54 +562,72 @@ tcp_state: T_SYN_SENT ct_filter_add_state(STATE(us_filter), IPPROTO_TCP, TCP_CONNTRACK_SYN_SENT); + + __kernel_filter_add_state(TCP_CONNTRACK_SYN_SENT); }; tcp_state: T_SYN_RECV { ct_filter_add_state(STATE(us_filter), IPPROTO_TCP, TCP_CONNTRACK_SYN_RECV); + + __kernel_filter_add_state(TCP_CONNTRACK_SYN_RECV); }; tcp_state: T_ESTABLISHED { ct_filter_add_state(STATE(us_filter), IPPROTO_TCP, TCP_CONNTRACK_ESTABLISHED); + + __kernel_filter_add_state(TCP_CONNTRACK_ESTABLISHED); }; tcp_state: T_FIN_WAIT { ct_filter_add_state(STATE(us_filter), IPPROTO_TCP, TCP_CONNTRACK_FIN_WAIT); + + __kernel_filter_add_state(TCP_CONNTRACK_FIN_WAIT); }; tcp_state: T_CLOSE_WAIT { ct_filter_add_state(STATE(us_filter), IPPROTO_TCP, TCP_CONNTRACK_CLOSE_WAIT); + + __kernel_filter_add_state(TCP_CONNTRACK_CLOSE_WAIT); }; tcp_state: T_LAST_ACK { ct_filter_add_state(STATE(us_filter), IPPROTO_TCP, TCP_CONNTRACK_LAST_ACK); + + __kernel_filter_add_state(TCP_CONNTRACK_LAST_ACK); }; tcp_state: T_TIME_WAIT { ct_filter_add_state(STATE(us_filter), IPPROTO_TCP, TCP_CONNTRACK_TIME_WAIT); + + __kernel_filter_add_state(TCP_CONNTRACK_TIME_WAIT); }; tcp_state: T_CLOSE { ct_filter_add_state(STATE(us_filter), IPPROTO_TCP, TCP_CONNTRACK_CLOSE); + + __kernel_filter_add_state(TCP_CONNTRACK_CLOSE); }; tcp_state: T_LISTEN { ct_filter_add_state(STATE(us_filter), IPPROTO_TCP, TCP_CONNTRACK_LISTEN); + + __kernel_filter_add_state(TCP_CONNTRACK_LISTEN); }; cache_writethrough: T_WRITE_THROUGH T_ON @@ -666,6 +688,8 @@ filter_item : T_PROTOCOL T_ACCEPT '{' filter_protocol_list '}' ct_filter_set_logic(STATE(us_filter), CT_FILTER_L4PROTO, CT_FILTER_POSITIVE); + + __kernel_filter_start(); }; filter_item : T_PROTOCOL T_IGNORE '{' filter_protocol_list '}' @@ -673,6 +697,12 @@ filter_item : T_PROTOCOL T_IGNORE '{' filter_protocol_list '}' ct_filter_set_logic(STATE(us_filter), CT_FILTER_L4PROTO, CT_FILTER_NEGATIVE); + + __kernel_filter_start(); + + nfct_filter_set_logic(STATE(filter), + NFCT_FILTER_L4PROTO, + NFCT_FILTER_LOGIC_NEGATIVE); }; filter_protocol_list : @@ -689,6 +719,12 @@ filter_protocol_item : T_STRING break; } ct_filter_add_proto(STATE(us_filter), pent->p_proto); + + __kernel_filter_start(); + + nfct_filter_add_attr_u32(STATE(filter), + NFCT_FILTER_L4PROTO, + pent->p_proto); }; filter_item : T_ADDRESS T_ACCEPT '{' filter_address_list '}' @@ -696,6 +732,8 @@ filter_item : T_ADDRESS T_ACCEPT '{' filter_address_list '}' ct_filter_set_logic(STATE(us_filter), CT_FILTER_ADDRESS, CT_FILTER_POSITIVE); + + __kernel_filter_start(); }; filter_item : T_ADDRESS T_IGNORE '{' filter_address_list '}' @@ -703,6 +741,15 @@ filter_item : T_ADDRESS T_IGNORE '{' filter_address_list '}' ct_filter_set_logic(STATE(us_filter), CT_FILTER_ADDRESS, CT_FILTER_NEGATIVE); + + __kernel_filter_start(); + + nfct_filter_set_logic(STATE(filter), + NFCT_FILTER_SRC_IPV4, + NFCT_FILTER_LOGIC_NEGATIVE); + nfct_filter_set_logic(STATE(filter), + NFCT_FILTER_DST_IPV4, + NFCT_FILTER_LOGIC_NEGATIVE); }; filter_address_list : @@ -726,6 +773,16 @@ filter_address_item : T_IPV4_ADDR T_IP if (errno == ENOSPC) fprintf(stderr, "Too many IP in the ignore pool!\n"); } + + __kernel_filter_start(); + + struct nfct_filter_ipv4 filter_ipv4 = { + .addr = htonl(ip.ipv4), + .mask = 0xffffffff, + }; + + nfct_filter_add_attr(STATE(filter), NFCT_FILTER_SRC_IPV4, &filter_ipv4); + nfct_filter_add_attr(STATE(filter), NFCT_FILTER_DST_IPV4, &filter_ipv4); }; filter_address_item : T_IPV6_ADDR T_IP @@ -758,6 +815,8 @@ filter_item : T_STATE T_ACCEPT '{' filter_state_list '}' ct_filter_set_logic(STATE(us_filter), CT_FILTER_STATE, CT_FILTER_POSITIVE); + + __kernel_filter_start(); }; filter_item : T_STATE T_IGNORE '{' filter_state_list '}' @@ -765,6 +824,13 @@ filter_item : T_STATE T_IGNORE '{' filter_state_list '}' ct_filter_set_logic(STATE(us_filter), CT_FILTER_STATE, CT_FILTER_NEGATIVE); + + + __kernel_filter_start(); + + nfct_filter_set_logic(STATE(filter), + NFCT_FILTER_L4PROTO_STATE, + NFCT_FILTER_LOGIC_NEGATIVE); }; filter_state_list : @@ -864,6 +930,30 @@ yyerror(char *msg) exit(EXIT_FAILURE); } +static void __kernel_filter_start(void) +{ + if (!STATE(filter)) { + STATE(filter) = nfct_filter_create(); + if (!STATE(filter)) { + fprintf(stderr, "Can't create ignore pool!\n"); + exit(EXIT_FAILURE); + } + } +} + +static void __kernel_filter_add_state(int value) +{ + __kernel_filter_start(); + + struct nfct_filter_proto filter_proto = { + .proto = IPPROTO_TCP, + .state = value + }; + nfct_filter_add_attr(STATE(filter), + NFCT_FILTER_L4PROTO_STATE, + &filter_proto); +} + int init_config(char *filename) { -- cgit v1.2.3 From f52bcb906ba05f67a0a54dfeb9abff0ba6a02c89 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 24 Jul 2008 09:28:32 +0200 Subject: log: syslog displays the entry that triggers the error This patch fixes an inconsistency in the output. If syslog was chosen as logger, the conntrack entries that triggered an error were not displayed. Signed-off-by: Pablo Neira Ayuso --- src/log.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/log.c b/src/log.c index d97a69f..9fe5119 100644 --- a/src/log.c +++ b/src/log.c @@ -134,8 +134,15 @@ void dlog_ct(FILE *fd, struct nf_conntrack *ct, unsigned int type) fputs(buf, fd); } - if (CONFIG(stats).syslog_facility != -1) - syslog(LOG_INFO, "%s", tmp); + if (fd == STATE(log)) { + /* error reporting */ + if (CONFIG(syslog_facility) != -1) + syslog(LOG_ERR, "%s", tmp); + } else if (fd == STATE(stats_log)) { + /* connection logging */ + if (CONFIG(stats).syslog_facility != -1) + syslog(LOG_INFO, "%s", tmp); + } } void close_log(void) -- cgit v1.2.3 From b0a327b7a8fda0ebe936839235394de03b520f5e Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 29 Jul 2008 16:01:41 +0200 Subject: filter: skip protocol state filtering if state not present Skip user-space the protocol state filter if the protocol state is not present in the event message. Signed-off-by: Pablo Neira Ayuso --- src/filter.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/filter.c b/src/filter.c index 6e4d64a..eaf0a93 100644 --- a/src/filter.c +++ b/src/filter.c @@ -192,6 +192,9 @@ static int __ct_filter_test_state(struct ct_filter *f, struct nf_conntrack *ct) switch(protonum) { case IPPROTO_TCP: + if (!nfct_attr_is_set(ct, ATTR_TCP_STATE)) + return -1; + val = nfct_get_attr_u8(ct, ATTR_TCP_STATE); break; default: -- cgit v1.2.3 From 21aabc2c4248d389fbf18a9110443371cc678b53 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 29 Jul 2008 17:53:18 +0200 Subject: CLI: add new option --buffer-size for -E Add new option --buffer-size for -E to set the netlink socket buffer size. Signed-off-by: Pablo Neira Ayuso --- conntrack.8 | 10 +++++++++ include/conntrack.h | 5 ++++- src/conntrack.c | 61 +++++++++++++++++++++++++++++++++++++---------------- 3 files changed, 57 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/conntrack.8 b/conntrack.8 index 7c4a168..bfb2de0 100644 --- a/conntrack.8 +++ b/conntrack.8 @@ -82,6 +82,16 @@ event code. Using this parameter, you can reduce the event messages generated by the kernel to those types to those that you are actually interested in. . This option can only be used in conjunction with "-E, --event". +.BI "-b, --buffer-size " "value (in bytes)" +Set the Netlink socket buffer size. This option is useful if the command line +tool reports ENOBUFS errors. If you do not pass this option, the default value +available at /proc/sys/net/core/rmem_default is used. The tool reports this +problem if your process is too slow to handle all the event messages or, in +other words, if the amount of events are big enough to overrun the socket +buffer. Note that using a big buffer reduces the chances to hit ENOBUFS, +however, this results in more memory consumption. +. +This option can only be used in conjunction with "-E, --event". .SS FILTER PARAMETERS .TP .BI "-s, --orig-src " IP_ADDRESS diff --git a/include/conntrack.h b/include/conntrack.h index dc30c13..e8059c8 100644 --- a/include/conntrack.h +++ b/include/conntrack.h @@ -132,8 +132,11 @@ enum options { CT_OPT_SECMARK_BIT = 20, CT_OPT_SECMARK = (1 << CT_OPT_SECMARK_BIT), + + CT_OPT_BUFFERSIZE_BIT = 21, + CT_OPT_BUFFERSIZE = (1 << CT_OPT_BUFFERSIZE_BIT), - CT_OPT_MAX = CT_OPT_SECMARK_BIT + CT_OPT_MAX = CT_OPT_BUFFERSIZE_BIT }; #define NUMBER_OF_OPT CT_OPT_MAX+1 diff --git a/src/conntrack.c b/src/conntrack.c index 1ee98e3..7400c1b 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -64,7 +64,7 @@ static const char cmd_need_param[NUMBER_OF_CMD] static const char *optflags[NUMBER_OF_OPT] = { "src","dst","reply-src","reply-dst","protonum","timeout","status","zero", "event-mask","tuple-src","tuple-dst","mask-src","mask-dst","nat-range","mark", -"id","family","src-nat","dst-nat","output","secmark"}; +"id","family","src-nat","dst-nat","output","secmark","buffersize"}; static struct option original_opts[] = { {"dump", 2, 0, 'L'}, @@ -99,6 +99,7 @@ static struct option original_opts[] = { {"src-nat", 2, 0, 'n'}, {"dst-nat", 2, 0, 'g'}, {"output", 1, 0, 'o'}, + {"buffer-size", 1, 0, 'b'}, {0, 0, 0, 0} }; @@ -120,22 +121,22 @@ static unsigned int global_option_offset = 0; static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = /* Well, it's better than "Re: Linux vs FreeBSD" */ { - /* s d r q p t u z e [ ] { } a m i f n g o c */ -/*CT_LIST*/ {2,2,2,2,2,0,2,2,0,0,0,0,0,0,2,0,2,2,2,2,2}, -/*CT_CREATE*/ {2,2,2,2,1,1,1,0,0,0,0,0,0,2,2,0,0,2,2,0,0}, -/*CT_UPDATE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,0}, -/*CT_DELETE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,0}, -/*CT_GET*/ {2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,2,0,0,0,2,0}, -/*CT_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*CT_EVENT*/ {2,2,2,2,2,0,0,0,2,0,0,0,0,0,2,0,0,2,2,2,2}, -/*VERSION*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*HELP*/ {0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*EXP_LIST*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0}, -/*EXP_CREATE*/{1,1,2,2,1,1,2,0,0,1,1,1,1,0,0,0,0,0,0,0,0}, -/*EXP_DELETE*/{1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*EXP_GET*/ {1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*EXP_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*EXP_EVENT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + /* s d r q p t u z e [ ] { } a m i f n g o c b*/ +/*CT_LIST*/ {2,2,2,2,2,0,2,2,0,0,0,0,0,0,2,0,2,2,2,2,2,0}, +/*CT_CREATE*/ {2,2,2,2,1,1,1,0,0,0,0,0,0,2,2,0,0,2,2,0,0,0}, +/*CT_UPDATE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0}, +/*CT_DELETE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0}, +/*CT_GET*/ {2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,2,0,0,0,2,0,0}, +/*CT_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*CT_EVENT*/ {2,2,2,2,2,0,0,0,2,0,0,0,0,0,2,0,0,2,2,2,2,2}, +/*VERSION*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*HELP*/ {0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*EXP_LIST*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0}, +/*EXP_CREATE*/{1,1,2,2,1,1,2,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0}, +/*EXP_DELETE*/{1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*EXP_GET*/ {1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*EXP_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*EXP_EVENT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, }; static LIST_HEAD(proto_list); @@ -540,6 +541,7 @@ static const char usage_parameters[] = " -f, --family proto\t\tLayer 3 Protocol, eg. 'ipv6'\n" " -t, --timeout timeout\t\tSet timeout\n" " -u, --status status\t\tSet status, eg. ASSURED\n" + " -b, --buffer-size\t\tNetlink socket buffer size\n" ; @@ -907,6 +909,7 @@ int main(int argc, char *argv[]) int c, cmd; unsigned int type = 0, event_mask = 0, l4flags = 0, status = 0; int res = 0; + size_t socketbuffersize = 0; int family = AF_UNSPEC; char __obj[nfct_maxsize()]; char __exptuple[nfct_maxsize()]; @@ -933,7 +936,7 @@ int main(int argc, char *argv[]) while ((c = getopt_long(argc, argv, "L::I::U::D::G::E::F::hVs:d:r:q:" "p:t:u:e:a:z[:]:{:}:m:i:f:o:n::" - "g::c:", + "g::c:b:", opts, NULL)) != -1) { switch(c) { /* commands */ @@ -1105,6 +1108,10 @@ int main(int argc, char *argv[]) "`%s' unsupported protocol", optarg); break; + case 'b': + socketbuffersize = atol(optarg); + options |= CT_OPT_BUFFERSIZE; + break; default: if (h && h->parse_opts &&!h->parse_opts(c - h->option_offset, obj, @@ -1297,10 +1304,28 @@ int main(int argc, char *argv[]) if (!cth) exit_error(OTHER_PROBLEM, "Can't open handler"); + + if (options & CT_OPT_BUFFERSIZE) { + size_t ret; + ret = nfnl_rcvbufsiz(nfct_nfnlh(cth), socketbuffersize); + fprintf(stderr, "NOTICE: Netlink socket buffer size " + "has been set to %u bytes.\n", ret); + } signal(SIGINT, event_sighandler); signal(SIGTERM, event_sighandler); nfct_callback_register(cth, NFCT_T_ALL, event_cb, obj); res = nfct_catch(cth); + if (res == -1) { + if (errno == ENOBUFS) { + fprintf(stderr, + "WARNING: We have hit ENOBUFS! We " + "are losing events.\nThis message " + "means that the current netlink " + "socket buffer size is too small.\n" + "Please, check --buffer-size in " + "conntrack(8) manpage.\n"); + } + } nfct_close(cth); break; -- cgit v1.2.3 From fa4eb049a549dfdd48a8f59ef2713694716a6811 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 1 Aug 2008 00:05:45 +0200 Subject: add more sanity checks in the input path Some users have reported crashes when nf_conntrack_ipv6 was not present. This patch performs more robust sanity checks in the input path. Signed-off-by: Pablo Neira Ayuso --- src/cache.c | 8 -------- src/netlink.c | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/cache.c b/src/cache.c index c72afd8..a73854f 100644 --- a/src/cache.c +++ b/src/cache.c @@ -75,14 +75,6 @@ static uint32_t hash(const void *data, struct hashtable *table) ret = __hash4(u->ct, table); break; case AF_INET6: - if (!nfct_attr_is_set(u->ct, ATTR_ORIG_IPV6_SRC) || - !nfct_attr_is_set(u->ct, ATTR_ORIG_IPV6_DST)) { - dlog(LOG_ERR, "missing IPv6 address. " - "You forgot to load " - "nf_conntrack_ipv6?"); - return 0; - } - ret = __hash6(u->ct, table); break; default: diff --git a/src/netlink.c b/src/netlink.c index 1287454..a8a5503 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -26,8 +26,46 @@ #include #include +static int sanity_check(struct nf_conntrack *ct) +{ + if (!nfct_attr_is_set(ct, ATTR_L3PROTO)) { + dlog(LOG_ERR, "missing layer 3 protocol"); + return 0; + } + + switch(nfct_get_attr_u8(ct, ATTR_L3PROTO)) { + case AF_INET: + if (!nfct_attr_is_set(ct, ATTR_IPV4_SRC) || + !nfct_attr_is_set(ct, ATTR_IPV4_DST) || + !nfct_attr_is_set(ct, ATTR_REPL_IPV4_SRC) || + !nfct_attr_is_set(ct, ATTR_REPL_IPV4_DST)) { + dlog(LOG_ERR, "missing IPv4 address. " + "You forgot to load " + "nf_conntrack_ipv4?"); + return 0; + } + break; + case AF_INET6: + if (!nfct_attr_is_set(ct, ATTR_IPV6_SRC) || + !nfct_attr_is_set(ct, ATTR_IPV6_DST) || + !nfct_attr_is_set(ct, ATTR_REPL_IPV6_SRC) || + !nfct_attr_is_set(ct, ATTR_REPL_IPV6_DST)) { + dlog(LOG_ERR, "missing IPv6 address. " + "You forgot to load " + "nf_conntrack_ipv6?"); + return 0; + } + break; + } + return 1; +} + int ignore_conntrack(struct nf_conntrack *ct) { + /* missing mandatory attributes in object */ + if (!sanity_check(ct)) + return 1; + /* Accept DNAT'ed traffic: not really coming to the local machine */ if (nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) { debug_ct(ct, "DNAT"); -- cgit v1.2.3 From e1c1dc00eb78f4255fbed0793bd205b42b3d4141 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Fri, 1 Aug 2008 11:00:22 +0200 Subject: commit: retry at least once if we hit ETIME or ENOMEM Some users are reporting ETIME errors in the update. This happens when you try to update a conntrack that is expiring. To avoid this problem, we retry once at least. We do similar for ENOMEM errors, although only users in virtual machines have reported this AFAIK. Signed-off-by: Pablo Neira Ayuso --- src/cache_iterators.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/cache_iterators.c b/src/cache_iterators.c index 562d9a2..e9ddbc0 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -24,6 +24,7 @@ #include "us-conntrack.h" #include +#include #include #include @@ -80,7 +81,7 @@ void cache_dump(struct cache *c, int fd, int type) /* no need to clone, called from child process */ static int do_commit(void *data1, void *data2) { - int ret; + int ret, retry = 1; struct cache *c = data1; struct us_conntrack *u = data2; struct nf_conntrack *ct = u->ct; @@ -98,7 +99,15 @@ static int do_commit(void *data1, void *data2) dlog_ct(STATE(log), ct, NFCT_O_PLAIN); break; case 0: +try_again_create: if (nl_create_conntrack(ct) == -1) { + if (errno == ENOMEM) { + if (retry) { + retry = 0; + sched_yield(); + goto try_again_create; + } + } dlog(LOG_ERR, "commit-create: %s", strerror(errno)); dlog_ct(STATE(log), ct, NFCT_O_PLAIN); c->commit_fail++; @@ -107,7 +116,15 @@ static int do_commit(void *data1, void *data2) break; case 1: c->commit_exist++; +try_again_update: if (nl_update_conntrack(ct) == -1) { + if (errno == ENOMEM || errno == ETIME) { + if (retry) { + retry = 0; + sched_yield(); + goto try_again_update; + } + } dlog(LOG_ERR, "commit-update: %s", strerror(errno)); dlog_ct(STATE(log), ct, NFCT_O_PLAIN); c->commit_fail++; -- cgit v1.2.3 From 1d3c3133107aea0d054fc444bf61b48ba3bf77cd Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 1 Aug 2008 11:27:27 +0200 Subject: fix: use %zu instead of %u for size_t Use %zu instead of %u for size_t to remove compilation warning. Signed-off-by: Pablo Neira Ayuso --- src/conntrack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index 7400c1b..cc19b5d 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -1309,7 +1309,7 @@ int main(int argc, char *argv[]) size_t ret; ret = nfnl_rcvbufsiz(nfct_nfnlh(cth), socketbuffersize); fprintf(stderr, "NOTICE: Netlink socket buffer size " - "has been set to %u bytes.\n", ret); + "has been set to %zu bytes.\n", ret); } signal(SIGINT, event_sighandler); signal(SIGTERM, event_sighandler); -- cgit v1.2.3 From ff402549052eb4b98ac9404a2f273d78ce323c94 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 1 Aug 2008 12:50:28 +0200 Subject: fix: wrong use of timersub in cache_timer Fix wrong output in the dump of the expire timer which was negative. Signed-off-by: Pablo Neira Ayuso --- src/cache_timer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/cache_timer.c b/src/cache_timer.c index 6619c2c..44482b7 100644 --- a/src/cache_timer.c +++ b/src/cache_timer.c @@ -64,7 +64,7 @@ static int timer_dump(struct us_conntrack *u, void *data, char *buf, int type) return 0; gettimeofday(&tv, NULL); - timersub(&tv, &alarm->tv, &tmp); + timersub(&alarm->tv, &tv, &tmp); return sprintf(buf, " [expires in %lds]", tmp.tv_sec); } -- cgit v1.2.3 From 6356d191a6d97483ad904fa1c8279a30564220cf Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 1 Aug 2008 14:35:47 +0200 Subject: fix broken normal deletion in caches This patch fixes the non-timer-based cache deletion. This bug affects the alarm-based approach since the backup replicas did not get the deletion event, thus, delaying the deletion. This patch introduces cache_find() to look up for a conntrack object and __cache_del_timer() to perform direct deletions by means of the pointer obtained with cache_find(). Signed-off-by: Pablo Neira Ayuso --- include/cache.h | 3 ++- src/cache.c | 62 ++++++++++++++++++++++++++++----------------------------- src/sync-mode.c | 19 +++++++++--------- 3 files changed, 42 insertions(+), 42 deletions(-) (limited to 'src') diff --git a/include/cache.h b/include/cache.h index 442a563..e2e2e34 100644 --- a/include/cache.h +++ b/include/cache.h @@ -82,7 +82,8 @@ struct us_conntrack *cache_add(struct cache *c, struct nf_conntrack *ct); struct us_conntrack *cache_update(struct cache *c, struct nf_conntrack *ct); struct us_conntrack *cache_update_force(struct cache *c, struct nf_conntrack *ct); int cache_del(struct cache *c, struct nf_conntrack *ct); -struct us_conntrack *cache_del_timeout(struct cache *c, struct nf_conntrack *ct, int timeout); +int __cache_del_timer(struct cache *c, struct us_conntrack *u, int timeout); +struct us_conntrack *cache_find(struct cache *c, struct nf_conntrack *ct); int cache_test(struct cache *c, struct nf_conntrack *ct); void cache_stats(const struct cache *c, int fd); struct us_conntrack *cache_get_conntrack(struct cache *, void *); diff --git a/src/cache.c b/src/cache.c index a73854f..7cd5ac7 100644 --- a/src/cache.c +++ b/src/cache.c @@ -321,7 +321,13 @@ static void __del2(struct cache *c, struct us_conntrack *u) free(p); } -static int __del(struct cache *c, struct nf_conntrack *ct) +static void __cache_del(struct cache *c, struct us_conntrack *u) +{ + del_alarm(&u->alarm); + __del2(c, u); +} + +int cache_del(struct cache *c, struct nf_conntrack *ct) { size_t size = c->h->datasize; char buf[size]; @@ -331,16 +337,7 @@ static int __del(struct cache *c, struct nf_conntrack *ct) u = (struct us_conntrack *) hashtable_test(c->h, u); if (u) { - del_alarm(&u->alarm); - __del2(c, u); - return 1; - } - return 0; -} - -int cache_del(struct cache *c, struct nf_conntrack *ct) -{ - if (__del(c, ct)) { + __cache_del(c, u); c->del_ok++; return 1; } @@ -356,33 +353,36 @@ static void __del_timeout(struct alarm_block *a, void *data) __del2(u->cache, u); } -struct us_conntrack * -cache_del_timeout(struct cache *c, struct nf_conntrack *ct, int timeout) +int +__cache_del_timer(struct cache *c, struct us_conntrack *u, int timeout) +{ + if (timeout <= 0) { + __cache_del(c, u); + return 1; + } + if (!alarm_pending(&u->alarm)) { + add_alarm(&u->alarm, timeout, 0); + /* + * increase stats even if this entry was not really + * removed yet. We do not want to make people think + * that the replication protocol does not work + * properly. + */ + c->del_ok++; + return 1; + } + return 0; +} + +struct us_conntrack *cache_find(struct cache *c, struct nf_conntrack *ct) { size_t size = c->h->datasize; char buf[size]; struct us_conntrack *u = (struct us_conntrack *) buf; - if (timeout <= 0) - cache_del(c, ct); - u->ct = ct; - u = (struct us_conntrack *) hashtable_test(c->h, u); - if (u) { - if (!alarm_pending(&u->alarm)) { - add_alarm(&u->alarm, timeout, 0); - /* - * increase stats even if this entry was not really - * removed yet. We do not want to make people think - * that the replication protocol does not work - * properly. - */ - c->del_ok++; - return u; - } - } - return NULL; + return ((struct us_conntrack *) hashtable_test(c->h, u)); } struct us_conntrack *cache_get_conntrack(struct cache *c, void *data) diff --git a/src/sync-mode.c b/src/sync-mode.c index 0f3760e..56c30af 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -407,10 +407,8 @@ static int purge_step(void *data1, void *data2) ret = nfct_query(h, NFCT_Q_GET, u->ct); if (ret == -1 && errno == ENOENT) { debug_ct(u->ct, "overrun purge resync"); - if (cache_del_timeout(STATE_SYNC(internal), - u->ct, - CONFIG(del_timeout))) - mcast_send_sync(u, NFCT_Q_DESTROY); + mcast_send_sync(u, NFCT_Q_DESTROY); + __cache_del_timer(STATE_SYNC(internal), u, CONFIG(del_timeout)); } return 0; @@ -502,15 +500,16 @@ static int event_destroy_sync(struct nf_conntrack *ct) if (!CONFIG(cache_write_through)) nfct_attr_unset(ct, ATTR_TIMEOUT); - u = cache_del_timeout(STATE_SYNC(internal), ct, CONFIG(del_timeout)); - if (u != NULL) { - mcast_send_sync(u, NFCT_Q_DESTROY); - debug_ct(ct, "internal destroy"); - return 1; - } else { + u = cache_find(STATE_SYNC(internal), ct); + if (u == NULL) { debug_ct(ct, "can't destroy"); return 0; } + + mcast_send_sync(u, NFCT_Q_DESTROY); + __cache_del_timer(STATE_SYNC(internal), u, CONFIG(del_timeout)); + debug_ct(ct, "internal destroy"); + return 1; } struct ct_mode sync_mode = { -- cgit v1.2.3 From 9de87ff1c675f7ae5f463c4820bffb502e7ce852 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 1 Aug 2008 17:52:54 +0200 Subject: ftfw: show consistent information to users for problem diagnosing This patch hides information that may confuse users while they are diagnosing problems in their setup. For example, we hide entries that are schedule to expire - from the user side, they are already destroyed entries; and we show in the counters the real active entries, not all that are stored in the caches. Signed-off-by: Pablo Neira Ayuso --- include/cache.h | 2 ++ src/cache.c | 14 ++++++++++++-- src/cache_iterators.c | 13 +++++++++++++ src/cache_lifetime.c | 8 +------- 4 files changed, 28 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/include/cache.h b/include/cache.h index e2e2e34..ba8d3aa 100644 --- a/include/cache.h +++ b/include/cache.h @@ -50,6 +50,8 @@ struct cache { unsigned int extra_offset; /* statistics */ + unsigned int active; + unsigned int add_ok; unsigned int del_ok; unsigned int upd_ok; diff --git a/src/cache.c b/src/cache.c index 7cd5ac7..820a385 100644 --- a/src/cache.c +++ b/src/cache.c @@ -208,6 +208,7 @@ static struct us_conntrack *__add(struct cache *c, struct nf_conntrack *ct) if (c->extra && c->extra->add) c->extra->add(u, ((char *) u) + c->extra_offset); + c->active++; return u; } free(newct); @@ -323,6 +324,15 @@ static void __del2(struct cache *c, struct us_conntrack *u) static void __cache_del(struct cache *c, struct us_conntrack *u) { + /* + * Do not increase stats if we are trying to + * kill an entry was previously deleted via + * __cache_del_timer. + */ + if (!alarm_pending(&u->alarm)) { + c->del_ok++; + c->active--; + } del_alarm(&u->alarm); __del2(c, u); } @@ -338,7 +348,6 @@ int cache_del(struct cache *c, struct nf_conntrack *ct) u = (struct us_conntrack *) hashtable_test(c->h, u); if (u) { __cache_del(c, u); - c->del_ok++; return 1; } c->del_fail++; @@ -369,6 +378,7 @@ __cache_del_timer(struct cache *c, struct us_conntrack *u, int timeout) * properly. */ c->del_ok++; + c->active--; return 1; } return 0; @@ -406,7 +416,7 @@ void cache_stats(const struct cache *c, int fd) "connections updated:\t\t%12u\tfailed:\t%12u\n" "connections destroyed:\t\t%12u\tfailed:\t%12u\n\n", c->name, - hashtable_counter(c->h), + c->active, c->add_ok, c->add_fail, c->upd_ok, diff --git a/src/cache_iterators.c b/src/cache_iterators.c index e9ddbc0..407db0b 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -42,6 +42,19 @@ static int do_dump(void *data1, void *data2) char *data = u->data; unsigned i; + /* + * XXX: Do not dump the entries that are scheduled to expire. + * These entries talk about already destroyed connections + * that we keep for some time just in case that we have to + * resent some lost messages. We do not show them to the + * user as he may think that the firewall replicas are not + * in sync. The branch below is a hack as it is quite + * specific and it breaks conntrackd modularity. Probably + * there's a nicer way to do this but until I come up with it... + */ + if (CONFIG(flags) & CTD_SYNC_FTFW && alarm_pending(&u->alarm)) + return 0; + memset(buf, 0, sizeof(buf)); size = nfct_snprintf(buf, sizeof(buf), diff --git a/src/cache_lifetime.c b/src/cache_lifetime.c index cf84d20..ad3416a 100644 --- a/src/cache_lifetime.c +++ b/src/cache_lifetime.c @@ -53,13 +53,7 @@ static int lifetime_dump(struct us_conntrack *u, gettimeofday(&tv, NULL); - if (alarm_pending(&u->alarm)) - return sprintf(buf, " [active since %lds] [expires in %lds]", - tv.tv_sec - *lifetime, - u->alarm.tv.tv_sec - tv.tv_sec); - else - return sprintf(buf, " [active since %lds]", - tv.tv_sec - *lifetime); + return sprintf(buf, " [active since %lds]", tv.tv_sec - *lifetime); } struct cache_feature lifetime_feature = { -- cgit v1.2.3 From 16010f777b090b293a00072d8368e94418cc99f8 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 2 Aug 2008 18:59:36 +0200 Subject: conntrackd: add -t option to shorten conntrack timeouts This patch adds the new option `-t' for conntrackd. This option shortens the value of the timeout for the cached entries that lives in the kernel. This option is particularly useful to remove the zombie established entries that remain in kernel if the user tests the platform by forcing the takeover from one to another node several times. We currently use the value of CommitTimeout which is sane for it. Adding a new option does not seem to add more flexibility IMO. Once we get the patches to notify user changes via ctnetlink and the netlink flag NLM_F_ECHO works, we may directly invoke a massive purge of the entries, however, such solution would still need evaluation. Signed-off-by: Pablo Neira Ayuso --- include/cache.h | 1 + include/conntrackd.h | 1 + src/cache_iterators.c | 34 ++++++++++++++++++++++++++++++++++ src/main.c | 4 ++++ src/sync-mode.c | 8 ++++++++ 5 files changed, 48 insertions(+) (limited to 'src') diff --git a/include/cache.h b/include/cache.h index ba8d3aa..45c3b7e 100644 --- a/include/cache.h +++ b/include/cache.h @@ -97,5 +97,6 @@ void cache_dump(struct cache *c, int fd, int type); void cache_commit(struct cache *c); void cache_flush(struct cache *c); void cache_bulk(struct cache *c); +void cache_reset_timers(struct cache *c); #endif diff --git a/include/conntrackd.h b/include/conntrackd.h index d2c8931..2f0d7e5 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -24,6 +24,7 @@ #define REQUEST_DUMP 23 /* request dump */ #define DUMP_INT_XML 24 /* dump internal cache in XML */ #define DUMP_EXT_XML 25 /* dump external cache in XML */ +#define RESET_TIMERS 26 /* reset kernel timers */ #define DEFAULT_CONFIGFILE "/etc/conntrackd/conntrackd.conf" #define DEFAULT_LOCKFILE "/var/lock/conntrackd.lock" diff --git a/src/cache_iterators.c b/src/cache_iterators.c index 407db0b..2abb6cd 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -174,6 +174,40 @@ void cache_commit(struct cache *c) "committed", commit_fail); } +static int do_reset_timers(void *data1, void *data2) +{ + int ret; + struct us_conntrack *u = data2; + struct nf_conntrack *ct = u->ct; + + /* this may increase timers but they will end up dying shortly anyway */ + nfct_set_attr_u32(ct, ATTR_TIMEOUT, CONFIG(commit_timeout)); + + ret = nl_exist_conntrack(ct); + switch (ret) { + case -1: + case 0: + /* the kernel table is not in sync with internal cache */ + dlog(LOG_ERR, "reset-timers: %s", strerror(errno)); + dlog_ct(STATE(log), ct, NFCT_O_PLAIN); + break; + case 1: + if (nl_update_conntrack(ct) == -1) { + if (errno == ETIME || errno == ENOENT) + break; + dlog(LOG_ERR, "reset-timers-upd: %s", strerror(errno)); + dlog_ct(STATE(log), ct, NFCT_O_PLAIN); + } + break; + } + return 0; +} + +void cache_reset_timers(struct cache *c) +{ + hashtable_iterate(c->h, NULL, do_reset_timers); +} + static int do_flush(void *data1, void *data2) { struct cache *c = data1; diff --git a/src/main.c b/src/main.c index 084643c..a4c5451 100644 --- a/src/main.c +++ b/src/main.c @@ -148,6 +148,10 @@ int main(int argc, char *argv[]) set_operation_mode(&type, REQUEST, argv); action = SEND_BULK; break; + case 't': + set_operation_mode(&type, REQUEST, argv); + action = RESET_TIMERS; + break; case 'k': set_operation_mode(&type, REQUEST, argv); action = KILL; diff --git a/src/sync-mode.c b/src/sync-mode.c index 56c30af..297a500 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -343,6 +343,14 @@ static int local_handler_sync(int fd, int type, void *data) exit(EXIT_SUCCESS); } break; + case RESET_TIMERS: + ret = fork(); + if (ret == 0) { + dlog(LOG_NOTICE, "resetting timers"); + cache_reset_timers(STATE_SYNC(internal)); + exit(EXIT_SUCCESS); + } + break; case FLUSH_CACHE: dlog(LOG_NOTICE, "flushing caches"); cache_flush(STATE_SYNC(internal)); -- cgit v1.2.3 From 6ae4b7710c4b8764418a1891902318aa7618044e Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 2 Aug 2008 20:07:06 +0200 Subject: cache_iterators: do not report ENOENT in cache_reset_timers Do not report ENOENT to log files, this may confuse users. There's a race condition when shortening the timers and handling the destroy messages. However, this problem is not serious as the point of the shortening is to reduce the lifetime of the conntracks. If the conntrack is dying, there's no point to shorten their lifetime anymore :) Signed-off-by: Pablo Neira Ayuso --- src/cache_iterators.c | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/cache_iterators.c b/src/cache_iterators.c index 2abb6cd..a7c6654 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -186,7 +186,6 @@ static int do_reset_timers(void *data1, void *data2) ret = nl_exist_conntrack(ct); switch (ret) { case -1: - case 0: /* the kernel table is not in sync with internal cache */ dlog(LOG_ERR, "reset-timers: %s", strerror(errno)); dlog_ct(STATE(log), ct, NFCT_O_PLAIN); -- cgit v1.2.3 From a4f4647b4b7f32f2d1caab98544802c8cdd7b4d6 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 7 Aug 2008 14:52:41 +0200 Subject: netlink: add getter and check existence functions This patch adds nl_get_conntrack and it changes the behaviour of nl_exist_conntrack. Now, nl_get_conntrack requests the kernel for a conntrack and updates the cached entry. On the other hand, nl_exist_conntrack only inquiries for the existence of the entry. Signed-off-by: Pablo Neira Ayuso --- include/conntrackd.h | 1 + include/netlink.h | 4 ++++ src/netlink.c | 25 +++++++++++++++++++++++-- src/run.c | 8 ++++++++ 4 files changed, 36 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/include/conntrackd.h b/include/conntrackd.h index 2f0d7e5..60bb2de 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -110,6 +110,7 @@ struct ct_general_state { struct nfct_filter *filter; /* event filter */ struct nfct_handle *dump; /* dump handler */ + struct nfct_handle *request; /* request handler */ struct nfct_handle *overrun; /* overrun handler */ struct alarm_block overrun_alarm; diff --git a/include/netlink.h b/include/netlink.h index a46fe11..a7b7dda 100644 --- a/include/netlink.h +++ b/include/netlink.h @@ -10,6 +10,8 @@ int nl_init_event_handler(void); int nl_init_dump_handler(void); +int nl_init_request_handler(void); + int nl_init_overrun_handler(void); int nl_overrun_request_resync(void); @@ -20,6 +22,8 @@ int nl_dump_conntrack_table(void); int nl_exist_conntrack(struct nf_conntrack *ct); +int nl_get_conntrack(struct nf_conntrack *ct); + int nl_create_conntrack(struct nf_conntrack *ct); int nl_update_conntrack(struct nf_conntrack *ct); diff --git a/src/netlink.c b/src/netlink.c index a8a5503..0d9b7db 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -214,6 +214,16 @@ int nl_init_overrun_handler(void) return 0; } +/* no callback, it does not do anything with the output */ +int nl_init_request_handler(void) +{ + STATE(request) = nfct_open(CONNTRACK, 0); + if (!STATE(request)) + return -1; + + return 0; +} + static int warned = 0; void nl_resize_socket_buffer(struct nfct_handle *h) @@ -257,7 +267,7 @@ int nl_overrun_request_resync(void) return nfct_send(STATE(overrun), NFCT_Q_DUMP, &family); } -int nl_exist_conntrack(struct nf_conntrack *ct) +static int __nl_get_conntrack(struct nfct_handle *h, struct nf_conntrack *ct) { int ret; char __tmp[nfct_maxsize()]; @@ -268,13 +278,24 @@ int nl_exist_conntrack(struct nf_conntrack *ct) /* use the original tuple to check if it is there */ nfct_copy(tmp, ct, NFCT_CP_ORIG); - ret = nfct_query(STATE(dump), NFCT_Q_GET, tmp); + ret = nfct_query(h, NFCT_Q_GET, tmp); if (ret == -1) return errno == ENOENT ? 0 : -1; return 1; } +int nl_exist_conntrack(struct nf_conntrack *ct) +{ + return __nl_get_conntrack(STATE(request), ct); +} + +/* get the conntrack and update the cache */ +int nl_get_conntrack(struct nf_conntrack *ct) +{ + return __nl_get_conntrack(STATE(dump), ct); +} + /* This function modifies the conntrack passed as argument! */ int nl_create_conntrack(struct nf_conntrack *ct) { diff --git a/src/run.c b/src/run.c index cf570d8..b7da18c 100644 --- a/src/run.c +++ b/src/run.c @@ -38,6 +38,7 @@ void killer(int foo) sigprocmask(SIG_BLOCK, &STATE(block), NULL); nfct_close(STATE(event)); + nfct_close(STATE(request)); ct_filter_destroy(STATE(us_filter)); local_server_destroy(&STATE(local)); @@ -144,6 +145,13 @@ init(void) return -1; } + if (nl_init_request_handler() == -1) { + dlog(LOG_ERR, "can't open netlink handler: %s", + strerror(errno)); + dlog(LOG_ERR, "no ctnetlink kernel support?"); + return -1; + } + init_alarm(&STATE(overrun_alarm), NULL, do_overrun_alarm); STATE(fds) = create_fds(); -- cgit v1.2.3 From 6cb33c62c8007593d8a85aa202fa173043877135 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 7 Aug 2008 14:53:12 +0200 Subject: cache iterators: rework cache_reset_timers This patch adds the clause PurgeTimeout that sets the new timer when conntrackd -t is called. This command is particularly useful when the sysadmin triggers hand-overs between several nodes without rebooting as it reduces the timers of the remaining entries in the kernel. Thus, avoiding clashes between new and old entries that may trigger INVALID packets. Signed-off-by: Pablo Neira Ayuso --- doc/sync/alarm/conntrackd.conf | 11 +++++++++++ doc/sync/ftfw/conntrackd.conf | 11 +++++++++++ doc/sync/keepalived.conf | 1 + doc/sync/notrack/conntrackd.conf | 11 +++++++++++ doc/sync/primary-backup.sh | 12 +++++++++++- include/conntrackd.h | 1 + src/cache_iterators.c | 17 +++++++++++++---- src/read_config_lex.l | 1 + src/read_config_yy.y | 12 +++++++++++- src/sync-mode.c | 15 --------------- 10 files changed, 71 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/doc/sync/alarm/conntrackd.conf b/doc/sync/alarm/conntrackd.conf index a65a378..d6f7a2a 100644 --- a/doc/sync/alarm/conntrackd.conf +++ b/doc/sync/alarm/conntrackd.conf @@ -23,6 +23,17 @@ Sync { # takeover process is completed. # CommitTimeout 180 + + # + # If the firewall replica goes from primary to backup, + # the conntrackd -t command is invoked in the script. + # This command resets the timers of the conntracks that + # live in the kernel to this new value. This is useful + # to purge the connection tracking table of zombie entries + # and avoid clashes with old entries if you trigger + # several consecutive hand-overs. + # + PurgeTimeout 15 } # diff --git a/doc/sync/ftfw/conntrackd.conf b/doc/sync/ftfw/conntrackd.conf index 6fec9a1..8f4d952 100644 --- a/doc/sync/ftfw/conntrackd.conf +++ b/doc/sync/ftfw/conntrackd.conf @@ -16,6 +16,17 @@ Sync { # CommitTimeout 180 + # + # If the firewall replica goes from primary to backup, + # the conntrackd -t command is invoked in the script. + # This command resets the timers of the conntracks that + # live in the kernel to this new value. This is useful + # to purge the connection tracking table of zombie entries + # and avoid clashes with old entries if you trigger + # several consecutive hand-overs. + # + PurgeTimeout 15 + # Set Acknowledgement window size ACKWindowSize 20 } diff --git a/doc/sync/keepalived.conf b/doc/sync/keepalived.conf index c9c8ac1..84f1383 100644 --- a/doc/sync/keepalived.conf +++ b/doc/sync/keepalived.conf @@ -9,6 +9,7 @@ vrrp_sync_group G1 { # must be before vrrp_instance declaration } notify_master "/etc/conntrackd/primary-backup.sh primary" notify_backup "/etc/conntrackd/primary-backup.sh backup" + notify_fault "/etc/conntrackd/primary-backup.sh fault" } vrrp_instance VI_1 { diff --git a/doc/sync/notrack/conntrackd.conf b/doc/sync/notrack/conntrackd.conf index d54934a..3ce1fa0 100644 --- a/doc/sync/notrack/conntrackd.conf +++ b/doc/sync/notrack/conntrackd.conf @@ -9,6 +9,17 @@ Sync { # takeover process is completed. # CommitTimeout 180 + + # + # If the firewall replica goes from primary to backup, + # the conntrackd -t command is invoked in the script. + # This command resets the timers of the conntracks that + # live in the kernel to this new value. This is useful + # to purge the connection tracking table of zombie entries + # and avoid clashes with old entries if you trigger + # several consecutive hand-overs. + # + PurgeTimeout 15 } # diff --git a/doc/sync/primary-backup.sh b/doc/sync/primary-backup.sh index 27fb1c3..e5331e3 100755 --- a/doc/sync/primary-backup.sh +++ b/doc/sync/primary-backup.sh @@ -95,9 +95,19 @@ case "$1" in logger "ERROR: failed to invoke conntrackd -n" fi ;; + fault) + # + # shorten kernel conntrack timers to remove the zombie entries. + # + $CONNTRACKD_BIN -C $CONNTRACKD_CONFIG -t + if [ $? -eq 1 ] + then + logger "ERROR: failed to invoke conntrackd -t" + fi + ;; *) logger "ERROR: unknown state transition" - echo "Usage: primary-backup.sh {primary|backup}" + echo "Usage: primary-backup.sh {primary|backup|fault}" exit 1 ;; esac diff --git a/include/conntrackd.h b/include/conntrackd.h index 60bb2de..23f5306 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -79,6 +79,7 @@ struct ct_conf { int refresh; int cache_timeout; /* cache entries timeout */ int commit_timeout; /* committed entries timeout */ + unsigned int purge_timeout; /* purge kernel entries timeout */ int del_timeout; unsigned int netlink_buffer_size; unsigned int netlink_buffer_size_max_grown; diff --git a/src/cache_iterators.c b/src/cache_iterators.c index a7c6654..8898930 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -55,6 +55,10 @@ static int do_dump(void *data1, void *data2) if (CONFIG(flags) & CTD_SYNC_FTFW && alarm_pending(&u->alarm)) return 0; + /* do not show cached timeout, this may confuse users */ + if (nfct_attr_is_set(u->ct, ATTR_TIMEOUT)) + nfct_attr_unset(u->ct, ATTR_TIMEOUT); + memset(buf, 0, sizeof(buf)); size = nfct_snprintf(buf, sizeof(buf), @@ -177,13 +181,11 @@ void cache_commit(struct cache *c) static int do_reset_timers(void *data1, void *data2) { int ret; + u_int32_t current_timeout; struct us_conntrack *u = data2; struct nf_conntrack *ct = u->ct; - /* this may increase timers but they will end up dying shortly anyway */ - nfct_set_attr_u32(ct, ATTR_TIMEOUT, CONFIG(commit_timeout)); - - ret = nl_exist_conntrack(ct); + ret = nl_get_conntrack(ct); switch (ret) { case -1: /* the kernel table is not in sync with internal cache */ @@ -191,6 +193,13 @@ static int do_reset_timers(void *data1, void *data2) dlog_ct(STATE(log), ct, NFCT_O_PLAIN); break; case 1: + current_timeout = nfct_get_attr_u32(ct, ATTR_TIMEOUT); + /* already about to die, do not touch it */ + if (current_timeout < CONFIG(purge_timeout)) + break; + + nfct_set_attr_u32(ct, ATTR_TIMEOUT, CONFIG(purge_timeout)); + if (nl_update_conntrack(ct) == -1) { if (errno == ETIME || errno == ENOENT) break; diff --git a/src/read_config_lex.l b/src/read_config_lex.l index 584a4a3..79d5b89 100644 --- a/src/read_config_lex.l +++ b/src/read_config_lex.l @@ -111,6 +111,7 @@ notrack [N|n][O|o][T|t][R|r][A|a][C|c][K|k] "State" { return T_STATE; } "Accept" { return T_ACCEPT; } "Ignore" { return T_IGNORE; } +"PurgeTimeout" { return T_PURGE; } {is_on} { return T_ON; } {is_off} { return T_OFF; } diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 33a435c..c7bce82 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -52,7 +52,7 @@ static void __kernel_filter_add_state(int value); %token T_GENERAL T_SYNC T_STATS T_RELAX_TRANSITIONS T_BUFFER_SIZE T_DELAY %token T_SYNC_MODE T_LISTEN_TO T_FAMILY T_RESEND_BUFFER_SIZE %token T_ALARM T_FTFW T_CHECKSUM T_WINDOWSIZE T_ON T_OFF -%token T_REPLICATE T_FOR T_IFACE +%token T_REPLICATE T_FOR T_IFACE T_PURGE %token T_ESTABLISHED T_SYN_SENT T_SYN_RECV T_FIN_WAIT %token T_CLOSE_WAIT T_LAST_ACK T_TIME_WAIT T_CLOSE T_LISTEN %token T_SYSLOG T_WRITE_THROUGH T_STAT_BUFFER_SIZE T_DESTROY_TIMEOUT @@ -163,6 +163,11 @@ timeout: T_TIMEOUT T_NUMBER conf.commit_timeout = $2; }; +purge: T_PURGE T_NUMBER +{ + conf.purge_timeout = $2; +}; + checksum: T_CHECKSUM T_ON { conf.mcast.checksum = 0; @@ -427,6 +432,7 @@ sync_list: sync_line: refreshtime | expiretime | timeout + | purge | checksum | multicast_line | relax_transitions @@ -987,6 +993,10 @@ init_config(char *filename) if (CONFIG(commit_timeout) == 0) CONFIG(commit_timeout) = 180; + /* default to 15 seconds: purge kernel entries */ + if (CONFIG(purge_timeout) == 0) + CONFIG(purge_timeout) = 15; + /* default to 60 seconds of refresh time */ if (CONFIG(refresh) == 0) CONFIG(refresh) = 60; diff --git a/src/sync-mode.c b/src/sync-mode.c index 297a500..db199bc 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -378,9 +378,6 @@ static int local_handler_sync(int fd, int type, void *data) static void dump_sync(struct nf_conntrack *ct) { - if (!CONFIG(cache_write_through)) - nfct_attr_unset(ct, ATTR_TIMEOUT); - /* This is required by kernels < 2.6.20 */ nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES); nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS); @@ -438,9 +435,6 @@ static int overrun_sync(enum nf_conntrack_msg_type type, if (ignore_conntrack(ct)) return NFCT_CB_CONTINUE; - if (!CONFIG(cache_write_through)) - nfct_attr_unset(ct, ATTR_TIMEOUT); - /* This is required by kernels < 2.6.20 */ nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES); nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS); @@ -462,9 +456,6 @@ static void event_new_sync(struct nf_conntrack *ct) { struct us_conntrack *u; - if (!CONFIG(cache_write_through)) - nfct_attr_unset(ct, ATTR_TIMEOUT); - /* required by linux kernel <= 2.6.20 */ nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES); nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS); @@ -490,9 +481,6 @@ static void event_update_sync(struct nf_conntrack *ct) { struct us_conntrack *u; - if (!CONFIG(cache_write_through)) - nfct_attr_unset(ct, ATTR_TIMEOUT); - if ((u = cache_update_force(STATE_SYNC(internal), ct)) == NULL) { debug_ct(ct, "can't update"); return; @@ -505,9 +493,6 @@ static int event_destroy_sync(struct nf_conntrack *ct) { struct us_conntrack *u; - if (!CONFIG(cache_write_through)) - nfct_attr_unset(ct, ATTR_TIMEOUT); - u = cache_find(STATE_SYNC(internal), ct); if (u == NULL) { debug_ct(ct, "can't destroy"); -- cgit v1.2.3 From 8a78dda3e6676286f09f5c78cca60a8178186930 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 7 Aug 2008 14:53:29 +0200 Subject: cache iterators: commit master entries before related ones Commit master entries before related ones to avoid ENOENT errors. Signed-off-by: Pablo Neira Ayuso --- include/netlink.h | 14 ++++++++++++++ src/cache_iterators.c | 29 ++++++++++++++++++++++++----- src/netlink.c | 12 ++++++++++++ 3 files changed, 50 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/include/netlink.h b/include/netlink.h index a7b7dda..6d28ac6 100644 --- a/include/netlink.h +++ b/include/netlink.h @@ -1,6 +1,8 @@ #ifndef _NETLINK_H_ #define _NETLINK_H_ +#include + struct nf_conntrack; struct nfct_handle; @@ -30,4 +32,16 @@ int nl_update_conntrack(struct nf_conntrack *ct); int nl_destroy_conntrack(struct nf_conntrack *ct); +static inline int ct_is_related(const struct nf_conntrack *ct) +{ + return (nfct_attr_is_set(ct, ATTR_MASTER_L3PROTO) && + nfct_attr_is_set(ct, ATTR_MASTER_L4PROTO) && + ((nfct_attr_is_set(ct, ATTR_MASTER_IPV4_SRC) && + nfct_attr_is_set(ct, ATTR_MASTER_IPV4_DST)) || + (nfct_attr_is_set(ct, ATTR_MASTER_IPV6_SRC) && + nfct_attr_is_set(ct, ATTR_MASTER_IPV6_DST))) && + nfct_attr_is_set(ct, ATTR_MASTER_PORT_SRC) && + nfct_attr_is_set(ct, ATTR_MASTER_PORT_DST)); +} + #endif diff --git a/src/cache_iterators.c b/src/cache_iterators.c index 8898930..8811fc4 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -95,12 +95,9 @@ void cache_dump(struct cache *c, int fd, int type) hashtable_iterate(c->h, (void *) &tmp, do_dump); } -/* no need to clone, called from child process */ -static int do_commit(void *data1, void *data2) +static void __do_commit_step(struct cache *c, struct us_conntrack *u) { int ret, retry = 1; - struct cache *c = data1; - struct us_conntrack *u = data2; struct nf_conntrack *ct = u->ct; /* @@ -149,18 +146,40 @@ try_again_update: c->commit_ok++; break; } +} + +static int do_commit_related(void *data1, void *data2) +{ + struct us_conntrack *u = data2; + + if (ct_is_related(u->ct)) + __do_commit_step(data1, u); /* keep iterating even if we have found errors */ return 0; } +static int do_commit_master(void *data1, void *data2) +{ + struct us_conntrack *u = data2; + + if (ct_is_related(u->ct)) + return 0; + + __do_commit_step(data1, u); + return 0; +} + +/* no need to clone, called from child process */ void cache_commit(struct cache *c) { unsigned int commit_ok = c->commit_ok; unsigned int commit_exist = c->commit_exist; unsigned int commit_fail = c->commit_fail; - hashtable_iterate(c->h, c, do_commit); + /* commit master conntrack first, then related ones */ + hashtable_iterate(c->h, c, do_commit_master); + hashtable_iterate(c->h, c, do_commit_related); /* calculate new entries committed */ commit_ok = c->commit_ok - commit_ok; diff --git a/src/netlink.c b/src/netlink.c index 0d9b7db..e9b1cfd 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -337,6 +337,18 @@ int nl_update_conntrack(struct nf_conntrack *ct) nfct_set_attr_u32(ct, ATTR_STATUS, status); } + /* we hit error if we try to update the master conntrack */ + if (ct_is_related(ct)) { + nfct_attr_unset(ct, ATTR_MASTER_L3PROTO); + nfct_attr_unset(ct, ATTR_MASTER_L4PROTO); + nfct_attr_unset(ct, ATTR_MASTER_IPV4_SRC); + nfct_attr_unset(ct, ATTR_MASTER_IPV4_DST); + nfct_attr_unset(ct, ATTR_MASTER_IPV6_SRC); + nfct_attr_unset(ct, ATTR_MASTER_IPV6_DST); + nfct_attr_unset(ct, ATTR_MASTER_PORT_SRC); + nfct_attr_unset(ct, ATTR_MASTER_PORT_DST); + } + return nl_create_conntrack(ct); } -- cgit v1.2.3 From d8df7a62cf50cc1af868b22e4d301a78e7f5c450 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 7 Aug 2008 15:22:00 +0200 Subject: netlink: avoid errors related to the expected bit handling We hit error if we try to change the expected bit for already existing conntracks. On the other hand, if the conntrack does not exist, do not change the expected bit, otherwise we also hit error. Signed-off-by: Pablo Neira Ayuso --- src/netlink.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/netlink.c b/src/netlink.c index e9b1cfd..8b02ac5 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -301,7 +301,7 @@ int nl_create_conntrack(struct nf_conntrack *ct) { uint8_t flags; - /* XXX: related connections */ + /* we hit error if we try to change the expected bit */ if (nfct_attr_is_set(ct, ATTR_STATUS)) { uint32_t status = nfct_get_attr_u32(ct, ATTR_STATUS); status &= ~IPS_EXPECTED; @@ -325,6 +325,8 @@ int nl_create_conntrack(struct nf_conntrack *ct) /* This function modifies the conntrack passed as argument! */ int nl_update_conntrack(struct nf_conntrack *ct) { + uint8_t flags; + /* unset NAT info, otherwise we hit error */ nfct_attr_unset(ct, ATTR_SNAT_IPV4); nfct_attr_unset(ct, ATTR_DNAT_IPV4); @@ -349,7 +351,18 @@ int nl_update_conntrack(struct nf_conntrack *ct) nfct_attr_unset(ct, ATTR_MASTER_PORT_DST); } - return nl_create_conntrack(ct); + nfct_setobjopt(ct, NFCT_SOPT_SETUP_REPLY); + + /* + * TCP flags to overpass window tracking for recovered connections + */ + flags = IP_CT_TCP_FLAG_BE_LIBERAL | IP_CT_TCP_FLAG_SACK_PERM; + nfct_set_attr_u8(ct, ATTR_TCP_FLAGS_ORIG, flags); + nfct_set_attr_u8(ct, ATTR_TCP_MASK_ORIG, flags); + nfct_set_attr_u8(ct, ATTR_TCP_FLAGS_REPL, flags); + nfct_set_attr_u8(ct, ATTR_TCP_MASK_REPL, flags); + + return nfct_query(STATE(dump), NFCT_Q_CREATE_UPDATE, ct); } int nl_destroy_conntrack(struct nf_conntrack *ct) -- cgit v1.2.3 From 064f0d6da31e9dd5a18da77a9dcf9938746a0c48 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 12 Aug 2008 12:59:32 +0200 Subject: cli: remove duplicated optarg checking Remove duplicated optarg checkings for options that require mandatory paramaters. This checking is already done by getopt_long(). Signed-off-by: Pablo Neira Ayuso --- src/conntrack.c | 36 ------------------------------------ 1 file changed, 36 deletions(-) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index cc19b5d..36a317a 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -964,10 +964,6 @@ int main(int argc, char *argv[]) case 'd': case 'r': case 'q': - if (!optarg) - exit_error(PARAMETER_PROBLEM, - "-%c requires an IP", c); - options |= opt2type[c]; l3protonum = parse_addr(optarg, &ad); @@ -987,10 +983,6 @@ int main(int argc, char *argv[]) case '}': case '[': case ']': - if (!optarg) - exit_error(PARAMETER_PROBLEM, - "-%c requires an IP", c); - options |= opt2type[c]; l3protonum = parse_addr(optarg, &ad); set_family(&family, l3protonum); @@ -1006,10 +998,6 @@ int main(int argc, char *argv[]) nfct_set_attr_u8(mask, ATTR_ORIG_L3PROTO, l3protonum); break; case 'p': - if (!optarg || !*optarg) - exit_error(PARAMETER_PROBLEM, - "-%c requires a valid protocol", c); - options |= CT_OPT_PROTO; h = findproto(optarg); if (!h) @@ -1022,44 +1010,24 @@ int main(int argc, char *argv[]) exit_error(OTHER_PROBLEM, "out of memory"); break; case 't': - if (!optarg) - exit_error(PARAMETER_PROBLEM, - "-%c requires value", c); - options |= CT_OPT_TIMEOUT; nfct_set_attr_u32(obj, ATTR_TIMEOUT, atol(optarg)); nfexp_set_attr_u32(exp, ATTR_EXP_TIMEOUT, atol(optarg)); break; case 'u': - if (!optarg) - exit_error(PARAMETER_PROBLEM, - "-%c requires type", c); - options |= CT_OPT_STATUS; parse_parameter(optarg, &status, PARSE_STATUS); nfct_set_attr_u32(obj, ATTR_STATUS, status); break; case 'e': - if (!optarg) - exit_error(PARAMETER_PROBLEM, - "-%c requires type", c); - options |= CT_OPT_EVENT_MASK; parse_parameter(optarg, &event_mask, PARSE_EVENT); break; case 'o': - if (!optarg) - exit_error(PARAMETER_PROBLEM, - "-%c requires type", c); - options |= CT_OPT_OUTPUT; parse_parameter(optarg, &output_mask, PARSE_OUTPUT); break; case 'z': - if (optarg) - exit_error(PARAMETER_PROBLEM, - "-%c does not require parameters",c); - options |= CT_OPT_ZERO; break; case 'n': @@ -1085,10 +1053,6 @@ int main(int argc, char *argv[]) case 'm': case 'c': options |= opt2type[c]; - if (!optarg) - exit_error(PARAMETER_PROBLEM, - "-%c requires value", c); - nfct_set_attr_u32(obj, opt2attr[c], strtoul(optarg, NULL, 0)); -- cgit v1.2.3 From e50e3a5b0f426571d6feb16800b991779aab6d8e Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 12 Aug 2008 13:46:27 +0200 Subject: cli: remove unrequired \n in error message Remove extra \n in error message. Signed-off-by: Pablo Neira Ayuso --- src/conntrack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index 36a317a..ab3da8a 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -383,7 +383,7 @@ static void add_command(unsigned int *cmd, const int newcmd) { if (*cmd) - exit_error(PARAMETER_PROBLEM, "Invalid commands combination\n"); + exit_error(PARAMETER_PROBLEM, "Invalid commands combination"); *cmd |= newcmd; } -- cgit v1.2.3 From b18a146363f170afa420af04f80d2a91c38f11a3 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 12 Aug 2008 18:08:07 +0200 Subject: cli: check for missing arguments in getopt_long From: Pablo Neira Ayuso If getopt_long returns '?', show an error telling that some arguments are missing. Signed-off-by: Pablo Neira Ayuso --- src/conntrack.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index ab3da8a..c126557 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -934,6 +934,9 @@ int main(int argc, char *argv[]) register_icmp(); register_icmpv6(); + /* disable explicit missing arguments error output from getopt_long */ + opterr = 0; + while ((c = getopt_long(argc, argv, "L::I::U::D::G::E::F::hVs:d:r:q:" "p:t:u:e:a:z[:]:{:}:m:i:f:o:n::" "g::c:b:", @@ -1076,18 +1079,21 @@ int main(int argc, char *argv[]) socketbuffersize = atol(optarg); options |= CT_OPT_BUFFERSIZE; break; + case '?': + if (optopt) + exit_error(PARAMETER_PROBLEM, + "option `%s' requires an " + "argument", argv[optind-1]); + else + exit_error(PARAMETER_PROBLEM, + "unknown option `%s'", + argv[optind-1]); + break; default: if (h && h->parse_opts &&!h->parse_opts(c - h->option_offset, obj, exptuple, mask, &l4flags)) exit_error(PARAMETER_PROBLEM, "parse error"); - - /* Unknown argument... */ - if (!h) { - usage(argv[0]); - exit_error(PARAMETER_PROBLEM, - "Missing arguments..."); - } break; } } -- cgit v1.2.3 From abc90e7c5d560973912ea736628d31ead1fe3d5e Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 12 Aug 2008 18:49:58 +0200 Subject: cli: insert `conntrack-tools' string in help and error messages Insert string `conntrack-tools' in error messages to explicitly print that this version is inside the conntrack-tools package. Signed-off-by: Pablo Neira Ayuso --- src/conntrack.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index c126557..7c12b39 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -200,7 +200,7 @@ exit_error(enum exittype status, const char *msg, ...) global_option_offset = 0; } va_start(args, msg); - fprintf(stderr,"%s v%s: ", PROGNAME, VERSION); + fprintf(stderr,"%s v%s (conntrack-tools): ", PROGNAME, VERSION); vfprintf(stderr, msg, args); fprintf(stderr, "\n"); va_end(args); @@ -616,7 +616,7 @@ event_sighandler(int s) fflush(stdout); } - fprintf(stderr, "%s v%s: ", PROGNAME, VERSION); + fprintf(stderr, "%s v%s (conntrack-tools): ", PROGNAME, VERSION); fprintf(stderr, "%d flow events has been shown.\n", counter); nfct_close(cth); exit(0); @@ -1254,7 +1254,7 @@ int main(int argc, char *argv[]) exit_error(OTHER_PROBLEM, "Can't open handler"); res = nfct_query(cth, NFCT_Q_FLUSH, &family); nfct_close(cth); - fprintf(stderr, "%s v%s: ", PROGNAME, VERSION); + fprintf(stderr, "%s v%s (conntrack-tools): ",PROGNAME,VERSION); fprintf(stderr,"connection tracking table has been emptied.\n"); break; @@ -1334,7 +1334,7 @@ int main(int argc, char *argv[]) err2str(errno, command)); if (exit_msg[cmd][0]) { - fprintf(stderr, "%s v%s: ", PROGNAME, VERSION); + fprintf(stderr, "%s v%s (conntrack-tools): ",PROGNAME,VERSION); fprintf(stderr, exit_msg[cmd], counter); if (counter == 0 && !(command & (CT_LIST | EXP_LIST))) return EXIT_FAILURE; -- cgit v1.2.3 From 406737e5aa38f90b01aebe2f6295e7b4ef828220 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 16 Sep 2008 21:06:10 +0200 Subject: ftfw: check for malformed ack and nack messages This patch checks that the [from, to] interval of ack and nack messages is OK. In other words, we check that: to >= from Signed-off-by: Pablo Neira Ayuso --- src/sync-ftfw.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src') diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 42005c4..cc8a08c 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -302,6 +302,10 @@ static int digest_msg(const struct nethdr *net) dprint("ACK(%u): from seq=%u to seq=%u\n", h->seq, h->from, h->to); + + if (before(h->to, h->from)) + return MSG_BAD; + rs_list_empty(STATE_SYNC(internal), h->from, h->to); queue_iterate(rs_queue, h, rs_queue_empty); return MSG_CTL; @@ -311,6 +315,10 @@ static int digest_msg(const struct nethdr *net) dprint("NACK(%u): from seq=%u to seq=%u\n", nack->seq, nack->from, nack->to); + + if (before(nack->to, nack->from)) + return MSG_BAD; + rs_list_to_tx(STATE_SYNC(internal), nack->from, nack->to); queue_iterate(rs_queue, nack, rs_queue_to_tx); return MSG_CTL; -- cgit v1.2.3 From 587a85e0603d514656a434d44c82d1fdacd5e326 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 16 Sep 2008 21:11:37 +0200 Subject: filter: fix NAT detection tweak With this patch, we rely on the real source and destination of the packet to perform the filter. The current NAT detection tweak is broken for certain situations. Signed-off-by: Pablo Neira Ayuso --- src/filter.c | 9 +++------ src/netlink.c | 12 ------------ 2 files changed, 3 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/filter.c b/src/filter.c index eaf0a93..33fe30e 100644 --- a/src/filter.c +++ b/src/filter.c @@ -167,10 +167,9 @@ __ct_filter_test_ipv4(struct ct_filter *f, struct nf_conntrack *ct) if (!f->h) return 0; + /* we only use the real source and destination address */ return (hashtable_test(f->h, nfct_get_attr(ct, ATTR_ORIG_IPV4_SRC)) || - hashtable_test(f->h, nfct_get_attr(ct, ATTR_ORIG_IPV4_DST)) || - hashtable_test(f->h, nfct_get_attr(ct, ATTR_REPL_IPV4_SRC)) || - hashtable_test(f->h, nfct_get_attr(ct, ATTR_REPL_IPV4_DST))); + hashtable_test(f->h, nfct_get_attr(ct, ATTR_REPL_IPV4_SRC))); } static int @@ -180,9 +179,7 @@ __ct_filter_test_ipv6(struct ct_filter *f, struct nf_conntrack *ct) return 0; return (hashtable_test(f->h6, nfct_get_attr(ct, ATTR_ORIG_IPV6_SRC)) || - hashtable_test(f->h6, nfct_get_attr(ct, ATTR_ORIG_IPV6_DST)) || - hashtable_test(f->h6, nfct_get_attr(ct, ATTR_REPL_IPV6_SRC)) || - hashtable_test(f->h6, nfct_get_attr(ct, ATTR_REPL_IPV6_DST))); + hashtable_test(f->h6, nfct_get_attr(ct, ATTR_REPL_IPV6_SRC))); } static int __ct_filter_test_state(struct ct_filter *f, struct nf_conntrack *ct) diff --git a/src/netlink.c b/src/netlink.c index 8b02ac5..a4b94dd 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -66,18 +66,6 @@ int ignore_conntrack(struct nf_conntrack *ct) if (!sanity_check(ct)) return 1; - /* Accept DNAT'ed traffic: not really coming to the local machine */ - if (nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) { - debug_ct(ct, "DNAT"); - return 0; - } - - /* Accept SNAT'ed traffic: not really coming to the local machine */ - if (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) { - debug_ct(ct, "SNAT"); - return 0; - } - /* Ignore traffic */ if (!ct_filter_check(STATE(us_filter), ct)) { debug_ct(ct, "ignore traffic"); -- cgit v1.2.3 From bfa809f6c809f30706a9718506e7a575d44052a6 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 17 Sep 2008 12:45:34 +0200 Subject: cleanup: Linux kernel version checking Minor cleanup to save a couple of lines in the Linux kernel version checking. Signed-off-by: Pablo Neira Ayuso --- src/main.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'src') diff --git a/src/main.c b/src/main.c index a4c5451..7360b77 100644 --- a/src/main.c +++ b/src/main.c @@ -90,12 +90,7 @@ int main(int argc, char *argv[]) exit(EXIT_FAILURE); } sscanf(u.release, "%d.%d.%d", &version, &major, &minor); - if (version < 2 && major < 6) { - fprintf(stderr, "Linux kernel version must be >= 2.6.18\n"); - exit(EXIT_FAILURE); - } - - if (major == 6 && minor < 18) { + if (version < 2 && major < 6 && minor < 18) { fprintf(stderr, "Linux kernel version must be >= 2.6.18\n"); exit(EXIT_FAILURE); } -- cgit v1.2.3 From fc5c992b7010a733250633d55c4a6ab4932a7125 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 17 Sep 2008 13:07:54 +0200 Subject: filter: check if kernel-space filtering is available Check if the Linux kernel is >= 2.6.26, otherwise it does not support kernel-space filtering. This is not clean but we have no choice, the BSF infrastructure does not return ENOTSUPP for unsupported operations. Signed-off-by: Pablo Neira Ayuso --- include/conntrackd.h | 1 + src/main.c | 4 ++++ src/netlink.c | 17 +++++++---------- 3 files changed, 12 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/include/conntrackd.h b/include/conntrackd.h index 23f5306..c0bb4bb 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -90,6 +90,7 @@ struct ct_conf { unsigned int resend_queue_size; /* FTFW protocol */ unsigned int window_size; int cache_write_through; + int kernel_support_netlink_bsf; struct { char logfile[FILENAME_MAXLEN]; int syslog_facility; diff --git a/src/main.c b/src/main.c index 7360b77..a53b0a8 100644 --- a/src/main.c +++ b/src/main.c @@ -95,6 +95,10 @@ int main(int argc, char *argv[]) exit(EXIT_FAILURE); } + /* BSF filter attaching does not report unsupported operations */ + if (version >= 2 && major >= 6 && minor >= 26) + CONFIG(kernel_support_netlink_bsf) = 1; + for (i=1; i= 2.6.26. Operation returns: %s", - strerror(errno)); - /* don't fail here, old kernels don't support this */ - } + if (CONFIG(kernel_support_netlink_bsf)) { + if (nfct_filter_attach(nfct_fd(STATE(event)), + STATE(filter)) == -1) { + dlog(LOG_ERR, "cannot set event filtering: %s", + strerror(errno)); + } + } nfct_filter_destroy(STATE(filter)); } -- cgit v1.2.3 From c131d10ce84b5c7b51893cbf933b32967b74314f Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 17 Sep 2008 13:12:51 +0200 Subject: cleanup: remove some debug messages from sync-ftfw.c Remove useless debug messages, now we have a pluging for tcpdump to debug the FT-FW protocol. Signed-off-by: Pablo Neira Ayuso --- src/sync-ftfw.c | 39 ++++++++------------------------------- 1 file changed, 8 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index cc8a08c..5019d4e 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -35,12 +35,6 @@ #define dp(...) #endif -#if 0 -#define dprint printf -#else -#define dprint(...) -#endif - static LIST_HEAD(rs_list); static LIST_HEAD(tx_list); static unsigned int rs_list_len; @@ -119,8 +113,6 @@ static void do_alive_alarm(struct alarm_block *a, void *data) { if (ack_from_set && mcast_track_is_seq_set()) { /* exp_seq contains the last update received */ - dprint("send ALIVE ACK (from=%u, to=%u)\n", - ack_from, STATE_SYNC(last_seq_recv)); tx_queue_add_ctlmsg(NET_F_ACK, ack_from, STATE_SYNC(last_seq_recv)); @@ -140,7 +132,7 @@ static int rs_dump(void *data1, const void *data2) { struct nethdr_ack *net = data1; - dprint("in RS queue -> seq:%u flags:%u\n", net->seq, net->flags); + printf("in RS queue -> seq:%u flags:%u\n", net->seq, net->flags); return 0; } @@ -155,7 +147,7 @@ static void my_dump(int foo) struct us_conntrack *u; u = cache_get_conntrack(STATE_SYNC(internal), cn); - dprint("in RS list -> seq:%u\n", cn->seq); + printf("in RS list -> seq:%u\n", cn->seq); } queue_iterate(rs_queue, NULL, rs_dump); @@ -300,9 +292,6 @@ static int digest_msg(const struct nethdr *net) else if (IS_ACK(net)) { const struct nethdr_ack *h = (const struct nethdr_ack *) net; - dprint("ACK(%u): from seq=%u to seq=%u\n", - h->seq, h->from, h->to); - if (before(h->to, h->from)) return MSG_BAD; @@ -313,9 +302,6 @@ static int digest_msg(const struct nethdr *net) } else if (IS_NACK(net)) { const struct nethdr_ack *nack = (const struct nethdr_ack *) net; - dprint("NACK(%u): from seq=%u to seq=%u\n", - nack->seq, nack->from, nack->to); - if (before(nack->to, nack->from)) return MSG_BAD; @@ -367,14 +353,10 @@ static int ftfw_recv(const struct nethdr *net) if (ack_from_set) { tx_queue_add_ctlmsg(NET_F_ACK, ack_from, exp_seq-1); - dprint("OFS send half ACK: from seq=%u to seq=%u\n", - ack_from, exp_seq-1); ack_from_set = 0; } tx_queue_add_ctlmsg(NET_F_NACK, exp_seq, net->seq-1); - dprint("OFS send NACK: from seq=%u to seq=%u\n", - exp_seq, net->seq-1); /* count this message as part of the new window */ window = CONFIG(window_size) - 1; @@ -405,9 +387,6 @@ bypass: if (--window <= 0) { /* received a window, send an acknowledgement */ - dprint("OFS send ACK: from seq=%u to seq=%u\n", - ack_from, net->seq); - tx_queue_add_ctlmsg(NET_F_ACK, ack_from, net->seq); window = CONFIG(window_size); ack_from_set = 0; @@ -468,11 +447,9 @@ static int tx_queue_xmit(void *data1, const void *data2) mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); HDR_NETWORK2HOST(net); - if (IS_DATA(net) || IS_ACK(net) || IS_NACK(net)) { - dprint("tx_queue -> to_rs_queue sq: %u fl:%u len:%u\n", - net->seq, net->flags, net->len); + if (IS_DATA(net) || IS_ACK(net) || IS_NACK(net)) queue_add(rs_queue, net, net->len); - } + queue_del(tx_queue, net); return 0; @@ -518,10 +495,10 @@ static void ftfw_run(void) /* reset alive alarm */ add_alarm(&alive_alarm, 1, 0); - dprint("tx_list_len:%u tx_queue_len:%u " - "rs_list_len: %u rs_queue_len:%u\n", - tx_list_len, queue_len(tx_queue), - rs_list_len, queue_len(rs_queue)); + dp("tx_list_len:%u tx_queue_len:%u " + "rs_list_len: %u rs_queue_len:%u\n", + tx_list_len, queue_len(tx_queue), + rs_list_len, queue_len(rs_queue)); } struct sync_mode sync_ftfw = { -- cgit v1.2.3 From 666ceb1e2cd71f844f5794a556c46b114764bca6 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 21 Sep 2008 14:00:50 +0200 Subject: fix: remove node from tx_list when the state-entry is destroy This patches fixes a race that triggers a read-after-free access to the tx_list. The state-entry is destroyed but it is still in the list. The fix removes the state-entry from the tx_list in the destroy path. Signed-off-by: Pablo Neira Ayuso --- src/sync-ftfw.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 5019d4e..4c1b536 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -70,12 +70,15 @@ static void cache_ftfw_del(struct us_conntrack *u, void *data) struct cache_ftfw *cn = data; /* this node is already out of the list */ - if (list_empty(&cn->rs_list)) - return; - - /* no need for list_del_init since the entry is destroyed */ - list_del(&cn->rs_list); - rs_list_len--; + if (!list_empty(&cn->rs_list)) { + /* no need for list_del_init since the entry is destroyed */ + list_del(&cn->rs_list); + rs_list_len--; + } + if (!list_empty(&cn->tx_list)) { + list_del(&cn->tx_list); + tx_list_len--; + } } static struct cache_extra cache_ftfw_extra = { -- cgit v1.2.3 From 3863f882469117afd6a2ad7ce25711b619f43b27 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 25 Sep 2008 17:05:50 +0200 Subject: ftfw: fix race that triggers a double insertion into tx_list This patch fixes a race condition that can trigger a double insertion to the tx_list. This happens if we receive two resync request very close or resync just after a nack or vice-versa. Signed-off-by: Pablo Neira Ayuso --- src/sync-ftfw.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 4c1b536..8dd5554 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -196,6 +196,10 @@ static int do_cache_to_tx(void *data1, void *data2) struct us_conntrack *u = data2; struct cache_ftfw *cn = cache_get_extra(STATE_SYNC(internal), u); + /* repeated request for resync? */ + if (!list_empty(&cn->tx_list)) + return 0; + /* add to tx list */ list_add_tail(&cn->tx_list, &tx_list); tx_list_len++; @@ -264,8 +268,11 @@ static void rs_list_to_tx(struct cache *c, unsigned int from, unsigned int to) dp("resending nack'ed (oldseq=%u)\n", cn->seq); list_del_init(&cn->rs_list); rs_list_len--; - list_add_tail(&cn->tx_list, &tx_list); - tx_list_len++; + /* we received a request for resync before this nack? */ + if (list_empty(&cn->tx_list)) { + list_add_tail(&cn->tx_list, &tx_list); + tx_list_len++; + } write_evfd(STATE_SYNC(evfd)); } } -- cgit v1.2.3 From 30216bf35c8cfe078ede4c4ad7f43544b469b7d3 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 25 Sep 2008 17:06:12 +0200 Subject: ftfw: fix race condition in the helloing routine This patch fixes a race condition that can prevent one node from sending the initial hello message required to reset the sequence tracking. node A node B | | start | | hello msg |----------------------->| stop | | start | | |<-----------------------| hello-back msg In the picture above, the node A never sends the hello messages. Thus, the node B drops the next messages as they are in the before boundary. This patch adds a new state to the the helloing state-machine to fix this problem. Signed-off-by: Pablo Neira Ayuso --- include/network.h | 6 ------ src/sync-ftfw.c | 44 ++++++++++++++++++++++++++++++-------------- 2 files changed, 30 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/include/network.h b/include/network.h index 777be11..d2e4edd 100644 --- a/include/network.h +++ b/include/network.h @@ -65,12 +65,6 @@ enum { SEQ_BEFORE, }; -enum { - SAY_HELLO, - HELLO_BACK, - HELLO_DONE, -}; - int mcast_track_seq(uint32_t seq, uint32_t *exp_seq); void mcast_track_update_seq(uint32_t seq); int mcast_track_is_seq_set(void); diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 8dd5554..11c0638 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -46,7 +46,14 @@ static uint32_t window; static uint32_t ack_from; static int ack_from_set = 0; static struct alarm_block alive_alarm; -static int hello_state = SAY_HELLO; + +enum { + HELLO_INIT, + HELLO_SAY, + HELLO_DONE, +}; +static int hello_state = HELLO_INIT; +static int say_hello_back; /* XXX: alive message expiration configurable */ #define ALIVE_INT 1 @@ -96,13 +103,17 @@ static void tx_queue_add_ctlmsg(uint32_t flags, uint32_t from, uint32_t to) }; switch(hello_state) { - case SAY_HELLO: + case HELLO_INIT: + hello_state = HELLO_SAY; + /* fall through */ + case HELLO_SAY: ack.flags |= NET_F_HELLO; break; - case HELLO_BACK: + } + + if (say_hello_back) { ack.flags |= NET_F_HELLO_BACK; - hello_state = HELLO_DONE; - break; + say_hello_back = 0; } queue_add(tx_queue, &ack, NETHDR_ACK_SIZ); @@ -335,12 +346,13 @@ static int digest_hello(const struct nethdr *net) int ret = 0; if (IS_HELLO(net)) { - dlog(LOG_NOTICE, "The other node says HELLO"); - hello_state = HELLO_BACK; + say_hello_back = 1; ret = 1; - } else if (IS_HELLO_BACK(net)) { - dlog(LOG_NOTICE, "The other node says HELLO BACK"); - hello_state = HELLO_DONE; + } + if (IS_HELLO_BACK(net)) { + /* this is a hello back for a requested hello */ + if (hello_state == HELLO_SAY) + hello_state = HELLO_DONE; } return ret; @@ -428,15 +440,19 @@ static void ftfw_send(struct nethdr *net, struct us_conntrack *u) } switch(hello_state) { - case SAY_HELLO: + case HELLO_INIT: + hello_state = HELLO_SAY; + /* fall through */ + case HELLO_SAY: net->flags = ntohs(net->flags) | NET_F_HELLO; net->flags = htons(net->flags); break; - case HELLO_BACK: + } + + if (say_hello_back) { net->flags = ntohs(net->flags) | NET_F_HELLO_BACK; net->flags = htons(net->flags); - hello_state = HELLO_DONE; - break; + say_hello_back = 0; } cn->seq = ntohl(net->seq); -- cgit v1.2.3 From 99a80b3fe6af95ca711c2d37737408c3703a6184 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 25 Sep 2008 17:10:42 +0200 Subject: ftfw: reset window and flush the resend queue during helloing This fixes two bugs when a hello message is received: * We can create malformed nack messages during the helloing. We have to reset the acknowlegdment window, otherwise we may create malformed nack messages. * We have to empty the resend list/queue when a hello message is received, otherwise the entries get stuck to the resend queue once the sequence number wraps around. Signed-off-by: Pablo Neira Ayuso --- src/sync-ftfw.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 11c0638..b7eabdf 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -260,6 +260,12 @@ static int rs_queue_empty(void *data1, const void *data2) struct nethdr *net = data1; const struct nethdr_ack *h = data2; + if (h == NULL) { + dp("inconditional remove from queue (seq=%u)\n", net->seq); + queue_del(rs_queue, data1); + return 0; + } + if (between(net->seq, h->from, h->to)) { dp("remove from queue (seq=%u)\n", net->seq); queue_del(rs_queue, data1); @@ -362,8 +368,22 @@ static int ftfw_recv(const struct nethdr *net) { int ret = MSG_DATA; - if (digest_hello(net)) + if (digest_hello(net)) { + /* we have received a hello while we had data to acknowledge. + * reset the window, the other doesn't know anthing about it. */ + if (ack_from_set && before(net->seq, ack_from)) { + window = CONFIG(window_size) - 1; + ack_from = net->seq; + } + + /* XXX: flush the resend queues since the other does not + * know anything about that data, we are unreliable until + * the helloing finishes */ + queue_iterate(rs_queue, NULL, rs_queue_empty); + rs_list_empty(STATE_SYNC(internal), 0, ~0U); + goto bypass; + } switch (mcast_track_seq(net->seq, &exp_seq)) { case SEQ_AFTER: -- cgit v1.2.3 From 7a399ccded7086436dff2b55e6461b520cc952f6 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 28 Sep 2008 18:28:39 +0200 Subject: conntrack: cleanup for the update path This patch cleans up the update path for the conntrack utility. Signed-off-by: Pablo Neira Ayuso --- src/conntrack.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index 7c12b39..568307a 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -787,21 +787,22 @@ static int update_cb(enum nf_conntrack_msg_type type, char __tmp[nfct_maxsize()]; struct nf_conntrack *tmp = (struct nf_conntrack *) (void *)__tmp; - memcpy(tmp, obj, sizeof(__tmp)); + memset(tmp, 0, sizeof(__tmp)); - if (ignore_nat(tmp, ct)) + if (ignore_nat(obj, ct)) return NFCT_CB_CONTINUE; if (nfct_attr_is_set(obj, ATTR_ID) && nfct_attr_is_set(ct, ATTR_ID) && nfct_get_attr_u32(obj, ATTR_ID) != nfct_get_attr_u32(ct, ATTR_ID)) return NFCT_CB_CONTINUE; - if (options & CT_OPT_TUPLE_ORIG && !nfct_cmp(tmp, ct, NFCT_CMP_ORIG)) + if (options & CT_OPT_TUPLE_ORIG && !nfct_cmp(obj, ct, NFCT_CMP_ORIG)) return NFCT_CB_CONTINUE; - if (options & CT_OPT_TUPLE_REPL && !nfct_cmp(tmp, ct, NFCT_CMP_REPL)) + if (options & CT_OPT_TUPLE_REPL && !nfct_cmp(obj, ct, NFCT_CMP_REPL)) return NFCT_CB_CONTINUE; nfct_copy(tmp, ct, NFCT_CP_ORIG); + nfct_copy(tmp, obj, NFCT_CP_META); res = nfct_query(ith, NFCT_Q_UPDATE, tmp); if (res < 0) -- cgit v1.2.3 From 1c2772d3e5f77022649410d9f5787221cc38573f Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 28 Sep 2008 22:46:15 +0200 Subject: conntrack: cleanup XML header handling This patch removes the use of snprintf and directly print the XML header to the standard output. This simplifies the handling. Signed-off-by: Pablo Neira Ayuso --- include/conntrack.h | 6 ------ src/conntrack.c | 28 ++++++---------------------- 2 files changed, 6 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/include/conntrack.h b/include/conntrack.h index e8059c8..69c2317 100644 --- a/include/conntrack.h +++ b/include/conntrack.h @@ -192,10 +192,4 @@ extern void register_udp(void); extern void register_icmp(void); extern void register_icmpv6(void); -#define BUFFER_SIZE(ret, len, offset) \ - if (ret > len) \ - ret = len; \ - offset += ret; \ - len -= ret; - #endif diff --git a/src/conntrack.c b/src/conntrack.c index 568307a..f7b9363 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -627,7 +627,6 @@ static int event_cb(enum nf_conntrack_msg_type type, void *data) { char buf[1024]; - int ret, offset = 0, len = sizeof(buf); struct nf_conntrack *obj = data; unsigned int op_type = NFCT_O_DEFAULT; unsigned int op_flags = 0; @@ -642,15 +641,8 @@ static int event_cb(enum nf_conntrack_msg_type type, op_type = NFCT_O_XML; if (dump_xml_header_done) { dump_xml_header_done = 0; - ret = snprintf(buf, len, "\n" - "\n"); - if (ret == -1) { - fprintf(stderr, "evil! snprintf fails\n"); - return NFCT_CB_CONTINUE; - } - - BUFFER_SIZE(ret, len, offset); + printf("\n" + "\n"); } } if (output_mask & _O_EXT) @@ -666,7 +658,7 @@ static int event_cb(enum nf_conntrack_msg_type type, if (output_mask & _O_ID) op_flags |= NFCT_OF_ID; - nfct_snprintf(buf+offset, len, ct, type, op_type, op_flags); + nfct_snprintf(buf, sizeof(buf), ct, type, op_type, op_flags); printf("%s\n", buf); fflush(stdout); @@ -681,7 +673,6 @@ static int dump_cb(enum nf_conntrack_msg_type type, void *data) { char buf[1024]; - int ret, offset = 0, len = sizeof(buf); struct nf_conntrack *obj = data; unsigned int op_type = NFCT_O_DEFAULT; unsigned int op_flags = 0; @@ -696,15 +687,8 @@ static int dump_cb(enum nf_conntrack_msg_type type, op_type = NFCT_O_XML; if (dump_xml_header_done) { dump_xml_header_done = 0; - ret = snprintf(buf, len, "\n" - "\n"); - if (ret == -1) { - fprintf(stderr, "evil! snprintf fails\n"); - return NFCT_CB_CONTINUE; - } - - BUFFER_SIZE(ret, len, offset); + printf("\n" + "\n"); } } if (output_mask & _O_EXT) @@ -712,7 +696,7 @@ static int dump_cb(enum nf_conntrack_msg_type type, if (output_mask & _O_ID) op_flags |= NFCT_OF_ID; - nfct_snprintf(buf+offset, len, ct, NFCT_T_UNKNOWN, op_type, op_flags); + nfct_snprintf(buf, sizeof(buf), ct, NFCT_T_UNKNOWN, op_type, op_flags); printf("%s\n", buf); counter++; -- cgit v1.2.3 From 6e5b823c8c33245d9e40a01c8ce514bc7bc489a1 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 2 Oct 2008 17:17:10 +0200 Subject: conntrack: fix mark-based filtering for event display The mark-based filtering for events does not work if the mark is not present in the event message. This happens because nfct_cmp() skips the comparison of the compared objects since it they do not have the same attributes set. This patch make use of the new NFCT_CMP_MASK flag that returns false if the first object passed as parameter is set and the second is not. Signed-off-by: Pablo Neira Ayuso --- src/conntrack.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index f7b9363..73c102b 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -634,7 +634,8 @@ static int event_cb(enum nf_conntrack_msg_type type, if (ignore_nat(obj, ct)) return NFCT_CB_CONTINUE; - if (options & CT_COMPARISON && !nfct_cmp(obj, ct, NFCT_CMP_ALL)) + if (options & CT_COMPARISON && + !nfct_cmp(obj, ct, NFCT_CMP_ALL | NFCT_CMP_MASK)) return NFCT_CB_CONTINUE; if (output_mask & _O_XML) { @@ -680,7 +681,8 @@ static int dump_cb(enum nf_conntrack_msg_type type, if (ignore_nat(obj, ct)) return NFCT_CB_CONTINUE; - if (options & CT_COMPARISON && !nfct_cmp(obj, ct, NFCT_CMP_ALL)) + if (options & CT_COMPARISON && + !nfct_cmp(obj, ct, NFCT_CMP_ALL | NFCT_CMP_MASK)) return NFCT_CB_CONTINUE; if (output_mask & _O_XML) { @@ -717,7 +719,8 @@ static int delete_cb(enum nf_conntrack_msg_type type, if (ignore_nat(obj, ct)) return NFCT_CB_CONTINUE; - if (options & CT_COMPARISON && !nfct_cmp(obj, ct, NFCT_CMP_ALL)) + if (options & CT_COMPARISON && + !nfct_cmp(obj, ct, NFCT_CMP_ALL | NFCT_CMP_MASK)) return NFCT_CB_CONTINUE; res = nfct_query(ith, NFCT_Q_DESTROY, ct); -- cgit v1.2.3 From e44561766b025600e4af55a35166db46206dd42c Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 4 Oct 2008 11:32:37 +0200 Subject: conntrack: fix filtering for unsupported protocol This patch fixes filtering for unsupported protocol. Thus, you can use -L -p 47 or -L -p gre to filter `gre' traffic. Based on an initial patch from Bryan Duff . Signed-off-by: Pablo Neira Ayuso --- extensions/Makefile.am | 4 ++- extensions/libct_proto_unknown.c | 34 +++++++++++++++++++++ include/conntrack.h | 1 + src/Makefile.am | 2 +- src/conntrack.c | 66 ++++++++++++++++++++++++++++++---------- 5 files changed, 89 insertions(+), 18 deletions(-) create mode 100644 extensions/libct_proto_unknown.c (limited to 'src') diff --git a/extensions/Makefile.am b/extensions/Makefile.am index 0eede22..7b48f05 100644 --- a/extensions/Makefile.am +++ b/extensions/Makefile.am @@ -1,9 +1,11 @@ include $(top_srcdir)/Make_global.am noinst_LTLIBRARIES = libct_proto_tcp.la libct_proto_udp.la \ - libct_proto_icmp.la libct_proto_icmpv6.la + libct_proto_icmp.la libct_proto_icmpv6.la \ + libct_proto_unknown.la libct_proto_tcp_la_SOURCES = libct_proto_tcp.c libct_proto_udp_la_SOURCES = libct_proto_udp.c libct_proto_icmp_la_SOURCES = libct_proto_icmp.c libct_proto_icmpv6_la_SOURCES = libct_proto_icmpv6.c +libct_proto_unknown_la_SOURCES = libct_proto_unknown.c diff --git a/extensions/libct_proto_unknown.c b/extensions/libct_proto_unknown.c new file mode 100644 index 0000000..2a47704 --- /dev/null +++ b/extensions/libct_proto_unknown.c @@ -0,0 +1,34 @@ +/* + * (C) 2005-2008 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 +#include + +#include "conntrack.h" + +static struct option opts[] = { + {0, 0, 0, 0} +}; + +static void help(void) +{ + fprintf(stdout, " no options (unsupported)\n"); +} + +struct ctproto_handler ct_proto_unknown = { + .name = "unknown", + .help = help, + .opts = opts, + .version = VERSION, +}; + +void register_unknown(void) +{ + /* we don't actually insert this protocol in the list */ +} diff --git a/include/conntrack.h b/include/conntrack.h index 69c2317..4787809 100644 --- a/include/conntrack.h +++ b/include/conntrack.h @@ -191,5 +191,6 @@ extern void register_tcp(void); extern void register_udp(void); extern void register_icmp(void); extern void register_icmpv6(void); +extern void register_unknown(void); #endif diff --git a/src/Makefile.am b/src/Makefile.am index 805e50d..82f7dfe 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -7,7 +7,7 @@ CLEANFILES = read_config_yy.c read_config_lex.c sbin_PROGRAMS = conntrack conntrackd conntrack_SOURCES = conntrack.c -conntrack_LDADD = ../extensions/libct_proto_tcp.la ../extensions/libct_proto_udp.la ../extensions/libct_proto_icmp.la ../extensions/libct_proto_icmpv6.la +conntrack_LDADD = ../extensions/libct_proto_tcp.la ../extensions/libct_proto_udp.la ../extensions/libct_proto_icmp.la ../extensions/libct_proto_icmpv6.la ../extensions/libct_proto_unknown.la conntrack_LDFLAGS = $(all_libraries) @LIBNETFILTER_CONNTRACK_LIBS@ conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c rbtree.c \ diff --git a/src/conntrack.c b/src/conntrack.c index 73c102b..eccaa7b 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -53,6 +53,7 @@ #endif #include #include +#include #include static const char cmdflags[NUMBER_OF_CMD] @@ -156,26 +157,61 @@ void register_proto(struct ctproto_handler *h) list_add(&h->head, &proto_list); } -static struct ctproto_handler *findproto(char *name) +extern struct ctproto_handler ct_proto_unknown; + +static struct ctproto_handler *findproto(char *name, int *pnum) { struct ctproto_handler *cur; + struct protoent *pent; + int protonum; - if (!name) - return NULL; - + /* is it in the list of supported protocol? */ list_for_each_entry(cur, &proto_list, head) { - if (strcmp(cur->name, name) == 0) + if (strcmp(cur->name, name) == 0) { + *pnum = cur->protonum; return cur; + } + } + /* using the protocol name for an unsupported protocol? */ + if ((pent = getprotobyname(name))) { + *pnum = pent->p_proto; + return &ct_proto_unknown; + } + /* using a protocol number? */ + protonum = atoi(name); + if (protonum > 0 && protonum <= IPPROTO_MAX) { + /* try lookup by number, perhaps this protocol is supported */ + list_for_each_entry(cur, &proto_list, head) { + if (cur->protonum == protonum) { + *pnum = protonum; + return cur; + } + } + *pnum = protonum; + return &ct_proto_unknown; } return NULL; } static void -extension_help(struct ctproto_handler *h) +extension_help(struct ctproto_handler *h, int protonum) { - fprintf(stdout, "\n"); - fprintf(stdout, "Proto `%s' help:\n", h->name); + const char *name; + + if (h == &ct_proto_unknown) { + struct protoent *pent; + + pent = getprotobynumber(protonum); + if (!pent) + name = h->name; + else + name = pent->p_name; + } else { + name = h->name; + } + + fprintf(stdout, "Proto `%s' help:\n", name); h->help(); } @@ -908,7 +944,7 @@ int main(int argc, char *argv[]) struct nf_conntrack *mask = (struct nf_conntrack *)(void*) __mask; char __exp[nfexp_maxsize()]; struct nf_expect *exp = (struct nf_expect *)(void*) __exp; - int l3protonum; + int l3protonum, protonum = 0; union ct_address ad; unsigned int command = 0; @@ -921,6 +957,7 @@ int main(int argc, char *argv[]) register_udp(); register_icmp(); register_icmpv6(); + register_unknown(); /* disable explicit missing arguments error output from getopt_long */ opterr = 0; @@ -990,7 +1027,7 @@ int main(int argc, char *argv[]) break; case 'p': options |= CT_OPT_PROTO; - h = findproto(optarg); + h = findproto(optarg, &protonum); if (!h) exit_error(PARAMETER_PROBLEM, "`%s' unsupported protocol", @@ -999,6 +1036,8 @@ int main(int argc, char *argv[]) opts = merge_options(opts, h->opts, &h->option_offset); if (opts == NULL) exit_error(OTHER_PROBLEM, "out of memory"); + + nfct_set_attr_u8(obj, ATTR_L4PROTO, protonum); break; case 't': options |= CT_OPT_TIMEOUT; @@ -1090,11 +1129,6 @@ int main(int argc, char *argv[]) if (family == AF_UNSPEC) family = AF_INET; - /* set the protocol number if we have seen -p with no parameters */ - if (h && !nfct_attr_is_set(obj, ATTR_ORIG_L4PROTO) && - !nfct_attr_is_set(obj, ATTR_REPL_L4PROTO)) - nfct_set_attr_u8(obj, ATTR_L4PROTO, h->protonum); - cmd = bit2cmd(command); generic_cmd_check(cmd, options); generic_opt_check(options, @@ -1304,7 +1338,7 @@ int main(int argc, char *argv[]) case CT_HELP: usage(argv[0]); if (options & CT_OPT_PROTO) - extension_help(h); + extension_help(h, protonum); break; default: usage(argv[0]); -- cgit v1.2.3 From 09a3f0cba34c2d29e9b6ffa3151fc970c5b93599 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 9 Oct 2008 15:01:44 +0200 Subject: conntrack: fix dump counter displayed with -L expect This patch fixes the dump counter displayed with -L expect. Signed-off-by: Pablo Neira Ayuso --- src/conntrack.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index eccaa7b..0051639 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -863,6 +863,7 @@ static int dump_exp_cb(enum nf_conntrack_msg_type type, nfexp_snprintf(buf, 1024, exp, NFCT_T_UNKNOWN, NFCT_O_DEFAULT, 0); printf("%s\n", buf); + counter++; return NFCT_CB_CONTINUE; } -- cgit v1.2.3 From b8ed29727d24862523d57066ede86635d8dbacbf Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 16 Oct 2008 15:40:49 +0200 Subject: conntrack: cleanup for NAT filtering This patch cleanups the NAT filtering. The former code had three branches, one if src and dst NAT are set, else one if src NAT is set, else one if dst NAT is set. Now, we check if src NAT is set or if dst NAT is set. Signed-off-by: Pablo Neira Ayuso --- src/conntrack.c | 33 +++++++++------------------------ 1 file changed, 9 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index 0051639..152f94e 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -597,28 +597,12 @@ usage(char *prog) static unsigned int output_mask; -static int ignore_nat(const struct nf_conntrack *obj, - const struct nf_conntrack *ct) +static int +filter_nat(const struct nf_conntrack *obj, const struct nf_conntrack *ct) { uint32_t ip; - if (options & CT_OPT_SRC_NAT && options & CT_OPT_DST_NAT) { - if (!nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT) && - !nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) - return 1; - - if (nfct_attr_is_set(obj, ATTR_SNAT_IPV4)) { - ip = nfct_get_attr_u32(obj, ATTR_SNAT_IPV4); - if (ip != nfct_get_attr_u32(ct, ATTR_REPL_IPV4_DST)) - return 1; - } - - if (nfct_attr_is_set(obj, ATTR_DNAT_IPV4)) { - ip = nfct_get_attr_u32(obj, ATTR_DNAT_IPV4); - if (ip != nfct_get_attr_u32(ct, ATTR_REPL_IPV4_SRC)) - return 1; - } - } else if (options & CT_OPT_SRC_NAT) { + if (options & CT_OPT_SRC_NAT) { if (!nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) return 1; @@ -627,7 +611,8 @@ static int ignore_nat(const struct nf_conntrack *obj, if (ip != nfct_get_attr_u32(ct, ATTR_REPL_IPV4_DST)) return 1; } - } else if (options & CT_OPT_DST_NAT) { + } + if (options & CT_OPT_DST_NAT) { if (!nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) return 1; @@ -667,7 +652,7 @@ static int event_cb(enum nf_conntrack_msg_type type, unsigned int op_type = NFCT_O_DEFAULT; unsigned int op_flags = 0; - if (ignore_nat(obj, ct)) + if (filter_nat(obj, ct)) return NFCT_CB_CONTINUE; if (options & CT_COMPARISON && @@ -714,7 +699,7 @@ static int dump_cb(enum nf_conntrack_msg_type type, unsigned int op_type = NFCT_O_DEFAULT; unsigned int op_flags = 0; - if (ignore_nat(obj, ct)) + if (filter_nat(obj, ct)) return NFCT_CB_CONTINUE; if (options & CT_COMPARISON && @@ -752,7 +737,7 @@ static int delete_cb(enum nf_conntrack_msg_type type, unsigned int op_type = NFCT_O_DEFAULT; unsigned int op_flags = 0; - if (ignore_nat(obj, ct)) + if (filter_nat(obj, ct)) return NFCT_CB_CONTINUE; if (options & CT_COMPARISON && @@ -812,7 +797,7 @@ static int update_cb(enum nf_conntrack_msg_type type, memset(tmp, 0, sizeof(__tmp)); - if (ignore_nat(obj, ct)) + if (filter_nat(obj, ct)) return NFCT_CB_CONTINUE; if (nfct_attr_is_set(obj, ATTR_ID) && nfct_attr_is_set(ct, ATTR_ID) && -- cgit v1.2.3 From 8509a878c0df580b7496c7fd0afd961c4c3c771d Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 20 Oct 2008 14:09:04 +0200 Subject: cache: fix update of scheduled-to-timeout entries This patch fixes a problem that allows the update of entries that are scheduled to be removed. Signed-off-by: Pablo Neira Ayuso --- src/cache.c | 99 ++++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 55 insertions(+), 44 deletions(-) (limited to 'src') diff --git a/src/cache.c b/src/cache.c index 820a385..63a8cff 100644 --- a/src/cache.c +++ b/src/cache.c @@ -231,6 +231,23 @@ struct us_conntrack *cache_add(struct cache *c, struct nf_conntrack *ct) return NULL; } +static void +__cache_update(struct cache *c, struct us_conntrack *u, struct nf_conntrack *ct) +{ + unsigned i; + char *data = u->data; + + nfct_copy(u->ct, ct, NFCT_CP_META); + + for (i = 0; i < c->num_features; i++) { + c->features[i]->update(u, data); + data += c->features[i]->size; + } + + if (c->extra && c->extra->update) + c->extra->update(u, ((char *) u) + c->extra_offset); +} + static struct us_conntrack *__update(struct cache *c, struct nf_conntrack *ct) { size_t size = c->h->datasize; @@ -241,19 +258,7 @@ static struct us_conntrack *__update(struct cache *c, struct nf_conntrack *ct) u = (struct us_conntrack *) hashtable_test(c->h, u); if (u) { - unsigned i; - char *data = u->data; - - nfct_copy(u->ct, ct, NFCT_CP_META); - - for (i = 0; i < c->num_features; i++) { - c->features[i]->update(u, data); - data += c->features[i]->size; - } - - if (c->extra && c->extra->update) - c->extra->update(u, ((char *) u) + c->extra_offset); - + __cache_update(c, u, ct); return u; } return NULL; @@ -273,37 +278,6 @@ struct us_conntrack *cache_update(struct cache *c, struct nf_conntrack *ct) return NULL; } -struct us_conntrack *cache_update_force(struct cache *c, - struct nf_conntrack *ct) -{ - struct us_conntrack *u; - - if ((u = __update(c, ct)) != NULL) { - c->upd_ok++; - return u; - } - if ((u = __add(c, ct)) != NULL) { - c->add_ok++; - return u; - } - c->add_fail++; - return NULL; -} - -int cache_test(struct cache *c, struct nf_conntrack *ct) -{ - size_t size = c->h->datasize; - char buf[size]; - struct us_conntrack *u = (struct us_conntrack *) buf; - void *ret; - - u->ct = ct; - - ret = hashtable_test(c->h, u); - - return ret != NULL; -} - static void __del2(struct cache *c, struct us_conntrack *u) { unsigned i; @@ -337,6 +311,43 @@ static void __cache_del(struct cache *c, struct us_conntrack *u) __del2(c, u); } +struct us_conntrack *cache_update_force(struct cache *c, + struct nf_conntrack *ct) +{ + struct us_conntrack *u; + + u = cache_find(c, ct); + if (u) { + if (!alarm_pending(&u->alarm)) { + c->upd_ok++; + __cache_update(c, u, ct); + return u; + } else { + __cache_del(c, u); + } + } + if ((u = __add(c, ct)) != NULL) { + c->add_ok++; + return u; + } + c->add_fail++; + return NULL; +} + +int cache_test(struct cache *c, struct nf_conntrack *ct) +{ + size_t size = c->h->datasize; + char buf[size]; + struct us_conntrack *u = (struct us_conntrack *) buf; + void *ret; + + u->ct = ct; + + ret = hashtable_test(c->h, u); + + return ret != NULL; +} + int cache_del(struct cache *c, struct nf_conntrack *ct) { size_t size = c->h->datasize; -- cgit v1.2.3 From a7c245bafd98a04414903787448ac17bb0922b70 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 20 Oct 2008 14:13:51 +0200 Subject: cache-iterators: improve committing This patches fixes two problems: - If we failt to update an entry, we remove it and try again. This happens when we still have an entry in a final state like TIME_WAIT while we see a new connection (SYN_SENT) with the same tuple. In this particular case, we fail to update since some status bits are only settable, but not unsettable. - If we hit ETIME in an update, we have to go over the creation patch, otherwise we hit ENOENT in the next run. Signed-off-by: Pablo Neira Ayuso --- src/cache_iterators.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/cache_iterators.c b/src/cache_iterators.c index 8811fc4..fd7aed6 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -106,6 +106,7 @@ static void __do_commit_step(struct cache *c, struct us_conntrack *u) */ nfct_set_attr_u32(ct, ATTR_TIMEOUT, CONFIG(commit_timeout)); +try_again: ret = nl_exist_conntrack(ct); switch (ret) { case -1: @@ -113,13 +114,12 @@ static void __do_commit_step(struct cache *c, struct us_conntrack *u) dlog_ct(STATE(log), ct, NFCT_O_PLAIN); break; case 0: -try_again_create: if (nl_create_conntrack(ct) == -1) { if (errno == ENOMEM) { if (retry) { retry = 0; sched_yield(); - goto try_again_create; + goto try_again; } } dlog(LOG_ERR, "commit-create: %s", strerror(errno)); @@ -130,15 +130,27 @@ try_again_create: break; case 1: c->commit_exist++; -try_again_update: if (nl_update_conntrack(ct) == -1) { if (errno == ENOMEM || errno == ETIME) { if (retry) { retry = 0; sched_yield(); - goto try_again_update; + goto try_again; } } + /* try harder, delete the entry and retry */ + if (retry) { + ret = nl_destroy_conntrack(ct); + if (ret == 0 || + (ret == -1 && errno == ENOENT)) { + retry = 0; + goto try_again; + } + dlog(LOG_ERR, "commit-rm: %s", strerror(errno)); + dlog_ct(STATE(log), ct, NFCT_O_PLAIN); + c->commit_fail++; + break; + } dlog(LOG_ERR, "commit-update: %s", strerror(errno)); dlog_ct(STATE(log), ct, NFCT_O_PLAIN); c->commit_fail++; -- cgit v1.2.3 From 9c2fd73489f516eb56f8fe216913ea70e3b4a76a Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 20 Oct 2008 14:15:46 +0200 Subject: config: fix usage of 'PurgeTimeout' in Sync NOTRACK This patch fixes a problem that is reported by conntrackd while trying to parse the example configuration file. We fix this instead of the example file to make it consistent with other replication approaches. Signed-off-by: Pablo Neira Ayuso --- src/read_config_yy.y | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/read_config_yy.y b/src/read_config_yy.y index c7bce82..c01abe4 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -467,6 +467,7 @@ sync_mode_alarm_list: sync_mode_alarm_line: refreshtime | expiretime | timeout + | purge | relax_transitions | delay_destroy_msgs ; @@ -476,6 +477,7 @@ sync_mode_ftfw_list: sync_mode_ftfw_line: resend_queue_size | timeout + | purge | window_size ; @@ -483,8 +485,8 @@ sync_mode_notrack_list: | sync_mode_notrack_list sync_mode_notrack_line; sync_mode_notrack_line: timeout - ; - + | purge + ; resend_queue_size: T_RESEND_BUFFER_SIZE T_NUMBER { -- cgit v1.2.3 From 5000afe7e1a3ae4a14995e051d3ee716d8a6c784 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 20 Oct 2008 14:17:13 +0200 Subject: notrack: fix double receival of resync requests This patch fixes double insertion in the tx_list if we receive two (or more) consecutive resync request in short time. Signed-off-by: Pablo Neira Ayuso --- src/sync-notrack.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'src') diff --git a/src/sync-notrack.c b/src/sync-notrack.c index 2b1bc13..c7ac9b5 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -36,8 +36,26 @@ struct cache_notrack { struct list_head tx_list; }; +static void cache_notrack_add(struct us_conntrack *u, void *data) +{ + struct cache_notrack *cn = data; + INIT_LIST_HEAD(&cn->tx_list); +} + +static void cache_notrack_del(struct us_conntrack *u, void *data) +{ + struct cache_notrack *cn = data; + + if (!list_empty(&cn->tx_list)) { + list_del(&cn->tx_list); + tx_list_len--; + } +} + static struct cache_extra cache_notrack_extra = { .size = sizeof(struct cache_notrack), + .add = cache_notrack_add, + .destroy = cache_notrack_del }; static void tx_queue_add_ctlmsg(uint32_t flags, uint32_t from, uint32_t to) @@ -73,6 +91,9 @@ static int do_cache_to_tx(void *data1, void *data2) struct us_conntrack *u = data2; struct cache_notrack *cn = cache_get_extra(STATE_SYNC(internal), u); + if (!list_empty(&cn->tx_list)) + return 0; + /* add to tx list */ list_add_tail(&cn->tx_list, &tx_list); tx_list_len++; -- cgit v1.2.3 From 5fa52f81764d078d0a719a8902ad00a0d3acd511 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 21 Oct 2008 18:25:12 +0200 Subject: netlink: report when kernel-space event filtering is in use This patch adds a log message to tell that conntrackd are using kernel-space filtering. Signed-off-by: Pablo Neira Ayuso --- src/netlink.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/netlink.c b/src/netlink.c index ad26201..c0a0805 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -118,6 +118,7 @@ int nl_init_event_handler(void) dlog(LOG_ERR, "cannot set event filtering: %s", strerror(errno)); } + dlog(LOG_NOTICE, "using kernel-space event filtering"); } nfct_filter_destroy(STATE(filter)); } -- cgit v1.2.3 From 705435f574e45348f5613672588b453d6285ef20 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 21 Oct 2008 18:50:51 +0200 Subject: filter: fix segfault if the Filter clause is unused This patch fixes a segfault when conntrackd -k is invoked for an instance of conntrackd with no use of the Filter clause. Signed-off-by: Pablo Neira Ayuso --- src/run.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/run.c b/src/run.c index b7da18c..34d20b0 100644 --- a/src/run.c +++ b/src/run.c @@ -40,7 +40,8 @@ void killer(int foo) nfct_close(STATE(event)); nfct_close(STATE(request)); - ct_filter_destroy(STATE(us_filter)); + if (STATE(us_filter)) + ct_filter_destroy(STATE(us_filter)); local_server_destroy(&STATE(local)); STATE(mode)->kill(); -- cgit v1.2.3 From 6d6ebd1247076c88ceeb8d9528d62cd38a5e909a Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 21 Oct 2008 19:05:02 +0200 Subject: cache: use jhash2 instead of double jhash+jhash_2words Currently, oprofile reports ~17% of sample in the hashing. With this patch, that uses jhash2 instead of a double call to jhash and one to jhash_2words, it goes down to ~11%. Signed-off-by: Pablo Neira Ayuso --- src/cache.c | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/cache.c b/src/cache.c index 63a8cff..1d39fd5 100644 --- a/src/cache.c +++ b/src/cache.c @@ -30,15 +30,14 @@ static uint32_t __hash4(const struct nf_conntrack *ct, struct hashtable *table) { - unsigned int a, b; - - a = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV4_SRC), sizeof(uint32_t), - ((nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO) << 16) | - (nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO)))); - - b = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV4_DST), sizeof(uint32_t), - ((nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC) << 16) | - (nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST)))); + uint32_t a[4] = { + [0] = nfct_get_attr_u32(ct, ATTR_IPV4_SRC), + [1] = nfct_get_attr_u32(ct, ATTR_IPV4_DST), + [2] = nfct_get_attr_u8(ct, ATTR_L3PROTO) << 16 | + nfct_get_attr_u8(ct, ATTR_L4PROTO), + [3] = nfct_get_attr_u16(ct, ATTR_PORT_SRC) << 16 | + nfct_get_attr_u16(ct, ATTR_PORT_DST), + }; /* * Instead of returning hash % table->hashsize (implying a divide) @@ -47,22 +46,21 @@ static uint32_t __hash4(const struct nf_conntrack *ct, struct hashtable *table) * but using a multiply, less expensive than a divide. See: * http://www.mail-archive.com/netdev@vger.kernel.org/msg56623.html */ - return ((uint64_t)jhash_2words(a, b, 0) * table->hashsize) >> 32; + return ((uint64_t)jhash2(a, 4, 0) * table->hashsize) >> 32; } static uint32_t __hash6(const struct nf_conntrack *ct, struct hashtable *table) { - unsigned int a, b; - - a = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV6_SRC), sizeof(uint32_t)*4, - ((nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO) << 16) | - (nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO)))); + uint32_t a[10]; - b = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV6_DST), sizeof(uint32_t)*4, - ((nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC) << 16) | - (nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST)))); + memcpy(&a[0], nfct_get_attr(ct, ATTR_IPV6_SRC), sizeof(uint32_t)*4); + memcpy(&a[4], nfct_get_attr(ct, ATTR_IPV6_SRC), sizeof(uint32_t)*4); + a[8] = nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO) << 16 | + nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO); + a[9] = nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC) << 16 | + nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST); - return ((uint64_t)jhash_2words(a, b, 0) * table->hashsize) >> 32; + return ((uint64_t)jhash2(a, 10, 0) * table->hashsize) >> 32; } static uint32_t hash(const void *data, struct hashtable *table) -- cgit v1.2.3 From 50162d3c19e38a491d95ec26767438ec25bab0dc Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 21 Oct 2008 19:11:42 +0200 Subject: filter: do not filter in user-space if kernel supports BSF This patch avoids a double filtering in user-space and kernel-space if the kernel support BSF. Since we do not use BSF for dumps and resyncs, we add a new parameter to ignore_conntrack to indicate if we have to perform the filtering in user-space or not. Signed-off-by: Pablo Neira Ayuso --- include/netlink.h | 2 +- src/netlink.c | 11 ++++++----- src/stats-mode.c | 2 +- src/sync-mode.c | 2 +- 4 files changed, 9 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/include/netlink.h b/include/netlink.h index 6d28ac6..d13d33d 100644 --- a/include/netlink.h +++ b/include/netlink.h @@ -6,7 +6,7 @@ struct nf_conntrack; struct nfct_handle; -int ignore_conntrack(struct nf_conntrack *ct); +int ignore_conntrack(struct nf_conntrack *ct, int userspace); int nl_init_event_handler(void); diff --git a/src/netlink.c b/src/netlink.c index c0a0805..89a4ebc 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -60,14 +60,14 @@ static int sanity_check(struct nf_conntrack *ct) return 1; } -int ignore_conntrack(struct nf_conntrack *ct) +/* we do user-space filtering for dump and resyncs */ +int ignore_conntrack(struct nf_conntrack *ct, int userspace) { /* missing mandatory attributes in object */ if (!sanity_check(ct)) return 1; - /* Ignore traffic */ - if (!ct_filter_check(STATE(us_filter), ct)) { + if (userspace && !ct_filter_check(STATE(us_filter), ct)) { debug_ct(ct, "ignore traffic"); return 1; } @@ -79,7 +79,8 @@ static int event_handler(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data) { - if (ignore_conntrack(ct)) + /* skip user-space filtering if already do it in the kernel */ + if (ignore_conntrack(ct, !CONFIG(kernel_support_netlink_bsf))) return NFCT_CB_STOP; switch(type) { @@ -155,7 +156,7 @@ static int dump_handler(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data) { - if (ignore_conntrack(ct)) + if (ignore_conntrack(ct, 1)) return NFCT_CB_CONTINUE; switch(type) { diff --git a/src/stats-mode.c b/src/stats-mode.c index 1650d5d..763afe0 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -104,7 +104,7 @@ static int overrun_stats(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data) { - if (ignore_conntrack(ct)) + if (ignore_conntrack(ct, 1)) return NFCT_CB_CONTINUE; /* This is required by kernels < 2.6.20 */ diff --git a/src/sync-mode.c b/src/sync-mode.c index db199bc..4c22745 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -432,7 +432,7 @@ static int overrun_sync(enum nf_conntrack_msg_type type, { struct us_conntrack *u; - if (ignore_conntrack(ct)) + if (ignore_conntrack(ct, 1)) return NFCT_CB_CONTINUE; /* This is required by kernels < 2.6.20 */ -- cgit v1.2.3 From bcb482d23f95c130faa54f7831ea661ad120a89c Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 21 Oct 2008 20:14:10 +0200 Subject: conntrackd: add missing information on -t to the help This patch adds missing information on -t when conntrackd is invoked with -h. Signed-off-by: Pablo Neira Ayuso --- src/main.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/main.c b/src/main.c index a53b0a8..b535c40 100644 --- a/src/main.c +++ b/src/main.c @@ -45,8 +45,9 @@ static const char usage_client_commands[] = " -k, kill conntrack daemon\n" " -s, dump statistics\n" " -R, resync with kernel conntrack table\n" - " -n, request resync with other node (only FT-FW mode)\n" - " -x, dump cache in XML format (requires -i or -e)"; + " -n, request resync with other node (only FT-FW and NOTRACK modes)\n" + " -x, dump cache in XML format (requires -i or -e)" + " -t, reset the kernel timeout (see PurgeTimeout clause)"; static const char usage_options[] = "Options:\n" -- cgit v1.2.3 From 61a1120a6bf28e9206e012f6c327b67d50edc1c8 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 21 Oct 2008 22:48:31 +0200 Subject: ftfw: rise the size of the acknowledgment window in the example This patch increases the size of the acknowledgment window based on some experiments in my testbed with oprofile. The previous default value was too small. This resulted in too many cycles to empty the resend queue. Signed-off-by: Pablo Neira Ayuso --- doc/sync/ftfw/conntrackd.conf | 13 +++++++++++-- src/read_config_yy.y | 4 ++-- 2 files changed, 13 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/doc/sync/ftfw/conntrackd.conf b/doc/sync/ftfw/conntrackd.conf index 3aa8216..06c3d15 100644 --- a/doc/sync/ftfw/conntrackd.conf +++ b/doc/sync/ftfw/conntrackd.conf @@ -27,8 +27,17 @@ Sync { # PurgeTimeout 15 - # Set Acknowledgement window size - ACKWindowSize 20 + # Set the acknowledgement window size. If you decrease this + # value, the number of acknowlegdments increases. More + # acknowledgments means more overhead as conntrackd has to + # handle more control messages. On the other hand, if you + # increase this value, the resend queue gets more populated. + # This results in more overhead in the queue releasing. + # The following value is based on some practical experiments + # measuring the cycles spent by the acknowledgment handling + # with oprofile. + # + ACKWindowSize 300 } # diff --git a/src/read_config_yy.y b/src/read_config_yy.y index c01abe4..0f6ffdc 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -1006,9 +1006,9 @@ init_config(char *filename) if (CONFIG(resend_queue_size) == 0) CONFIG(resend_queue_size) = 262144; - /* default to a window size of 20 packets */ + /* default to a window size of 300 packets */ if (CONFIG(window_size) == 0) - CONFIG(window_size) = 20; + CONFIG(window_size) = 300; /* double of 120 seconds which is common timeout of a final state */ if (conf.flags & CTD_SYNC_FTFW && CONFIG(del_timeout) == 0) -- cgit v1.2.3 From c9fc2e7843e56eec84d92b5baa208afdb5b81d3c Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 26 Oct 2008 20:48:55 +0100 Subject: ftfw: add option `-v' to output debugging information (if any) This patch introduces the option `-v' to show useful debugging information, if any. As for now, only sync-ftfw.c make use of it to display the content and the length of the resent list/queue. This is useful to check for message leaks. Other working modes or synchronization approaches may use it to display debugging information in the future. This patch removes _SIGNAL_DEBUG in sync-ftfw.c that was used for for the same purpose. However, it could only be enabled at compilation time and it uses signalling instead of the standard UNIX socket interface that conntrackd provides. Signed-off-by: Pablo Neira Ayuso --- include/conntrackd.h | 1 + src/main.c | 7 +++++- src/sync-ftfw.c | 69 ++++++++++++++++++++++++++-------------------------- 3 files changed, 42 insertions(+), 35 deletions(-) (limited to 'src') diff --git a/include/conntrackd.h b/include/conntrackd.h index c0bb4bb..448d594 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -25,6 +25,7 @@ #define DUMP_INT_XML 24 /* dump internal cache in XML */ #define DUMP_EXT_XML 25 /* dump external cache in XML */ #define RESET_TIMERS 26 /* reset kernel timers */ +#define DEBUG_INFO 27 /* show debug info (if any) */ #define DEFAULT_CONFIGFILE "/etc/conntrackd/conntrackd.conf" #define DEFAULT_LOCKFILE "/var/lock/conntrackd.lock" diff --git a/src/main.c b/src/main.c index b535c40..d6aa938 100644 --- a/src/main.c +++ b/src/main.c @@ -47,7 +47,8 @@ static const char usage_client_commands[] = " -R, resync with kernel conntrack table\n" " -n, request resync with other node (only FT-FW and NOTRACK modes)\n" " -x, dump cache in XML format (requires -i or -e)" - " -t, reset the kernel timeout (see PurgeTimeout clause)"; + " -t, reset the kernel timeout (see PurgeTimeout clause)" + " -v, show internal debugging information (if any)"; static const char usage_options[] = "Options:\n" @@ -180,6 +181,10 @@ int main(int argc, char *argv[]) } break; + case 'v': + set_operation_mode(&type, REQUEST, argv); + action = DEBUG_INFO; + break; default: show_usage(argv[0]); fprintf(stderr, "Unknown option: %s\n", argv[i]); diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index b7eabdf..f900919 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -139,36 +139,6 @@ static void do_alive_alarm(struct alarm_block *a, void *data) mcast_buffered_pending_netmsg(STATE_SYNC(mcast_client)); } -#undef _SIGNAL_DEBUG -#ifdef _SIGNAL_DEBUG - -static int rs_dump(void *data1, const void *data2) -{ - struct nethdr_ack *net = data1; - - printf("in RS queue -> seq:%u flags:%u\n", net->seq, net->flags); - - return 0; -} - -#include - -static void my_dump(int foo) -{ - struct cache_ftfw *cn, *tmp; - - list_for_each_entry_safe(cn, tmp, &rs_list, rs_list) { - struct us_conntrack *u; - - u = cache_get_conntrack(STATE_SYNC(internal), cn); - printf("in RS list -> seq:%u\n", cn->seq); - } - - queue_iterate(rs_queue, NULL, rs_dump); -} - -#endif - static int ftfw_init(void) { tx_queue = queue_create(CONFIG(resend_queue_size)); @@ -189,10 +159,6 @@ static int ftfw_init(void) /* set ack window size */ window = CONFIG(window_size); -#ifdef _SIGNAL_DEBUG - signal(SIGUSR1, my_dump); -#endif - return 0; } @@ -219,6 +185,38 @@ static int do_cache_to_tx(void *data1, void *data2) return 0; } +static int debug_rs_queue_dump_step(void *data1, const void *data2) +{ + struct nethdr_ack *net = data1; + const int *fd = data2; + char buf[512]; + int size; + + size = sprintf(buf, "seq:%u flags:%u\n", net->seq, net->flags); + send(*fd, buf, size, 0); + return 0; +} + +static void debug_rs_dump(int fd) +{ + struct cache_ftfw *cn, *tmp; + char buf[512]; + int size; + + size = sprintf(buf, "resent list (len=%u):\n", rs_list_len); + send(fd, buf, size, 0); + list_for_each_entry_safe(cn, tmp, &rs_list, rs_list) { + struct us_conntrack *u; + + u = cache_get_conntrack(STATE_SYNC(internal), cn); + size = sprintf(buf, "seq:%u\n", cn->seq); + send(fd, buf, size, 0); + } + size = sprintf(buf, "\nresent queue (len=%u):\n", queue_len(rs_queue)); + send(fd, buf, size, 0); + queue_iterate(rs_queue, &fd, debug_rs_queue_dump_step); +} + static int ftfw_local(int fd, int type, void *data) { int ret = 1; @@ -232,6 +230,9 @@ static int ftfw_local(int fd, int type, void *data) dlog(LOG_NOTICE, "sending bulk update"); cache_iterate(STATE_SYNC(internal), NULL, do_cache_to_tx); break; + case DEBUG_INFO: + debug_rs_dump(fd); + break; default: ret = 0; break; -- cgit v1.2.3 From e78d828aff1ba35dfdb2e4ccede22cb887977086 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 26 Oct 2008 21:13:39 +0100 Subject: ftfw: remove bottleneck in ack/nack handling Since the resend list/queue contain elements in order, we can break looping once we find the first element that is after the ack/nack window. This patch fixes a bottleneck in the ack/nack handling reported by oprofile. Signed-off-by: Pablo Neira Ayuso --- src/sync-ftfw.c | 64 ++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index f900919..ed97ceb 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -246,13 +246,16 @@ static int rs_queue_to_tx(void *data1, const void *data2) struct nethdr_ack *net = data1; const struct nethdr_ack *nack = data2; - if (between(net->seq, nack->from, nack->to)) { - dp("rs_queue_to_tx sq: %u fl:%u len:%u\n", - net->seq, net->flags, net->len); - queue_add(tx_queue, net, net->len); - write_evfd(STATE_SYNC(evfd)); - queue_del(rs_queue, net); - } + if (before(net->seq, nack->from)) + return 0; /* continue */ + else if (after(net->seq, nack->to)) + return 1; /* break */ + + dp("rs_queue_to_tx sq: %u fl:%u len:%u\n", + net->seq, net->flags, net->len); + queue_add(tx_queue, net, net->len); + write_evfd(STATE_SYNC(evfd)); + queue_del(rs_queue, net); return 0; } @@ -267,10 +270,13 @@ static int rs_queue_empty(void *data1, const void *data2) return 0; } - if (between(net->seq, h->from, h->to)) { - dp("remove from queue (seq=%u)\n", net->seq); - queue_del(rs_queue, data1); - } + if (before(net->seq, h->from)) + return 0; /* continue */ + else if (after(net->seq, h->to)) + return 1; /* break */ + + dp("remove from queue (seq=%u)\n", net->seq); + queue_del(rs_queue, data1); return 0; } @@ -282,17 +288,20 @@ static void rs_list_to_tx(struct cache *c, unsigned int from, unsigned int to) struct us_conntrack *u; u = cache_get_conntrack(STATE_SYNC(internal), cn); - if (between(cn->seq, from, to)) { - dp("resending nack'ed (oldseq=%u)\n", cn->seq); - list_del_init(&cn->rs_list); - rs_list_len--; - /* we received a request for resync before this nack? */ - if (list_empty(&cn->tx_list)) { - list_add_tail(&cn->tx_list, &tx_list); - tx_list_len++; - } - write_evfd(STATE_SYNC(evfd)); + if (before(cn->seq, from)) + continue; + else if (after(cn->seq, to)) + break; + + dp("resending nack'ed (oldseq=%u)\n", cn->seq); + list_del_init(&cn->rs_list); + rs_list_len--; + /* we received a request for resync before this nack? */ + if (list_empty(&cn->tx_list)) { + list_add_tail(&cn->tx_list, &tx_list); + tx_list_len++; } + write_evfd(STATE_SYNC(evfd)); } } @@ -304,11 +313,14 @@ static void rs_list_empty(struct cache *c, unsigned int from, unsigned int to) struct us_conntrack *u; u = cache_get_conntrack(STATE_SYNC(internal), cn); - if (between(cn->seq, from, to)) { - dp("queue: deleting from queue (seq=%u)\n", cn->seq); - list_del_init(&cn->rs_list); - rs_list_len--; - } + if (before(cn->seq, from)) + continue; + else if (after(cn->seq, to)) + break; + + dp("queue: deleting from queue (seq=%u)\n", cn->seq); + list_del_init(&cn->rs_list); + rs_list_len--; } } -- cgit v1.2.3 From 43694a92f5521537109f14ec5fb9c8f4b2a821f6 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 2 Nov 2008 18:40:11 +0100 Subject: network: remove message omission test-code This patch removes a part of the code that can be used to simulate message loss in the replication. This was useful to test the FT-FW code. However, this code is not useful anymore as long as we have netem: tc qdisc add dev eth0 root netem loss 0.1% Signed-off-by: Pablo Neira Ayuso --- src/network.c | 13 ------------- 1 file changed, 13 deletions(-) (limited to 'src') diff --git a/src/network.c b/src/network.c index fb6ea90..7d1d9fa 100644 --- a/src/network.c +++ b/src/network.c @@ -31,19 +31,6 @@ static size_t __do_send(struct mcast_sock *m, void *data, size_t len) { struct nethdr *net = data; -#undef _TEST_DROP -#ifdef _TEST_DROP - -#define DROP_RATE .25 - - /* simulate message omission with a certain probability */ - if ((random() & 0x7FFFFFFF) < 0x80000000 * DROP_RATE) { - printf("drop sq: %u fl:%u len:%u\n", - ntohl(net->seq), ntohs(net->flags), - ntohs(net->len)); - return 0; - } -#endif debug("send sq: %u fl:%u len:%u\n", ntohl(net->seq), ntohs(net->flags), ntohs(net->len)); -- cgit v1.2.3 From 64ce47955778805afceb6ced58b63839763541ad Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 2 Nov 2008 21:29:04 +0100 Subject: network: add protocol version field (breaks backward compatibility) This patch adds the version field (8-bits long) to the nethdr structure. This fields can be used to indicate the protocol version in case that we detect an incompatibility between two conntrackd daemons working with different protocol versions. Unfortunately, this patch breaks backward compatibility, ie. conntrackd <= 0.9.8 protocol is not compatible with the upcoming conntrackd >= 0.9.9. Better do this now than later. Signed-off-by: Pablo Neira Ayuso --- include/network.h | 10 ++++++---- src/network.c | 4 ++-- src/sync-ftfw.c | 11 ++++------- src/sync-mode.c | 8 +++++++- 4 files changed, 19 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/include/network.h b/include/network.h index d2e4edd..d2431f9 100644 --- a/include/network.h +++ b/include/network.h @@ -4,10 +4,13 @@ #include #include +#define CONNTRACKD_PROTOCOL_VERSION 0 + struct nf_conntrack; struct nethdr { - uint16_t flags; + uint8_t version; + uint8_t flags; uint16_t len; uint32_t seq; }; @@ -17,7 +20,8 @@ struct nethdr { (struct netpld *)(((char *)x) + sizeof(struct nethdr)) struct nethdr_ack { - uint16_t flags; + uint8_t version; + uint8_t flags; uint16_t len; uint32_t seq; uint32_t from; @@ -87,7 +91,6 @@ ssize_t mcast_buffered_pending_netmsg(struct mcast_sock *m); #define HDR_NETWORK2HOST(x) \ ({ \ - x->flags = ntohs(x->flags); \ x->len = ntohs(x->len); \ x->seq = ntohl(x->seq); \ if (IS_CTL(x)) { \ @@ -104,7 +107,6 @@ ssize_t mcast_buffered_pending_netmsg(struct mcast_sock *m); __ack->from = htonl(__ack->from); \ __ack->to = htonl(__ack->to); \ } \ - x->flags = htons(x->flags); \ x->len = htons(x->len); \ x->seq = htonl(x->seq); \ }) diff --git a/src/network.c b/src/network.c index 7d1d9fa..04c9d39 100644 --- a/src/network.c +++ b/src/network.c @@ -32,8 +32,7 @@ static size_t __do_send(struct mcast_sock *m, void *data, size_t len) struct nethdr *net = data; debug("send sq: %u fl:%u len:%u\n", - ntohl(net->seq), ntohs(net->flags), - ntohs(net->len)); + ntohl(net->seq), net->flags, ntohs(net->len)); return mcast_send(m, net, len); } @@ -46,6 +45,7 @@ static size_t __do_prepare(struct mcast_sock *m, void *data, size_t len) seq_set = 1; cur_seq = time(NULL); } + net->version = CONNTRACKD_PROTOCOL_VERSION; net->len = len; net->seq = cur_seq++; HDR_HOST2NETWORK(net); diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index ed97ceb..598945f 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -477,14 +477,12 @@ static void ftfw_send(struct nethdr *net, struct us_conntrack *u) hello_state = HELLO_SAY; /* fall through */ case HELLO_SAY: - net->flags = ntohs(net->flags) | NET_F_HELLO; - net->flags = htons(net->flags); + net->flags |= NET_F_HELLO; break; } if (say_hello_back) { - net->flags = ntohs(net->flags) | NET_F_HELLO_BACK; - net->flags = htons(net->flags); + net->flags |= NET_F_HELLO_BACK; say_hello_back = 0; } @@ -501,7 +499,7 @@ static int tx_queue_xmit(void *data1, const void *data2) size_t len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); dp("tx_queue sq: %u fl:%u len:%u\n", - ntohl(net->seq), ntohs(net->flags), ntohs(net->len)); + ntohl(net->seq), net->flags, ntohs(net->len)); mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); HDR_NETWORK2HOST(net); @@ -521,8 +519,7 @@ static int tx_list_xmit(struct list_head *i, struct us_conntrack *u, int type) size_t len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); dp("tx_list sq: %u fl:%u len:%u\n", - ntohl(net->seq), ntohs(net->flags), - ntohs(net->len)); + ntohl(net->seq), net->flags, ntohs(net->len)); list_del_init(i); tx_list_len--; diff --git a/src/sync-mode.c b/src/sync-mode.c index 4c22745..152a8e2 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -41,6 +41,12 @@ static void do_mcast_handler_step(struct nethdr *net, size_t remain) struct nf_conntrack *ct = (struct nf_conntrack *)(void*) __ct; struct us_conntrack *u; + if (net->version != CONNTRACKD_PROTOCOL_VERSION) { + STATE(malformed)++; + dlog(LOG_WARNING, "wrong protocol version `%u'", net->version); + return; + } + switch (STATE_SYNC(sync)->recv(net)) { case MSG_DATA: break; @@ -144,7 +150,7 @@ static void mcast_handler(void) } debug("recv sq: %u fl:%u len:%u (rem:%d)\n", - ntohl(net->seq), ntohs(net->flags), + ntohl(net->seq), net->flags, ntohs(net->len), remain); HDR_NETWORK2HOST(net); -- cgit v1.2.3 From 76ac8ebe5e49385585c8e29fe530ed4baef390bf Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 2 Nov 2008 21:35:42 +0100 Subject: network: rework TLV-based protocol This patch reworks the TLV-based protocol to reduce the overhead in the message building. The idea is to group some attributes that must be present in a consistent configuration. Putting them together help us to save some cycles in the message building. Now, oprofile reports ~15% of samples in the build path instead of ~25%. CPU consumption for 3000 HTTP GET requests per second (1000 concurrent with apache benchmark tool) is ~45% in my testbed, that is ~19% more consumption than with no replication at all. Signed-off-by: Pablo Neira Ayuso --- configure.in | 2 +- include/network.h | 29 ++++++++ src/build.c | 202 ++++++++++++++++++++++++++---------------------------- src/parse.c | 153 +++++++++++++++++++++++++++++------------ 4 files changed, 240 insertions(+), 146 deletions(-) (limited to 'src') diff --git a/configure.in b/configure.in index c66679d..0994e60 100644 --- a/configure.in +++ b/configure.in @@ -18,7 +18,7 @@ esac dnl Dependencies LIBNFNETLINK_REQUIRED=0.0.33 -LIBNETFILTER_CONNTRACK_REQUIRED=0.0.97 +LIBNETFILTER_CONNTRACK_REQUIRED=0.0.98 AC_CHECK_PROG(HAVE_PKG_CONFIG, pkg-config, yes) if test "x$HAVE_PKG_CONFIG" = "x" diff --git a/include/network.h b/include/network.h index d2431f9..2487c81 100644 --- a/include/network.h +++ b/include/network.h @@ -178,6 +178,35 @@ struct netattr { #define NTA_ALIGN(len) (((len) + NTA_ALIGNTO - 1) & ~(NTA_ALIGNTO - 1)) #define NTA_LENGTH(len) (NTA_ALIGN(sizeof(struct netattr)) + (len)) +enum nta_attr { + NTA_IPV4 = 0, /* struct nfct_attr_grp_ipv4 */ + NTA_IPV6, /* struct nfct_attr_grp_ipv6 */ + NTA_L4PROTO, /* uint8_t */ + NTA_PORT, /* struct nfct_attr_grp_port */ + NTA_STATE = 4, /* uint8_t */ + NTA_STATUS, /* uint32_t */ + NTA_TIMEOUT, /* uint32_t */ + NTA_MARK, /* uint32_t */ + NTA_MASTER_IPV4 = 8, /* struct nfct_attr_grp_ipv4 */ + NTA_MASTER_IPV6, /* struct nfct_attr_grp_ipv6 */ + NTA_MASTER_L4PROTO, /* uint8_t */ + NTA_MASTER_PORT, /* struct nfct_attr_grp_port */ + NTA_SNAT_IPV4 = 12, /* uint32_t */ + NTA_DNAT_IPV4, /* uint32_t */ + NTA_SPAT_PORT, /* uint16_t */ + NTA_DPAT_PORT, /* uint16_t */ + NTA_NAT_SEQ_ADJ = 16, /* struct nta_attr_natseqadj */ +}; + +struct nta_attr_natseqadj { + uint32_t orig_seq_correction_pos; + uint32_t orig_seq_offset_before; + uint32_t orig_seq_offset_after; + uint32_t repl_seq_correction_pos; + uint32_t repl_seq_offset_before; + uint32_t repl_seq_offset_after; +}; + void build_netpld(struct nf_conntrack *ct, struct netpld *pld, int query); int parse_netpld(struct nf_conntrack *ct, struct nethdr *net, int *query, size_t remain); diff --git a/src/build.c b/src/build.c index be33c86..5143048 100644 --- a/src/build.c +++ b/src/build.c @@ -1,5 +1,5 @@ /* - * (C) 2006-2007 by Pablo Neira Ayuso + * (C) 2006-2008 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 @@ -20,143 +20,139 @@ #include #include "network.h" -static void addattr(struct netpld *pld, int attr, const void *data, size_t len) +static inline void * +put_header(struct netpld *pld, int attr, size_t len) { - struct netattr *nta; - int tlen = NTA_LENGTH(len); - - nta = PLD_TAIL(pld); + struct netattr *nta = PLD_TAIL(pld); + pld->len += NTA_ALIGN(NTA_LENGTH(len)); nta->nta_attr = htons(attr); nta->nta_len = htons(len); - memcpy(NTA_DATA(nta), data, len); - pld->len += NTA_ALIGN(tlen); + return NTA_DATA(nta); } -static void __build_u8(const struct nf_conntrack *ct, - struct netpld *pld, - int attr) +static inline void +addattr(struct netpld *pld, int attr, const void *data, size_t len) { - uint8_t data = nfct_get_attr_u8(ct, attr); - addattr(pld, attr, &data, sizeof(uint8_t)); + void *ptr = put_header(pld, attr, len); + memcpy(ptr, data, len); } -static void __build_u16(const struct nf_conntrack *ct, - struct netpld *pld, - int attr) +static inline void +__build_u8(const struct nf_conntrack *ct, int a, struct netpld *pld, int b) { - uint16_t data = nfct_get_attr_u16(ct, attr); - data = htons(data); - addattr(pld, attr, &data, sizeof(uint16_t)); + void *ptr = put_header(pld, b, sizeof(uint8_t)); + memcpy(ptr, nfct_get_attr(ct, a), sizeof(uint8_t)); } -static void __build_u32(const struct nf_conntrack *ct, - struct netpld *pld, - int attr) +static inline void +__build_u16(const struct nf_conntrack *ct, int a, struct netpld *pld, int b) { - uint32_t data = nfct_get_attr_u32(ct, attr); - data = htonl(data); - addattr(pld, attr, &data, sizeof(uint32_t)); + uint32_t data = nfct_get_attr_u16(ct, a); + data = htons(data); + addattr(pld, b, &data, sizeof(uint16_t)); } -static void __build_pointer_be(const struct nf_conntrack *ct, - struct netpld *pld, - int attr, - size_t size) +static inline void +__build_u32(const struct nf_conntrack *ct, int a, struct netpld *pld, int b) { - addattr(pld, attr, nfct_get_attr(ct, attr), size); + uint32_t data = nfct_get_attr_u32(ct, a); + data = htonl(data); + addattr(pld, b, &data, sizeof(uint32_t)); } -static void __nat_build_u32(uint32_t data, struct netpld *pld, int attr) +static inline void +__build_group(const struct nf_conntrack *ct, int a, struct netpld *pld, + int b, int size) { - data = htonl(data); - addattr(pld, attr, &data, sizeof(uint32_t)); + void *ptr = put_header(pld, b, size); + nfct_get_attr_grp(ct, a, ptr); } -static void __nat_build_u16(uint16_t data, struct netpld *pld, int attr) +static inline void +__build_natseqadj(const struct nf_conntrack *ct, struct netpld *pld) { - data = htons(data); - addattr(pld, attr, &data, sizeof(uint16_t)); + struct nta_attr_natseqadj data = { + .orig_seq_correction_pos = + htonl(nfct_get_attr_u32(ct, ATTR_ORIG_NAT_SEQ_CORRECTION_POS)), + .orig_seq_offset_before = + htonl(nfct_get_attr_u32(ct, ATTR_ORIG_NAT_SEQ_OFFSET_BEFORE)), + .orig_seq_offset_after = + htonl(nfct_get_attr_u32(ct, ATTR_ORIG_NAT_SEQ_OFFSET_AFTER)), + .repl_seq_correction_pos = + htonl(nfct_get_attr_u32(ct, ATTR_REPL_NAT_SEQ_CORRECTION_POS)), + .repl_seq_offset_before = + htonl(nfct_get_attr_u32(ct, ATTR_REPL_NAT_SEQ_OFFSET_BEFORE)), + .repl_seq_offset_after = + htonl(nfct_get_attr_u32(ct, ATTR_REPL_NAT_SEQ_OFFSET_AFTER)) + }; + addattr(pld, NTA_NAT_SEQ_ADJ, &data, sizeof(struct nta_attr_natseqadj)); } +static enum nf_conntrack_attr nat_type[] = + { ATTR_ORIG_NAT_SEQ_CORRECTION_POS, ATTR_ORIG_NAT_SEQ_OFFSET_BEFORE, + ATTR_ORIG_NAT_SEQ_OFFSET_AFTER, ATTR_REPL_NAT_SEQ_CORRECTION_POS, + ATTR_REPL_NAT_SEQ_OFFSET_BEFORE, ATTR_REPL_NAT_SEQ_OFFSET_AFTER }; + /* XXX: ICMP not supported */ void build_netpld(struct nf_conntrack *ct, struct netpld *pld, int query) { - if (nfct_attr_is_set(ct, ATTR_IPV4_SRC)) - __build_pointer_be(ct, pld, ATTR_IPV4_SRC, sizeof(uint32_t)); - if (nfct_attr_is_set(ct, ATTR_IPV4_DST)) - __build_pointer_be(ct, pld, ATTR_IPV4_DST, sizeof(uint32_t)); - if (nfct_attr_is_set(ct, ATTR_IPV6_SRC)) - __build_pointer_be(ct, pld, ATTR_IPV6_SRC, sizeof(uint32_t)*4); - if (nfct_attr_is_set(ct, ATTR_IPV6_DST)) - __build_pointer_be(ct, pld, ATTR_IPV6_DST, sizeof(uint32_t)*4); - if (nfct_attr_is_set(ct, ATTR_L3PROTO)) - __build_u8(ct, pld, ATTR_L3PROTO); - if (nfct_attr_is_set(ct, ATTR_PORT_SRC)) - __build_u16(ct, pld, ATTR_PORT_SRC); - if (nfct_attr_is_set(ct, ATTR_PORT_DST)) - __build_u16(ct, pld, ATTR_PORT_DST); - if (nfct_attr_is_set(ct, ATTR_L4PROTO)) { - uint8_t proto; - - __build_u8(ct, pld, ATTR_L4PROTO); - proto = nfct_get_attr_u8(ct, ATTR_L4PROTO); - if (proto == IPPROTO_TCP) { - if (nfct_attr_is_set(ct, ATTR_TCP_STATE)) - __build_u8(ct, pld, ATTR_TCP_STATE); - } + if (nfct_attr_grp_is_set(ct, ATTR_GRP_ORIG_IPV4)) { + __build_group(ct, ATTR_GRP_ORIG_IPV4, pld, NTA_IPV4, + sizeof(struct nfct_attr_grp_ipv4)); + } else if (nfct_attr_grp_is_set(ct, ATTR_GRP_ORIG_IPV6)) { + __build_group(ct, ATTR_GRP_ORIG_IPV6, pld, NTA_IPV6, + sizeof(struct nfct_attr_grp_ipv6)); + } + + __build_u8(ct, ATTR_L4PROTO, pld, NTA_L4PROTO); + if (nfct_attr_grp_is_set(ct, ATTR_GRP_ORIG_PORT)) { + __build_group(ct, ATTR_GRP_ORIG_PORT, pld, NTA_PORT, + sizeof(struct nfct_attr_grp_port)); } + + __build_u32(ct, ATTR_STATUS, pld, NTA_STATUS); + + if (nfct_attr_is_set(ct, ATTR_TCP_STATE)) + __build_u8(ct, ATTR_TCP_STATE, pld, NTA_STATE); if (nfct_attr_is_set(ct, ATTR_TIMEOUT)) - __build_u32(ct, pld, ATTR_TIMEOUT); + __build_u32(ct, ATTR_TIMEOUT, pld, NTA_TIMEOUT); if (nfct_attr_is_set(ct, ATTR_MARK)) - __build_u32(ct, pld, ATTR_MARK); - if (nfct_attr_is_set(ct, ATTR_STATUS)) - __build_u32(ct, pld, ATTR_STATUS); + __build_u32(ct, ATTR_MARK, pld, NTA_MARK); /* setup the master conntrack */ - if (nfct_attr_is_set(ct, ATTR_MASTER_IPV4_SRC)) - __build_u32(ct, pld, ATTR_MASTER_IPV4_SRC); - if (nfct_attr_is_set(ct, ATTR_MASTER_IPV4_DST)) - __build_u32(ct, pld, ATTR_MASTER_IPV4_DST); - if (nfct_attr_is_set(ct, ATTR_MASTER_L3PROTO)) - __build_u8(ct, pld, ATTR_MASTER_L3PROTO); - if (nfct_attr_is_set(ct, ATTR_MASTER_PORT_SRC)) - __build_u16(ct, pld, ATTR_MASTER_PORT_SRC); - if (nfct_attr_is_set(ct, ATTR_MASTER_PORT_DST)) - __build_u16(ct, pld, ATTR_MASTER_PORT_DST); - if (nfct_attr_is_set(ct, ATTR_MASTER_L4PROTO)) - __build_u8(ct, pld, ATTR_MASTER_L4PROTO); + if (nfct_attr_grp_is_set(ct, ATTR_GRP_MASTER_IPV4)) { + __build_group(ct, ATTR_GRP_MASTER_IPV4, pld, NTA_MASTER_IPV4, + sizeof(struct nfct_attr_grp_ipv4)); + __build_u8(ct, ATTR_MASTER_L4PROTO, pld, NTA_MASTER_L4PROTO); + if (nfct_attr_grp_is_set(ct, ATTR_GRP_MASTER_PORT)) { + __build_group(ct, ATTR_GRP_MASTER_PORT, + pld, NTA_MASTER_PORT, + sizeof(struct nfct_attr_grp_port)); + } + } else if (nfct_attr_grp_is_set(ct, ATTR_GRP_MASTER_IPV6)) { + __build_group(ct, ATTR_GRP_MASTER_IPV6, pld, NTA_MASTER_IPV6, + sizeof(struct nfct_attr_grp_ipv6)); + __build_u8(ct, ATTR_MASTER_L4PROTO, pld, NTA_MASTER_L4PROTO); + if (nfct_attr_grp_is_set(ct, ATTR_GRP_MASTER_PORT)) { + __build_group(ct, ATTR_GRP_MASTER_PORT, + pld, NTA_MASTER_PORT, + sizeof(struct nfct_attr_grp_port)); + } + } /* NAT */ - if (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) { - uint32_t data = nfct_get_attr_u32(ct, ATTR_REPL_IPV4_DST); - __nat_build_u32(data, pld, ATTR_SNAT_IPV4); - } - if (nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) { - uint32_t data = nfct_get_attr_u32(ct, ATTR_REPL_IPV4_SRC); - __nat_build_u32(data, pld, ATTR_DNAT_IPV4); - } - if (nfct_getobjopt(ct, NFCT_GOPT_IS_SPAT)) { - uint16_t data = nfct_get_attr_u16(ct, ATTR_REPL_PORT_DST); - __nat_build_u16(data, pld, ATTR_SNAT_PORT); - } - if (nfct_getobjopt(ct, NFCT_GOPT_IS_DPAT)) { - uint16_t data = nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC); - __nat_build_u16(data, pld, ATTR_DNAT_PORT); - } + if (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) + __build_u32(ct, ATTR_REPL_IPV4_DST, pld, NTA_SNAT_IPV4); + if (nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) + __build_u32(ct, ATTR_REPL_IPV4_SRC, pld, NTA_DNAT_IPV4); + if (nfct_getobjopt(ct, NFCT_GOPT_IS_SPAT)) + __build_u16(ct, ATTR_REPL_PORT_DST, pld, NTA_SPAT_PORT); + if (nfct_getobjopt(ct, NFCT_GOPT_IS_DPAT)) + __build_u16(ct, ATTR_REPL_PORT_SRC, pld, NTA_DPAT_PORT); /* NAT sequence adjustment */ - if (nfct_attr_is_set(ct, ATTR_ORIG_NAT_SEQ_CORRECTION_POS)) - __build_u32(ct, pld, ATTR_ORIG_NAT_SEQ_CORRECTION_POS); - if (nfct_attr_is_set(ct, ATTR_ORIG_NAT_SEQ_OFFSET_BEFORE)) - __build_u32(ct, pld, ATTR_ORIG_NAT_SEQ_OFFSET_BEFORE); - if (nfct_attr_is_set(ct, ATTR_ORIG_NAT_SEQ_OFFSET_AFTER)) - __build_u32(ct, pld, ATTR_ORIG_NAT_SEQ_OFFSET_AFTER); - if (nfct_attr_is_set(ct, ATTR_REPL_NAT_SEQ_CORRECTION_POS)) - __build_u32(ct, pld, ATTR_REPL_NAT_SEQ_CORRECTION_POS); - if (nfct_attr_is_set(ct, ATTR_REPL_NAT_SEQ_OFFSET_BEFORE)) - __build_u32(ct, pld, ATTR_REPL_NAT_SEQ_OFFSET_BEFORE); - if (nfct_attr_is_set(ct, ATTR_REPL_NAT_SEQ_OFFSET_AFTER)) - __build_u32(ct, pld, ATTR_REPL_NAT_SEQ_OFFSET_AFTER); + if (nfct_attr_is_set_array(ct, nat_type, 6)) + __build_natseqadj(ct, pld); pld->query = query; diff --git a/src/parse.c b/src/parse.c index b14e487..0184c5a 100644 --- a/src/parse.c +++ b/src/parse.c @@ -24,61 +24,127 @@ #define ssizeof(x) (int)sizeof(x) #endif -static void parse_u8(struct nf_conntrack *ct, int attr, void *data) +static void parse_u8(struct nf_conntrack *ct, int attr, void *data); +static void parse_u16(struct nf_conntrack *ct, int attr, void *data); +static void parse_u32(struct nf_conntrack *ct, int attr, void *data); +static void parse_group(struct nf_conntrack *ct, int attr, void *data); +static void parse_nat_seq_adj(struct nf_conntrack *ct, int attr, void *data); + +struct parser { + void (*parse)(struct nf_conntrack *ct, int attr, void *data); + int attr; +}; + +static struct parser h[ATTR_MAX] = { + [NTA_IPV4] = { + .parse = parse_group, + .attr = ATTR_GRP_ORIG_IPV4, + }, + [NTA_IPV6] = { + .parse = parse_group, + .attr = ATTR_GRP_ORIG_IPV6, + }, + [NTA_PORT] = { + .parse = parse_group, + .attr = ATTR_GRP_ORIG_PORT, + }, + [NTA_L4PROTO] = { + .parse = parse_u8, + .attr = ATTR_L4PROTO, + }, + [NTA_STATE] = { + .parse = parse_u8, + .attr = ATTR_TCP_STATE, + }, + [NTA_STATUS] = { + .parse = parse_u32, + .attr = ATTR_STATUS, + }, + [NTA_MARK] = { + .parse = parse_u32, + .attr = ATTR_MARK, + }, + [NTA_TIMEOUT] = { + .parse = parse_u32, + .attr = ATTR_TIMEOUT, + }, + [NTA_MASTER_IPV4] = { + .parse = parse_group, + .attr = ATTR_GRP_MASTER_IPV4, + }, + [NTA_MASTER_IPV6] = { + .parse = parse_group, + .attr = ATTR_GRP_MASTER_IPV6, + }, + [NTA_MASTER_PORT] = { + .parse = parse_group, + .attr = ATTR_GRP_MASTER_PORT, + }, + [NTA_SNAT_IPV4] = { + .parse = parse_u32, + .attr = ATTR_SNAT_IPV4, + }, + [NTA_DNAT_IPV4] = { + .parse = parse_u32, + .attr = ATTR_DNAT_IPV4, + }, + [NTA_SPAT_PORT] = { + .parse = parse_u16, + .attr = ATTR_SNAT_PORT, + }, + [NTA_DPAT_PORT] = { + .parse = parse_u16, + .attr = ATTR_SNAT_PORT, + }, + [NTA_NAT_SEQ_ADJ] = { + .parse = parse_nat_seq_adj, + }, +}; + +static void +parse_u8(struct nf_conntrack *ct, int attr, void *data) { uint8_t *value = (uint8_t *) data; - nfct_set_attr_u8(ct, attr, *value); + nfct_set_attr_u8(ct, h[attr].attr, *value); } -static void parse_u16(struct nf_conntrack *ct, int attr, void *data) +static void +parse_u16(struct nf_conntrack *ct, int attr, void *data) { uint16_t *value = (uint16_t *) data; - nfct_set_attr_u16(ct, attr, ntohs(*value)); + nfct_set_attr_u16(ct, h[attr].attr, ntohs(*value)); } -static void parse_u32(struct nf_conntrack *ct, int attr, void *data) +static void +parse_u32(struct nf_conntrack *ct, int attr, void *data) { uint32_t *value = (uint32_t *) data; - nfct_set_attr_u32(ct, attr, ntohl(*value)); + nfct_set_attr_u32(ct, h[attr].attr, ntohl(*value)); } -static void parse_pointer_be(struct nf_conntrack *ct, int attr, void *data) +static void +parse_group(struct nf_conntrack *ct, int attr, void *data) { - nfct_set_attr(ct, attr, data); + nfct_set_attr_grp(ct, h[attr].attr, data); } -typedef void (*parse)(struct nf_conntrack *ct, int attr, void *data); - -static parse h[ATTR_MAX] = { - [ATTR_IPV4_SRC] = parse_pointer_be, - [ATTR_IPV4_DST] = parse_pointer_be, - [ATTR_IPV6_SRC] = parse_pointer_be, - [ATTR_IPV6_DST] = parse_pointer_be, - [ATTR_L3PROTO] = parse_u8, - [ATTR_PORT_SRC] = parse_u16, - [ATTR_PORT_DST] = parse_u16, - [ATTR_L4PROTO] = parse_u8, - [ATTR_TCP_STATE] = parse_u8, - [ATTR_SNAT_IPV4] = parse_u32, - [ATTR_DNAT_IPV4] = parse_u32, - [ATTR_SNAT_PORT] = parse_u16, - [ATTR_DNAT_PORT] = parse_u16, - [ATTR_TIMEOUT] = parse_u32, - [ATTR_MARK] = parse_u32, - [ATTR_STATUS] = parse_u32, - [ATTR_MASTER_IPV4_SRC] = parse_u32, - [ATTR_MASTER_IPV4_DST] = parse_u32, - [ATTR_MASTER_L3PROTO] = parse_u8, - [ATTR_MASTER_PORT_SRC] = parse_u16, - [ATTR_MASTER_PORT_DST] = parse_u16, - [ATTR_MASTER_L4PROTO] = parse_u8, - [ATTR_ORIG_NAT_SEQ_CORRECTION_POS] = parse_u32, - [ATTR_ORIG_NAT_SEQ_OFFSET_BEFORE] = parse_u32, - [ATTR_ORIG_NAT_SEQ_OFFSET_AFTER] = parse_u32, - [ATTR_REPL_NAT_SEQ_CORRECTION_POS] = parse_u32, - [ATTR_REPL_NAT_SEQ_OFFSET_BEFORE] = parse_u32, - [ATTR_REPL_NAT_SEQ_OFFSET_AFTER] = parse_u32, -}; +static void +parse_nat_seq_adj(struct nf_conntrack *ct, int attr, void *data) +{ + struct nta_attr_natseqadj *this = data; + nfct_set_attr_u32(ct, ATTR_ORIG_NAT_SEQ_CORRECTION_POS, + ntohl(this->orig_seq_correction_pos)); + nfct_set_attr_u32(ct, ATTR_ORIG_NAT_SEQ_OFFSET_BEFORE, + ntohl(this->orig_seq_correction_pos)); + nfct_set_attr_u32(ct, ATTR_ORIG_NAT_SEQ_OFFSET_AFTER, + ntohl(this->orig_seq_correction_pos)); + nfct_set_attr_u32(ct, ATTR_REPL_NAT_SEQ_CORRECTION_POS, + ntohl(this->orig_seq_correction_pos)); + nfct_set_attr_u32(ct, ATTR_REPL_NAT_SEQ_OFFSET_BEFORE, + ntohl(this->orig_seq_correction_pos)); + nfct_set_attr_u32(ct, ATTR_REPL_NAT_SEQ_OFFSET_AFTER, + ntohl(this->orig_seq_correction_pos)); +} int parse_netpld(struct nf_conntrack *ct, @@ -109,8 +175,11 @@ parse_netpld(struct nf_conntrack *ct, ATTR_NETWORK2HOST(attr); if (attr->nta_len > len) return -1; - if (h[attr->nta_attr]) - h[attr->nta_attr](ct, attr->nta_attr, NTA_DATA(attr)); + if (h[attr->nta_attr].parse == NULL) { + attr = NTA_NEXT(attr, len); + continue; + } + h[attr->nta_attr].parse(ct, attr->nta_attr, NTA_DATA(attr)); attr = NTA_NEXT(attr, len); } -- cgit v1.2.3 From f135f1c317a3c9430dc33a6ea7ff90a1ba808e36 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 9 Nov 2008 13:26:31 +0100 Subject: filter: use XOR instead of branches use XOR instead of branches in ct_filter_check. Signed-off-by: Pablo Neira Ayuso --- src/filter.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/filter.c b/src/filter.c index 33fe30e..c4854bb 100644 --- a/src/filter.c +++ b/src/filter.c @@ -211,9 +211,7 @@ int ct_filter_check(struct ct_filter *f, struct nf_conntrack *ct) if (f->logic[CT_FILTER_L4PROTO] != -1) { ret = test_bit_u32(protonum, f->l4protomap); - if (ret == 0 && f->logic[CT_FILTER_L4PROTO]) - return 0; - else if (ret == 1 && !f->logic[CT_FILTER_L4PROTO]) + if (ret ^ f->logic[CT_FILTER_L4PROTO]) return 0; } @@ -221,16 +219,12 @@ int ct_filter_check(struct ct_filter *f, struct nf_conntrack *ct) switch(nfct_get_attr_u8(ct, ATTR_L3PROTO)) { case AF_INET: ret = __ct_filter_test_ipv4(f, ct); - if (ret == 0 && f->logic[CT_FILTER_ADDRESS]) - return 0; - else if (ret == 1 && !f->logic[CT_FILTER_ADDRESS]) + if (ret ^ f->logic[CT_FILTER_ADDRESS]) return 0; break; case AF_INET6: - ret = __ct_filter_test_ipv6(f, ct); - if (ret == 0 && f->logic[CT_FILTER_ADDRESS]) - return 0; - else if (ret == 1 && !f->logic[CT_FILTER_ADDRESS]) + ret = __ct_filter_test_ipv6(f, ct); + if (ret ^ f->logic[CT_FILTER_ADDRESS]) return 0; break; default: @@ -240,9 +234,7 @@ int ct_filter_check(struct ct_filter *f, struct nf_conntrack *ct) if (f->logic[CT_FILTER_STATE] != -1) { ret = __ct_filter_test_state(f, ct); - if (ret == 0 && f->logic[CT_FILTER_STATE]) - return 0; - else if (ret == 1 && !f->logic[CT_FILTER_STATE]) + if (ret ^ f->logic[CT_FILTER_STATE]) return 0; } -- cgit v1.2.3 From e6d816f8d096d98deeb0a52f96d44a4ace03ffe7 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 15 Nov 2008 21:22:24 +0100 Subject: filter: use jhash2 instead of jhash for IPv6 addresses Since an IPv6 address can be seen as an array of uint32_t. Use the optimized jhash2() function instead of the generic jhash(). Signed-off-by: Pablo Neira Ayuso --- include/jhash.h | 2 +- src/filter.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/include/jhash.h b/include/jhash.h index 38b8780..d164e38 100644 --- a/include/jhash.h +++ b/include/jhash.h @@ -87,7 +87,7 @@ static inline u32 jhash(const void *key, u32 length, u32 initval) /* A special optimized version that handles 1 or more of u32s. * The length parameter here is the number of u32s in the key. */ -static inline u32 jhash2(u32 *k, u32 length, u32 initval) +static inline u32 jhash2(const u32 *k, u32 length, u32 initval) { u32 a, b, c, len; diff --git a/src/filter.c b/src/filter.c index c4854bb..83c2eb3 100644 --- a/src/filter.c +++ b/src/filter.c @@ -49,7 +49,7 @@ static uint32_t hash(const void *data, struct hashtable *table) static uint32_t hash6(const void *data, struct hashtable *table) { - return jhash(data, sizeof(uint32_t)*4, 0) % table->hashsize; + return jhash2(data, 4, 0) % table->hashsize; } static int compare(const void *data1, const void *data2) -- cgit v1.2.3 From 2ea70aa69ec0535101d0f417517fc3d4454ca840 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 15 Nov 2008 21:22:24 +0100 Subject: filter: remove useless branch in the check functions If the logic is set to -1, this means that we do not perform any filtering for this sort of network address. Therefore, we don't need to re-check if there is any filter later. This patch also inlines the check functions. Signed-off-by: Pablo Neira Ayuso --- src/filter.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/filter.c b/src/filter.c index 83c2eb3..f6da8bb 100644 --- a/src/filter.c +++ b/src/filter.c @@ -161,23 +161,17 @@ void ct_filter_add_state(struct ct_filter *f, int protonum, int val) set_bit_u16(val, &f->statemap[protonum]); } -static int +static inline int __ct_filter_test_ipv4(struct ct_filter *f, struct nf_conntrack *ct) { - if (!f->h) - return 0; - /* we only use the real source and destination address */ return (hashtable_test(f->h, nfct_get_attr(ct, ATTR_ORIG_IPV4_SRC)) || hashtable_test(f->h, nfct_get_attr(ct, ATTR_REPL_IPV4_SRC))); } -static int +static inline int __ct_filter_test_ipv6(struct ct_filter *f, struct nf_conntrack *ct) { - if (!f->h6) - return 0; - return (hashtable_test(f->h6, nfct_get_attr(ct, ATTR_ORIG_IPV6_SRC)) || hashtable_test(f->h6, nfct_get_attr(ct, ATTR_REPL_IPV6_SRC))); } -- cgit v1.2.3 From d6f1b4be37e97dabb5de2d9ae664ef8afeec37ae Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 15 Nov 2008 21:22:24 +0100 Subject: conntrack: --status should not be mandatory with -I This patch relaxes the parameter checking as now we don't need to pass --status when we create a conntrack via command line interface. In this case, the conntrack entry is created only with the IPS_CONFIRMED flag. Signed-off-by: Pablo Neira Ayuso --- src/conntrack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index 152f94e..26e7408 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -124,7 +124,7 @@ static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = { /* s d r q p t u z e [ ] { } a m i f n g o c b*/ /*CT_LIST*/ {2,2,2,2,2,0,2,2,0,0,0,0,0,0,2,0,2,2,2,2,2,0}, -/*CT_CREATE*/ {2,2,2,2,1,1,1,0,0,0,0,0,0,2,2,0,0,2,2,0,0,0}, +/*CT_CREATE*/ {2,2,2,2,1,1,0,0,0,0,0,0,0,2,2,0,0,2,2,0,0,0}, /*CT_UPDATE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0}, /*CT_DELETE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0}, /*CT_GET*/ {2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,2,0,0,0,2,0,0}, -- cgit v1.2.3 From 6d8903cbf33ac10e8e03f884a58e374adc366887 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 18 Nov 2008 10:33:33 +0100 Subject: filter: choose the filtering method via configuration file This patch changes the current behaviour of the filtering selection. Up to now, conntrackd has used the kernel version to select the filtering method based on the following logic: If kernel is >= 2.6.26 we use BSF-based filtering from kernel-space, otherwise, default to userspace. However, this filtering method still lacks of IPv6 support and it requires a patch that got into 2.6.29 to filter IPv6 addresses from kernel-space. To fix this issue, we default to user-space filtering and let the user choose the method via the configuration file. Signed-off-by: Pablo Neira Ayuso --- doc/sync/alarm/conntrackd.conf | 12 ++++++++++-- doc/sync/ftfw/conntrackd.conf | 12 ++++++++++-- doc/sync/notrack/conntrackd.conf | 12 ++++++++++-- include/conntrackd.h | 2 +- src/main.c | 4 ---- src/netlink.c | 8 +++++--- src/read_config_lex.l | 3 +++ src/read_config_yy.y | 16 +++++++++++++++- 8 files changed, 54 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/doc/sync/alarm/conntrackd.conf b/doc/sync/alarm/conntrackd.conf index 8d34697..6995d6c 100644 --- a/doc/sync/alarm/conntrackd.conf +++ b/doc/sync/alarm/conntrackd.conf @@ -159,8 +159,16 @@ General { # State. The filter is attached to an action that can be: Accept or # Ignore. Thus, you can define the event filtering policy of the # filter-sets in positive or negative logic depending on your needs. - # - Filter { + # You can select if conntrackd filters the event messages from + # user-space or kernel-space. The kernel-space event filtering + # saves some CPU cycles by avoiding the copy of the event message + # from kernel-space to user-space. The kernel-space event filtering + # is prefered, however, you require a Linux kernel >= 2.6.29 to + # filter from kernel-space. If you want to select kernel-space + # event filtering, use the keyword 'Kernelspace' instead of + # 'Userspace'. + # + Filter from Userspace { # # Accept only certain protocols: You may want to replicate # the state of flows depending on their layer 4 protocol. diff --git a/doc/sync/ftfw/conntrackd.conf b/doc/sync/ftfw/conntrackd.conf index 06c3d15..3a2ed0e 100644 --- a/doc/sync/ftfw/conntrackd.conf +++ b/doc/sync/ftfw/conntrackd.conf @@ -163,8 +163,16 @@ General { # State. The filter is attached to an action that can be: Accept or # Ignore. Thus, you can define the event filtering policy of the # filter-sets in positive or negative logic depending on your needs. - # - Filter { + # You can select if conntrackd filters the event messages from + # user-space or kernel-space. The kernel-space event filtering + # saves some CPU cycles by avoiding the copy of the event message + # from kernel-space to user-space. The kernel-space event filtering + # is prefered, however, you require a Linux kernel >= 2.6.29 to + # filter from kernel-space. If you want to select kernel-space + # event filtering, use the keyword 'Kernelspace' instead of + # 'Userspace'. + # + Filter from Userspace { # # Accept only certain protocols: You may want to replicate # the state of flows depending on their layer 4 protocol. diff --git a/doc/sync/notrack/conntrackd.conf b/doc/sync/notrack/conntrackd.conf index 446e981..e9835e8 100644 --- a/doc/sync/notrack/conntrackd.conf +++ b/doc/sync/notrack/conntrackd.conf @@ -147,8 +147,16 @@ General { # State. The filter is attached to an action that can be: Accept or # Ignore. Thus, you can define the event filtering policy of the # filter-sets in positive or negative logic depending on your needs. - # - Filter { + # You can select if conntrackd filters the event messages from + # user-space or kernel-space. The kernel-space event filtering + # saves some CPU cycles by avoiding the copy of the event message + # from kernel-space to user-space. The kernel-space event filtering + # is prefered, however, you require a Linux kernel >= 2.6.29 to + # filter from kernel-space. If you want to select kernel-space + # event filtering, use the keyword 'Kernelspace' instead of + # 'Userspace'. + # + Filter from Userspace { # # Accept only certain protocols: You may want to replicate # the state of flows depending on their layer 4 protocol. diff --git a/include/conntrackd.h b/include/conntrackd.h index 448d594..dc992db 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -91,7 +91,7 @@ struct ct_conf { unsigned int resend_queue_size; /* FTFW protocol */ unsigned int window_size; int cache_write_through; - int kernel_support_netlink_bsf; + int filter_from_kernelspace; struct { char logfile[FILENAME_MAXLEN]; int syslog_facility; diff --git a/src/main.c b/src/main.c index d6aa938..f811acf 100644 --- a/src/main.c +++ b/src/main.c @@ -97,10 +97,6 @@ int main(int argc, char *argv[]) exit(EXIT_FAILURE); } - /* BSF filter attaching does not report unsupported operations */ - if (version >= 2 && major >= 6 && minor >= 26) - CONFIG(kernel_support_netlink_bsf) = 1; - for (i=1; i T_IP T_PATH_VAL %token T_NUMBER @@ -686,7 +687,20 @@ family : T_FAMILY T_STRING conf.family = AF_INET; }; -filter : T_FILTER '{' filter_list '}'; +filter : T_FILTER '{' filter_list '}' +{ + CONFIG(filter_from_kernelspace) = 0; +}; + +filter : T_FILTER T_FROM T_USERSPACE '{' filter_list '}' +{ + CONFIG(filter_from_kernelspace) = 0; +}; + +filter : T_FILTER T_FROM T_KERNELSPACE '{' filter_list '}' +{ + CONFIG(filter_from_kernelspace) = 1; +}; filter_list : | filter_list filter_item; -- cgit v1.2.3 From 6262a4a7b7139fb5636228cb0f5a1e72f848d871 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 25 Nov 2008 01:56:47 +0100 Subject: build: add attribute header size to total attribute length This patch adds the size of the attribute header (4 bytes) to the length field of netattr. This fixes a possible invalid memory access in malformed messages. This change is included in the set of scheduled changes for 0.9.9 that break backward compatibility. This patch also removes a memset of 4096 by one to initialize the headers and the netattr paddings. Signed-off-by: Pablo Neira Ayuso --- include/network.h | 6 +++--- src/build.c | 7 +++++-- 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/include/network.h b/include/network.h index 2487c81..f24fb5f 100644 --- a/include/network.h +++ b/include/network.h @@ -49,7 +49,7 @@ enum { #define BUILD_NETMSG(ct, query) \ ({ \ char __net[4096]; \ - memset(__net, 0, sizeof(__net)); \ + memset(__net, 0, NETHDR_SIZ + NETPLD_SIZ); \ build_netmsg(ct, query, (struct nethdr *) __net); \ (struct nethdr *) __net; \ }) @@ -170,8 +170,8 @@ struct netattr { #define NTA_NEXT(x, len) \ ( \ - len -= NTA_ALIGN(NTA_LENGTH(x->nta_len)), \ - (struct netattr *)(((char *)x) + NTA_ALIGN(NTA_LENGTH(x->nta_len))) \ + len -= NTA_ALIGN(x->nta_len), \ + (struct netattr *)(((char *)x) + NTA_ALIGN(x->nta_len)) \ ) #define NTA_ALIGNTO 4 diff --git a/src/build.c b/src/build.c index 5143048..c776de8 100644 --- a/src/build.c +++ b/src/build.c @@ -24,9 +24,12 @@ static inline void * put_header(struct netpld *pld, int attr, size_t len) { struct netattr *nta = PLD_TAIL(pld); - pld->len += NTA_ALIGN(NTA_LENGTH(len)); + int total_size = NTA_ALIGN(NTA_LENGTH(len)); + int attr_size = NTA_LENGTH(len); + pld->len += total_size; nta->nta_attr = htons(attr); - nta->nta_len = htons(len); + nta->nta_len = htons(attr_size); + memset((unsigned char *)nta + attr_size, 0, total_size - attr_size); return NTA_DATA(nta); } -- cgit v1.2.3 From b2edf895af82914ab09a842641a45b7a806e9b1e Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 25 Nov 2008 23:34:48 +0100 Subject: filter: CIDR-based filtering support This patch adds CIDR-based filtering support. The current implementation is O(n). This patch also introduces the vector data type which is used to store the IP address and the network mask. Signed-off-by: Pablo Neira Ayuso --- doc/sync/alarm/conntrackd.conf | 3 ++ doc/sync/ftfw/conntrackd.conf | 3 ++ doc/sync/notrack/conntrackd.conf | 3 ++ include/Makefile.am | 2 +- include/cidr.h | 8 ++++ include/filter.h | 15 ++++++- include/vector.h | 13 ++++++ src/Makefile.am | 4 +- src/cidr.c | 59 ++++++++++++++++++++++++++ src/filter.c | 90 ++++++++++++++++++++++++++++++++++++++++ src/read_config_lex.l | 6 ++- src/read_config_yy.y | 86 +++++++++++++++++++++++++++++++------- src/vector.c | 88 +++++++++++++++++++++++++++++++++++++++ 13 files changed, 358 insertions(+), 22 deletions(-) create mode 100644 include/cidr.h create mode 100644 include/vector.h create mode 100644 src/cidr.c create mode 100644 src/vector.c (limited to 'src') diff --git a/doc/sync/alarm/conntrackd.conf b/doc/sync/alarm/conntrackd.conf index 6995d6c..31a1a4d 100644 --- a/doc/sync/alarm/conntrackd.conf +++ b/doc/sync/alarm/conntrackd.conf @@ -191,6 +191,9 @@ General { IPv4_address 192.168.0.1 IPv4_address 192.168.1.1 IPv4_address 192.168.100.100 # dedicated link ip + # + # You can also specify networks in format IP/cidr. + # IPv4_address 192.168.0.0/24 } # diff --git a/doc/sync/ftfw/conntrackd.conf b/doc/sync/ftfw/conntrackd.conf index 3a2ed0e..ae2fe78 100644 --- a/doc/sync/ftfw/conntrackd.conf +++ b/doc/sync/ftfw/conntrackd.conf @@ -195,6 +195,9 @@ General { IPv4_address 192.168.0.1 IPv4_address 192.168.1.1 IPv4_address 192.168.100.100 # dedicated link ip + # + # You can also specify networks in format IP/cidr. + # IPv4_address 192.168.0.0/24 } # diff --git a/doc/sync/notrack/conntrackd.conf b/doc/sync/notrack/conntrackd.conf index e9835e8..d0e141c 100644 --- a/doc/sync/notrack/conntrackd.conf +++ b/doc/sync/notrack/conntrackd.conf @@ -179,6 +179,9 @@ General { IPv4_address 192.168.0.1 IPv4_address 192.168.1.1 IPv4_address 192.168.100.100 # dedicated link ip + # + # You can also specify networks in format IP/cidr. + # IPv4_address 192.168.0.0/24 } # diff --git a/include/Makefile.am b/include/Makefile.am index 3287a0c..4d22993 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -2,6 +2,6 @@ noinst_HEADERS = alarm.h jhash.h slist.h cache.h linux_list.h linux_rbtree.h \ sync.h conntrackd.h local.h us-conntrack.h \ debug.h log.h hash.h mcast.h conntrack.h \ - network.h filter.h queue.h \ + network.h filter.h queue.h vector.h \ traffic_stats.h netlink.h fds.h event.h bitops.h diff --git a/include/cidr.h b/include/cidr.h new file mode 100644 index 0000000..f8a4e2a --- /dev/null +++ b/include/cidr.h @@ -0,0 +1,8 @@ +#ifndef _CIDR_H_ + +uint32_t ipv4_cidr2mask_host(uint8_t cidr); +uint32_t ipv4_cidr2mask_net(uint8_t cidr); +void ipv6_cidr2mask_host(uint8_t cidr, uint32_t *res); +void ipv6_cidr2mask_net(uint8_t cidr, uint32_t *res); + +#endif diff --git a/include/filter.h b/include/filter.h index de0754e..567be34 100644 --- a/include/filter.h +++ b/include/filter.h @@ -2,11 +2,13 @@ #define _FILTER_H_ #include +#include +#include enum ct_filter_type { CT_FILTER_L4PROTO, CT_FILTER_STATE, - CT_FILTER_ADDRESS, + CT_FILTER_ADDRESS, /* also for netmask */ CT_FILTER_MAX }; @@ -15,12 +17,23 @@ enum ct_filter_logic { CT_FILTER_POSITIVE = 1, }; +struct ct_filter_netmask_ipv4 { + uint32_t ip; + uint32_t mask; +}; + +struct ct_filter_netmask_ipv6 { + uint32_t ip[4]; + uint32_t mask[4]; +}; + struct nf_conntrack; struct ct_filter; struct ct_filter *ct_filter_create(void); void ct_filter_destroy(struct ct_filter *filter); int ct_filter_add_ip(struct ct_filter *filter, void *data, uint8_t family); +int ct_filter_add_netmask(struct ct_filter *filter, void *data, uint8_t family); void ct_filter_add_proto(struct ct_filter *filter, int protonum); void ct_filter_add_state(struct ct_filter *f, int protonum, int state); void ct_filter_set_logic(struct ct_filter *f, diff --git a/include/vector.h b/include/vector.h new file mode 100644 index 0000000..5b05cba --- /dev/null +++ b/include/vector.h @@ -0,0 +1,13 @@ +#ifndef _VECTOR_H_ +#define _VECTOR_H_ + +#include + +struct vector; + +struct vector *vector_create(size_t size); +void vector_destroy(struct vector *v); +int vector_add(struct vector *v, void *data); +int vector_iterate(struct vector *v, const void *data, int (*fcn)(const void *a, const void *b)); + +#endif diff --git a/src/Makefile.am b/src/Makefile.am index 82f7dfe..64ed2b5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -11,13 +11,13 @@ conntrack_LDADD = ../extensions/libct_proto_tcp.la ../extensions/libct_proto_udp conntrack_LDFLAGS = $(all_libraries) @LIBNETFILTER_CONNTRACK_LIBS@ conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c rbtree.c \ - local.c log.c mcast.c netlink.c \ + local.c log.c mcast.c netlink.c vector.c \ filter.c fds.c event.c \ cache.c cache_iterators.c \ cache_lifetime.c cache_timer.c cache_wt.c \ sync-mode.c sync-alarm.c sync-ftfw.c sync-notrack.c \ traffic_stats.c stats-mode.c \ - network.c \ + network.c cidr.c \ build.c parse.c \ read_config_yy.y read_config_lex.l diff --git a/src/cidr.c b/src/cidr.c new file mode 100644 index 0000000..d43dabc --- /dev/null +++ b/src/cidr.c @@ -0,0 +1,59 @@ +/* + * (C) 2006-2008 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include "cidr.h" + +/* returns the netmask in host byte order */ +uint32_t ipv4_cidr2mask_host(uint8_t cidr) +{ + return 0xFFFFFFFF << (32 - cidr); +} + +/* returns the netmask in network byte order */ +uint32_t ipv4_cidr2mask_net(uint8_t cidr) +{ + return htonl(ipv4_cidr2mask_host(cidr)); +} + +void ipv6_cidr2mask_host(uint8_t cidr, uint32_t *res) +{ + int i, j; + + memset(res, 0, sizeof(uint32_t)*4); + for (i = 0; i < 4 && cidr > 32; i++) { + res[i] = 0xFFFFFFFF; + cidr -= 32; + } + res[i] = 0xFFFFFFFF << (32 - cidr); + for (j = i+1; j < 4; j++) { + res[j] = 0; + } +} + +void ipv6_cidr2mask_net(uint8_t cidr, uint32_t *res) +{ + int i; + + ipv6_cidr2mask_host(cidr, res); + for (i=0; i<4; i++) + res[i] = htonl(res[i]); +} + diff --git a/src/filter.c b/src/filter.c index f6da8bb..905d10f 100644 --- a/src/filter.c +++ b/src/filter.c @@ -20,12 +20,14 @@ #include "bitops.h" #include "jhash.h" #include "hash.h" +#include "vector.h" #include "conntrackd.h" #include "log.h" #include #include #include +#include #include struct ct_filter { @@ -34,6 +36,8 @@ struct ct_filter { u_int16_t statemap[IPPROTO_MAX]; struct hashtable *h; struct hashtable *h6; + struct vector *v; + struct vector *v6; }; /* XXX: These should be configurable, better use a rb-tree */ @@ -95,6 +99,23 @@ struct ct_filter *ct_filter_create(void) return NULL; } + filter->v = vector_create(sizeof(struct ct_filter_netmask_ipv4)); + if (!filter->v) { + free(filter->h6); + free(filter->h); + free(filter); + return NULL; + } + + filter->v6 = vector_create(sizeof(struct ct_filter_netmask_ipv6)); + if (!filter->v6) { + free(filter->v); + free(filter->h6); + free(filter->h); + free(filter); + return NULL; + } + for (i=0; ilogic[i] = -1; @@ -105,6 +126,8 @@ void ct_filter_destroy(struct ct_filter *filter) { hashtable_destroy(filter->h); hashtable_destroy(filter->h6); + vector_destroy(filter->v); + vector_destroy(filter->v6); free(filter); } @@ -147,6 +170,39 @@ int ct_filter_add_ip(struct ct_filter *filter, void *data, uint8_t family) return 1; } +static int cmp_ipv4_addr(const void *a, const void *b) +{ + return memcmp(a, b, sizeof(struct ct_filter_netmask_ipv4)) == 0; +} + +static int cmp_ipv6_addr(const void *a, const void *b) +{ + return memcmp(a, b, sizeof(struct ct_filter_netmask_ipv6)) == 0; +} + +int ct_filter_add_netmask(struct ct_filter *filter, void *data, uint8_t family) +{ + filter = __filter_alloc(filter); + + switch(family) { + case AF_INET: + if (vector_iterate(filter->v, data, cmp_ipv4_addr)) { + errno = EEXIST; + return 0; + } + vector_add(filter->v, data); + break; + case AF_INET6: + if (vector_iterate(filter->v, data, cmp_ipv6_addr)) { + errno = EEXIST; + return 0; + } + vector_add(filter->v6, data); + break; + } + return 1; +} + void ct_filter_add_proto(struct ct_filter *f, int protonum) { f = __filter_alloc(f); @@ -176,6 +232,34 @@ __ct_filter_test_ipv6(struct ct_filter *f, struct nf_conntrack *ct) hashtable_test(f->h6, nfct_get_attr(ct, ATTR_REPL_IPV6_SRC))); } +static int +__ct_filter_test_mask4(const void *ptr, const void *ct) +{ + const struct ct_filter_netmask_ipv4 *elem = ptr; + const uint32_t src = nfct_get_attr_u32(ct, ATTR_ORIG_IPV4_SRC); + const uint32_t dst = nfct_get_attr_u32(ct, ATTR_REPL_IPV4_SRC); + + return ((elem->ip & elem->mask) == (src & elem->mask) || + (elem->ip & elem->mask) == (dst & elem->mask)); +} + +static int +__ct_filter_test_mask6(const void *ptr, const void *ct) +{ + const struct ct_filter_netmask_ipv6 *elem = ptr; + const uint32_t *src = nfct_get_attr(ct, ATTR_ORIG_IPV6_SRC); + const uint32_t *dst = nfct_get_attr(ct, ATTR_REPL_IPV6_SRC); + + return (((elem->ip[0] & elem->mask[0]) == (src[0] & elem->mask[0]) && + (elem->ip[1] & elem->mask[1]) == (src[1] & elem->mask[1]) && + (elem->ip[2] & elem->mask[2]) == (src[2] & elem->mask[2]) && + (elem->ip[3] & elem->mask[3]) == (src[3] & elem->mask[3])) || + ((elem->ip[0] & elem->mask[0]) == (dst[0] & elem->mask[0]) && + (elem->ip[1] & elem->mask[1]) == (dst[1] & elem->mask[1]) && + (elem->ip[2] & elem->mask[2]) == (dst[2] & elem->mask[2]) && + (elem->ip[3] & elem->mask[3]) == (dst[3] & elem->mask[3]))); +} + static int __ct_filter_test_state(struct ct_filter *f, struct nf_conntrack *ct) { uint16_t val = 0; @@ -212,11 +296,17 @@ int ct_filter_check(struct ct_filter *f, struct nf_conntrack *ct) if (f->logic[CT_FILTER_ADDRESS] != -1) { switch(nfct_get_attr_u8(ct, ATTR_L3PROTO)) { case AF_INET: + ret = vector_iterate(f->v, ct, __ct_filter_test_mask4); + if (ret ^ f->logic[CT_FILTER_ADDRESS]) + return 0; ret = __ct_filter_test_ipv4(f, ct); if (ret ^ f->logic[CT_FILTER_ADDRESS]) return 0; break; case AF_INET6: + ret = vector_iterate(f->v6, ct, __ct_filter_test_mask6); + if (ret ^ f->logic[CT_FILTER_ADDRESS]) + return 0; ret = __ct_filter_test_ipv6(f, ct); if (ret ^ f->logic[CT_FILTER_ADDRESS]) return 0; diff --git a/src/read_config_lex.l b/src/read_config_lex.l index cbb6ca8..67c95d3 100644 --- a/src/read_config_lex.l +++ b/src/read_config_lex.l @@ -36,14 +36,16 @@ is_on [o|O][n|N] is_off [o|O][f|F][f|F] integer [0-9]+ path \/[^\"\n ]* +ip4_cidr \/[0-2]*[0-9]+ ip4_end [0-9]*[0-9]+ ip4_part [0-2]*{ip4_end} -ip4 {ip4_part}\.{ip4_part}\.{ip4_part}\.{ip4_part} +ip4 {ip4_part}\.{ip4_part}\.{ip4_part}\.{ip4_part}{ip4_cidr}? hex_255 [0-9a-fA-F]{1,4} +ip6_cidr \/[0-1]*[0-9]*[0-9]+ ip6_part {hex_255}":"? ip6_form1 {ip6_part}{0,16}"::"{ip6_part}{0,16} ip6_form2 ({hex_255}":"){16}{hex_255} -ip6 {ip6_form1}|{ip6_form2} +ip6 {ip6_form1}{ip6_cidr}?|{ip6_form2}{ip6_cidr}? string [a-zA-Z][a-zA-Z0-9\.]* persistent [P|p][E|e][R|r][S|s][I|i][S|s][T|t][E|e][N|n][T|T] nack [N|n][A|a][C|c][K|k] diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 06ada52..32ddeff 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -26,6 +26,7 @@ #include #include "conntrackd.h" #include "bitops.h" +#include "cidr.h" #include #include #include @@ -780,27 +781,55 @@ filter_address_list : filter_address_item : T_IPV4_ADDR T_IP { union inet_address ip; + char *slash; + unsigned int cidr = 32; memset(&ip, 0, sizeof(union inet_address)); + slash = strchr($2, '/'); + if (slash) { + *slash = '\0'; + cidr = atoi(slash+1); + if (cidr > 32) { + fprintf(stderr, "%s/%d is not a valid network, " + "ignoring\n", $2, cidr); + break; + } + } + if (!inet_aton($2, &ip.ipv4)) { fprintf(stderr, "%s is not a valid IPv4, ignoring", $2); break; } - if (!ct_filter_add_ip(STATE(us_filter), &ip, AF_INET)) { - if (errno == EEXIST) - fprintf(stderr, "IP %s is repeated " - "in the ignore pool\n", $2); - if (errno == ENOSPC) - fprintf(stderr, "Too many IP in the ignore pool!\n"); + if (slash && cidr < 32) { + /* network byte order */ + struct ct_filter_netmask_ipv4 tmp = { + .ip = ip.ipv4, + .mask = ipv4_cidr2mask_net(cidr) + }; + + if (!ct_filter_add_netmask(STATE(us_filter), &tmp, AF_INET)) { + if (errno == EEXIST) + fprintf(stderr, "Netmask %s is repeated " + "in the ignore pool\n", $2); + } + } else { + if (!ct_filter_add_ip(STATE(us_filter), &ip, AF_INET)) { + if (errno == EEXIST) + fprintf(stderr, "IP %s is repeated " + "in the ignore pool\n", $2); + if (errno == ENOSPC) + fprintf(stderr, "Too many IP in the " + "ignore pool!\n"); + } } - __kernel_filter_start(); + /* host byte order */ struct nfct_filter_ipv4 filter_ipv4 = { - .addr = htonl(ip.ipv4), - .mask = 0xffffffff, + .addr = ntohl(ip.ipv4), + .mask = ipv4_cidr2mask_host(cidr), }; nfct_filter_add_attr(STATE(filter), NFCT_FILTER_SRC_IPV4, &filter_ipv4); @@ -810,9 +839,22 @@ filter_address_item : T_IPV4_ADDR T_IP filter_address_item : T_IPV6_ADDR T_IP { union inet_address ip; + char *slash; + int cidr; memset(&ip, 0, sizeof(union inet_address)); + slash = strchr($2, '/'); + if (slash) { + *slash = '\0'; + cidr = atoi(slash+1); + if (cidr > 128) { + fprintf(stderr, "%s/%d is not a valid network, " + "ignoring\n", $2, cidr); + break; + } + } + #ifdef HAVE_INET_PTON_IPV6 if (inet_pton(AF_INET6, $2, &ip.ipv6) <= 0) { fprintf(stderr, "%s is not a valid IPv6, ignoring", $2); @@ -822,13 +864,25 @@ filter_address_item : T_IPV6_ADDR T_IP fprintf(stderr, "Cannot find inet_pton(), IPv6 unsupported!"); break; #endif - - if (!ct_filter_add_ip(STATE(us_filter), &ip, AF_INET6)) { - if (errno == EEXIST) - fprintf(stderr, "IP %s is repeated " - "in the ignore pool\n", $2); - if (errno == ENOSPC) - fprintf(stderr, "Too many IP in the ignore pool!\n"); + if (slash && cidr < 128) { + struct ct_filter_netmask_ipv6 tmp; + + memcpy(tmp.ip, ip.ipv6, sizeof(uint32_t)*4); + ipv6_cidr2mask_net(cidr, tmp.mask); + if (!ct_filter_add_netmask(STATE(us_filter), &tmp, AF_INET6)) { + if (errno == EEXIST) + fprintf(stderr, "Netmask %s is repeated " + "in the ignore pool\n", $2); + } + } else { + if (!ct_filter_add_ip(STATE(us_filter), &ip, AF_INET6)) { + if (errno == EEXIST) + fprintf(stderr, "IP %s is repeated " + "in the ignore pool\n", $2); + if (errno == ENOSPC) + fprintf(stderr, "Too many IP in the " + "ignore pool!\n"); + } } }; diff --git a/src/vector.c b/src/vector.c new file mode 100644 index 0000000..c81e7ce --- /dev/null +++ b/src/vector.c @@ -0,0 +1,88 @@ +/* + * (C) 2006-2008 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "vector.h" + +#include +#include + +struct vector { + char *data; + unsigned int cur_elems; + unsigned int max_elems; + size_t size; +}; + +#define DEFAULT_VECTOR_MEMBERS 8 +#define DEFAULT_VECTOR_GROWTH 8 + +struct vector *vector_create(size_t size) +{ + struct vector *v; + + v = calloc(sizeof(struct vector), 1); + if (v == NULL) + return NULL; + + v->size = size; + v->cur_elems = 0; + v->max_elems = DEFAULT_VECTOR_MEMBERS; + + v->data = calloc(size * DEFAULT_VECTOR_MEMBERS, 1); + if (v->data == NULL) { + free(v); + return NULL; + } + + return v; +} + +void vector_destroy(struct vector *v) +{ + free(v->data); + free(v); +} + +int vector_add(struct vector *v, void *data) +{ + if (v->cur_elems >= v->max_elems) { + v->max_elems += DEFAULT_VECTOR_GROWTH; + v->data = realloc(v->data, v->max_elems * v->size); + if (v->data == NULL) { + v->max_elems -= DEFAULT_VECTOR_GROWTH; + return -1; + } + } + memcpy(v->data + (v->size * v->cur_elems), data, v->size); + v->cur_elems++; + return 0; +} + +int vector_iterate(struct vector *v, + const void *data, + int (*fcn)(const void *a, const void *b)) +{ + unsigned int i; + + for (i=0; icur_elems; i++) { + char *ptr = v->data + (v->size * i); + if (fcn(ptr, data)) + return 1; + } + return 0; +} -- cgit v1.2.3 From 1bc6f65123550e52c7d37645709931b20ceff2b3 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 26 Nov 2008 00:16:27 +0100 Subject: run: release fds structure in the exit path This patch adds the missing destroy_fds() in the exit path. Signed-off-by: Pablo Neira Ayuso --- src/run.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/run.c b/src/run.c index 34d20b0..ec110d7 100644 --- a/src/run.c +++ b/src/run.c @@ -46,6 +46,7 @@ void killer(int foo) STATE(mode)->kill(); nfct_close(STATE(dump)); /* cache_wt needs this here */ + destroy_fds(STATE(fds)); unlink(CONFIG(lockfile)); dlog(LOG_NOTICE, "---- shutdown received ----"); -- cgit v1.2.3 From 22353928caf9c821e70d15c2dd827c8725f6ac40 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 26 Nov 2008 00:16:57 +0100 Subject: fds: remove unused array of file descriptors This patch removes an unused array of file descriptors inside the fds structure. Signed-off-by: Pablo Neira Ayuso --- include/fds.h | 3 --- src/fds.c | 30 +----------------------------- 2 files changed, 1 insertion(+), 32 deletions(-) (limited to 'src') diff --git a/include/fds.h b/include/fds.h index cc213fe..019d3f9 100644 --- a/include/fds.h +++ b/include/fds.h @@ -3,9 +3,6 @@ struct fds { int maxfd; - int fd_array_len; - int fd_array_cur; - int *fd_array; fd_set readfds; }; diff --git a/src/fds.c b/src/fds.c index 908f048..fac3482 100644 --- a/src/fds.c +++ b/src/fds.c @@ -19,35 +19,19 @@ #include #include "fds.h" -/* we don't handle that many descriptors so eight is just fine */ -#define FDS_ARRAY_LEN 8 -#define FDS_ARRAY_SIZE (sizeof(int) * FDS_ARRAY_LEN) - struct fds *create_fds(void) { struct fds *fds; - fds = (struct fds *) malloc(sizeof(struct fds)); + fds = (struct fds *) calloc(sizeof(struct fds), 1); if (fds == NULL) return NULL; - memset(fds, 0, sizeof(struct fds)); - - fds->fd_array = (int *) malloc(FDS_ARRAY_SIZE); - if (fds->fd_array == NULL) { - free(fds); - return NULL; - } - - memset(fds->fd_array, 0, FDS_ARRAY_SIZE); - fds->fd_array_len = FDS_ARRAY_LEN; - return fds; } void destroy_fds(struct fds *fds) { - free(fds->fd_array); free(fds); } @@ -58,17 +42,5 @@ int register_fd(int fd, struct fds *fds) if (fd > fds->maxfd) fds->maxfd = fd; - if (fds->fd_array_cur >= fds->fd_array_len) { - fds->fd_array_len += FDS_ARRAY_LEN; - fds->fd_array = realloc(fds->fd_array, - fds->fd_array_len * sizeof(int)); - if (fds->fd_array == NULL) { - fds->fd_array_len -= FDS_ARRAY_LEN; - return -1; - } - } - - fds->fd_array[fds->fd_array_cur++] = fd; - return 0; } -- cgit v1.2.3 From e6832ed088eac06fee6316dd2ecb8003aa635f17 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 26 Nov 2008 00:30:27 +0100 Subject: ftfw: remove useless ftfw_run invocation in the alive alarm handler This patch removes a forced run of the transmission queue. This is not required since we currently have an event descriptor that indicates when to give a queue run to push pending messages. Signed-off-by: Pablo Neira Ayuso --- src/sync-ftfw.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'src') diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 598945f..abba1fe 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -120,8 +120,6 @@ static void tx_queue_add_ctlmsg(uint32_t flags, uint32_t from, uint32_t to) write_evfd(STATE_SYNC(evfd)); } -static void ftfw_run(void); - /* this function is called from the alarm framework */ static void do_alive_alarm(struct alarm_block *a, void *data) { @@ -133,10 +131,6 @@ static void do_alive_alarm(struct alarm_block *a, void *data) ack_from_set = 0; } else tx_queue_add_ctlmsg(NET_F_ALIVE, 0, 0); - - /* TODO: no need for buffered send, extracted from run_sync() */ - ftfw_run(); - mcast_buffered_pending_netmsg(STATE_SYNC(mcast_client)); } static int ftfw_init(void) -- cgit v1.2.3 From 9aba3974d60bfbc773ac366ad6b8859a5c000377 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 27 Nov 2008 23:40:13 +0100 Subject: src: move callbacks to run.c for better readability This patch is a cleanup. It moves the callbacks from netlink.c to run.c where they are actually invoked. This is better for code readability as I usually have to switch from run.c to netlink.c to remember what the callbacks actually do. Signed-off-by: Pablo Neira Ayuso --- include/filter.h | 2 +- include/netlink.h | 10 ++-- src/filter.c | 49 +++++++++++++++- src/netlink.c | 166 +++++++++++------------------------------------------- src/run.c | 72 +++++++++++++++++++++-- src/stats-mode.c | 2 +- src/sync-mode.c | 2 +- 7 files changed, 154 insertions(+), 149 deletions(-) (limited to 'src') diff --git a/include/filter.h b/include/filter.h index 567be34..9c2cf66 100644 --- a/include/filter.h +++ b/include/filter.h @@ -39,6 +39,6 @@ void ct_filter_add_state(struct ct_filter *f, int protonum, int state); void ct_filter_set_logic(struct ct_filter *f, enum ct_filter_type type, enum ct_filter_logic logic); -int ct_filter_check(struct ct_filter *filter, struct nf_conntrack *ct); +int ct_filter_conntrack(struct nf_conntrack *ct, int userspace); #endif diff --git a/include/netlink.h b/include/netlink.h index d13d33d..52482c1 100644 --- a/include/netlink.h +++ b/include/netlink.h @@ -6,15 +6,13 @@ struct nf_conntrack; struct nfct_handle; -int ignore_conntrack(struct nf_conntrack *ct, int userspace); +struct nfct_handle *nl_init_event_handler(void); -int nl_init_event_handler(void); +struct nfct_handle *nl_init_dump_handler(void); -int nl_init_dump_handler(void); +struct nfct_handle *nl_init_request_handler(void); -int nl_init_request_handler(void); - -int nl_init_overrun_handler(void); +struct nfct_handle *nl_init_overrun_handler(void); int nl_overrun_request_resync(void); diff --git a/src/filter.c b/src/filter.c index 905d10f..5a8b5d8 100644 --- a/src/filter.c +++ b/src/filter.c @@ -279,7 +279,7 @@ static int __ct_filter_test_state(struct ct_filter *f, struct nf_conntrack *ct) return test_bit_u16(val, &f->statemap[protonum]); } -int ct_filter_check(struct ct_filter *f, struct nf_conntrack *ct) +static int ct_filter_check(struct ct_filter *f, struct nf_conntrack *ct) { int ret, protonum = nfct_get_attr_u8(ct, ATTR_L4PROTO); @@ -324,3 +324,50 @@ int ct_filter_check(struct ct_filter *f, struct nf_conntrack *ct) return 1; } + +static inline int ct_filter_sanity_check(struct nf_conntrack *ct) +{ + if (!nfct_attr_is_set(ct, ATTR_L3PROTO)) { + dlog(LOG_ERR, "missing layer 3 protocol"); + return 0; + } + + switch(nfct_get_attr_u8(ct, ATTR_L3PROTO)) { + case AF_INET: + if (!nfct_attr_is_set(ct, ATTR_IPV4_SRC) || + !nfct_attr_is_set(ct, ATTR_IPV4_DST) || + !nfct_attr_is_set(ct, ATTR_REPL_IPV4_SRC) || + !nfct_attr_is_set(ct, ATTR_REPL_IPV4_DST)) { + dlog(LOG_ERR, "missing IPv4 address. " + "You forgot to load " + "nf_conntrack_ipv4?"); + return 0; + } + break; + case AF_INET6: + if (!nfct_attr_is_set(ct, ATTR_IPV6_SRC) || + !nfct_attr_is_set(ct, ATTR_IPV6_DST) || + !nfct_attr_is_set(ct, ATTR_REPL_IPV6_SRC) || + !nfct_attr_is_set(ct, ATTR_REPL_IPV6_DST)) { + dlog(LOG_ERR, "missing IPv6 address. " + "You forgot to load " + "nf_conntrack_ipv6?"); + return 0; + } + break; + } + return 1; +} + +/* we do user-space filtering for dump and resyncs */ +int ct_filter_conntrack(struct nf_conntrack *ct, int userspace) +{ + /* missing mandatory attributes in object */ + if (!ct_filter_sanity_check(ct)) + return 1; + + if (userspace && !ct_filter_check(STATE(us_filter), ct)) + return 1; + + return 0; +} diff --git a/src/netlink.c b/src/netlink.c index b8a2a02..81ac7a1 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -18,103 +18,27 @@ #include "netlink.h" #include "conntrackd.h" -#include "traffic_stats.h" #include "filter.h" #include "log.h" #include "debug.h" #include #include - -static int sanity_check(struct nf_conntrack *ct) -{ - if (!nfct_attr_is_set(ct, ATTR_L3PROTO)) { - dlog(LOG_ERR, "missing layer 3 protocol"); - return 0; - } - - switch(nfct_get_attr_u8(ct, ATTR_L3PROTO)) { - case AF_INET: - if (!nfct_attr_is_set(ct, ATTR_IPV4_SRC) || - !nfct_attr_is_set(ct, ATTR_IPV4_DST) || - !nfct_attr_is_set(ct, ATTR_REPL_IPV4_SRC) || - !nfct_attr_is_set(ct, ATTR_REPL_IPV4_DST)) { - dlog(LOG_ERR, "missing IPv4 address. " - "You forgot to load " - "nf_conntrack_ipv4?"); - return 0; - } - break; - case AF_INET6: - if (!nfct_attr_is_set(ct, ATTR_IPV6_SRC) || - !nfct_attr_is_set(ct, ATTR_IPV6_DST) || - !nfct_attr_is_set(ct, ATTR_REPL_IPV6_SRC) || - !nfct_attr_is_set(ct, ATTR_REPL_IPV6_DST)) { - dlog(LOG_ERR, "missing IPv6 address. " - "You forgot to load " - "nf_conntrack_ipv6?"); - return 0; - } - break; - } - return 1; -} - -/* we do user-space filtering for dump and resyncs */ -int ignore_conntrack(struct nf_conntrack *ct, int userspace) -{ - /* missing mandatory attributes in object */ - if (!sanity_check(ct)) - return 1; - - if (userspace && !ct_filter_check(STATE(us_filter), ct)) { - debug_ct(ct, "ignore traffic"); - return 1; - } - - return 0; -} - -static int event_handler(enum nf_conntrack_msg_type type, - struct nf_conntrack *ct, - void *data) -{ - /* skip user-space filtering if already do it in the kernel */ - if (ignore_conntrack(ct, !CONFIG(filter_from_kernelspace))) - return NFCT_CB_STOP; - - switch(type) { - case NFCT_T_NEW: - STATE(mode)->event_new(ct); - break; - case NFCT_T_UPDATE: - STATE(mode)->event_upd(ct); - break; - case NFCT_T_DESTROY: - if (STATE(mode)->event_dst(ct)) - update_traffic_stats(ct); - break; - default: - dlog(LOG_WARNING, "unknown msg from ctnetlink\n"); - break; - } - - return NFCT_CB_CONTINUE; -} - #include #include #include -int nl_init_event_handler(void) +struct nfct_handle *nl_init_event_handler(void) { - STATE(event) = nfct_open(CONNTRACK, NFCT_ALL_CT_GROUPS); - if (!STATE(event)) - return -1; + struct nfct_handle *h; + + h = nfct_open(CONNTRACK, NFCT_ALL_CT_GROUPS); + if (h == NULL) + return NULL; if (STATE(filter)) { if (CONFIG(filter_from_kernelspace)) { - if (nfct_filter_attach(nfct_fd(STATE(event)), + if (nfct_filter_attach(nfct_fd(h), STATE(filter)) == -1) { dlog(LOG_ERR, "cannot set event filtering: %s", strerror(errno)); @@ -126,18 +50,18 @@ int nl_init_event_handler(void) nfct_filter_destroy(STATE(filter)); } - fcntl(nfct_fd(STATE(event)), F_SETFL, O_NONBLOCK); + fcntl(nfct_fd(h), F_SETFL, O_NONBLOCK); /* set up socket buffer size */ if (CONFIG(netlink_buffer_size)) - nfnl_rcvbufsiz(nfct_nfnlh(STATE(event)), + nfnl_rcvbufsiz(nfct_nfnlh(h), CONFIG(netlink_buffer_size)); else { socklen_t socklen = sizeof(unsigned int); unsigned int read_size; /* get current buffer size */ - getsockopt(nfct_fd(STATE(event)), SOL_SOCKET, + getsockopt(nfct_fd(h), SOL_SOCKET, SO_RCVBUF, &read_size, &socklen); CONFIG(netlink_buffer_size) = read_size; @@ -148,69 +72,43 @@ int nl_init_event_handler(void) CONFIG(netlink_buffer_size_max_grown) = CONFIG(netlink_buffer_size); - /* register callback for events */ - nfct_callback_register(STATE(event), NFCT_T_ALL, event_handler, NULL); - - return 0; + return h; } -static int dump_handler(enum nf_conntrack_msg_type type, - struct nf_conntrack *ct, - void *data) +struct nfct_handle *nl_init_dump_handler(void) { - if (ignore_conntrack(ct, 1)) - return NFCT_CB_CONTINUE; - - switch(type) { - case NFCT_T_UPDATE: - STATE(mode)->dump(ct); - break; - default: - dlog(LOG_WARNING, "unknown msg from ctnetlink"); - break; - } - return NFCT_CB_CONTINUE; -} + struct nfct_handle *h; -int nl_init_dump_handler(void) -{ /* open dump netlink socket */ - STATE(dump) = nfct_open(CONNTRACK, 0); - if (!STATE(dump)) - return -1; - - /* register callback for dumped entries */ - nfct_callback_register(STATE(dump), NFCT_T_ALL, dump_handler, NULL); + h = nfct_open(CONNTRACK, 0); + if (h == NULL) + return NULL; - if (nl_dump_conntrack_table() == -1) - return -1; - - return 0; + return h; } -int nl_init_overrun_handler(void) +struct nfct_handle *nl_init_overrun_handler(void) { - STATE(overrun) = nfct_open(CONNTRACK, 0); - if (!STATE(overrun)) - return -1; + struct nfct_handle *h; + + h = nfct_open(CONNTRACK, 0); + if (h == NULL) + return NULL; - fcntl(nfct_fd(STATE(overrun)), F_SETFL, O_NONBLOCK); + fcntl(nfct_fd(h), F_SETFL, O_NONBLOCK); - nfct_callback_register(STATE(overrun), - NFCT_T_ALL, - STATE(mode)->overrun, - NULL); - return 0; + return h; } -/* no callback, it does not do anything with the output */ -int nl_init_request_handler(void) +struct nfct_handle *nl_init_request_handler(void) { - STATE(request) = nfct_open(CONNTRACK, 0); - if (!STATE(request)) - return -1; + struct nfct_handle *h; + + h = nfct_open(CONNTRACK, 0); + if (h == NULL) + return NULL; - return 0; + return h; } static int warned = 0; diff --git a/src/run.c b/src/run.c index ec110d7..6515e62 100644 --- a/src/run.c +++ b/src/run.c @@ -24,6 +24,7 @@ #include "log.h" #include "alarm.h" #include "fds.h" +#include "traffic_stats.h" #include #include @@ -100,6 +101,51 @@ static void do_overrun_alarm(struct alarm_block *a, void *data) add_alarm(&STATE(overrun_alarm), 2, 0); } +static int event_handler(enum nf_conntrack_msg_type type, + struct nf_conntrack *ct, + void *data) +{ + /* skip user-space filtering if already do it in the kernel */ + if (ct_filter_conntrack(ct, !CONFIG(filter_from_kernelspace))) + return NFCT_CB_STOP; + + switch(type) { + case NFCT_T_NEW: + STATE(mode)->event_new(ct); + break; + case NFCT_T_UPDATE: + STATE(mode)->event_upd(ct); + break; + case NFCT_T_DESTROY: + if (STATE(mode)->event_dst(ct)) + update_traffic_stats(ct); + break; + default: + dlog(LOG_WARNING, "unknown msg from ctnetlink\n"); + break; + } + + return NFCT_CB_CONTINUE; +} + +static int dump_handler(enum nf_conntrack_msg_type type, + struct nf_conntrack *ct, + void *data) +{ + if (ct_filter_conntrack(ct, 1)) + return NFCT_CB_CONTINUE; + + switch(type) { + case NFCT_T_UPDATE: + STATE(mode)->dump(ct); + break; + default: + dlog(LOG_WARNING, "unknown msg from ctnetlink"); + break; + } + return NFCT_CB_CONTINUE; +} + int init(void) { @@ -126,28 +172,44 @@ init(void) return -1; } - if (nl_init_event_handler() == -1) { + STATE(event) = nl_init_event_handler(); + if (STATE(event) == NULL) { dlog(LOG_ERR, "can't open netlink handler: %s", strerror(errno)); dlog(LOG_ERR, "no ctnetlink kernel support?"); return -1; } + nfct_callback_register(STATE(event), NFCT_T_ALL, event_handler, NULL); - if (nl_init_dump_handler() == -1) { + STATE(dump) = nl_init_dump_handler(); + if (STATE(dump) == NULL) { dlog(LOG_ERR, "can't open netlink handler: %s", strerror(errno)); dlog(LOG_ERR, "no ctnetlink kernel support?"); return -1; } + nfct_callback_register(STATE(dump), NFCT_T_ALL, dump_handler, NULL); - if (nl_init_overrun_handler() == -1) { + if (nl_dump_conntrack_table() == -1) { + dlog(LOG_ERR, "can't get kernel conntrack table"); + return -1; + } + + STATE(overrun) = nl_init_overrun_handler(); + if (STATE(overrun)== NULL) { dlog(LOG_ERR, "can't open netlink handler: %s", strerror(errno)); dlog(LOG_ERR, "no ctnetlink kernel support?"); return -1; } - - if (nl_init_request_handler() == -1) { + nfct_callback_register(STATE(overrun), + NFCT_T_ALL, + STATE(mode)->overrun, + NULL); + + /* no callback, it does not do anything with the output */ + STATE(request) = nl_init_request_handler(); + if (STATE(request) == NULL) { dlog(LOG_ERR, "can't open netlink handler: %s", strerror(errno)); dlog(LOG_ERR, "no ctnetlink kernel support?"); diff --git a/src/stats-mode.c b/src/stats-mode.c index 763afe0..ad28008 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -104,7 +104,7 @@ static int overrun_stats(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data) { - if (ignore_conntrack(ct, 1)) + if (ct_filter_conntrack(ct, 1)) return NFCT_CB_CONTINUE; /* This is required by kernels < 2.6.20 */ diff --git a/src/sync-mode.c b/src/sync-mode.c index 152a8e2..e613111 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -438,7 +438,7 @@ static int overrun_sync(enum nf_conntrack_msg_type type, { struct us_conntrack *u; - if (ignore_conntrack(ct, 1)) + if (ct_filter_conntrack(ct, 1)) return NFCT_CB_CONTINUE; /* This is required by kernels < 2.6.20 */ -- cgit v1.2.3 From 35a22c2721d92c983dc130468ca48aaae46be299 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 28 Nov 2008 00:44:46 +0100 Subject: conntrack: do_parse_parameter show warning to stderr (not to stdout) This patch fixes a wrong warning display to stdout instead of stderr. Make the warning message homogeneous to others. Signed-off-by: Pablo Neira Ayuso --- src/conntrack.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index 26e7408..999df87 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -379,12 +379,14 @@ do_parse_parameter(const char *str, size_t str_length, unsigned int *value, struct parse_parameter *p = &parse_array[parse_type]; if (strncasecmp(str, "SRC_NAT", str_length) == 0) { - printf("skipping SRC_NAT, use --src-nat instead\n"); + fprintf(stderr, "WARNING: ignoring SRC_NAT, " + "use --src-nat instead\n"); return 1; } if (strncasecmp(str, "DST_NAT", str_length) == 0) { - printf("skipping DST_NAT, use --dst-nat instead\n"); + fprintf(stderr, "WARNING: ignoring DST_NAT, " + "use --dst-nat instead\n"); return 1; } -- cgit v1.2.3 From 43ba03341b176cb71502df0ac7b979447b98fad9 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 28 Nov 2008 00:45:03 +0100 Subject: conntrack: remove hardcoded buffer size, use sizeof instead This patch replaces a couple of hardcoded buffer sizes by sizeof() calls. This sort of code is error-prone. Signed-off-by: Pablo Neira Ayuso --- src/conntrack.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index 999df87..9d73631 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -759,7 +759,7 @@ static int delete_cb(enum nf_conntrack_msg_type type, if (output_mask & _O_ID) op_flags |= NFCT_OF_ID; - nfct_snprintf(buf, 1024, ct, NFCT_T_UNKNOWN, op_type, op_flags); + nfct_snprintf(buf, sizeof(buf), ct, NFCT_T_UNKNOWN, op_type, op_flags); printf("%s\n", buf); counter++; @@ -782,7 +782,7 @@ static int print_cb(enum nf_conntrack_msg_type type, if (output_mask & _O_ID) op_flags |= NFCT_OF_ID; - nfct_snprintf(buf, 1024, ct, NFCT_T_UNKNOWN, op_type, op_flags); + nfct_snprintf(buf, sizeof(buf), ct, NFCT_T_UNKNOWN, op_type, op_flags); printf("%s\n", buf); return NFCT_CB_CONTINUE; @@ -848,7 +848,7 @@ static int dump_exp_cb(enum nf_conntrack_msg_type type, { char buf[1024]; - nfexp_snprintf(buf, 1024, exp, NFCT_T_UNKNOWN, NFCT_O_DEFAULT, 0); + nfexp_snprintf(buf,sizeof(buf), exp, NFCT_T_UNKNOWN, NFCT_O_DEFAULT, 0); printf("%s\n", buf); counter++; -- cgit v1.2.3 From a81b65aee06b864772647d9ec0ee09fdaccf2889 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 28 Nov 2008 00:45:05 +0100 Subject: conntrack: support diminutives for -L With this patch, you can specify the following command to dump the expectation table, instead of writing 'expect'. # conntrack -L e also, it is valid the following command: # conntrack -L ex # conntrack -L exp and so on. Signed-off-by: Pablo Neira Ayuso --- src/conntrack.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index 9d73631..e165144 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -442,9 +442,9 @@ check_type(int argc, char *argv[]) if (!table) return 0; - if (strncmp("expect", table, 6) == 0) + if (strncmp("expect", table, strlen(table)) == 0) return 1; - else if (strncmp("conntrack", table, 9) == 0) + else if (strncmp("conntrack", table, strlen(table)) == 0) return 0; else exit_error(PARAMETER_PROBLEM, "unknown type `%s'", table); -- cgit v1.2.3 From 1cd6dc33d533d05f5212f215521d5c3c9e362714 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 28 Nov 2008 00:45:06 +0100 Subject: conntrack: move release options code to free_options() This patch move the options release to free_options(). It also move the free_options call after the error checking because exit_error already free the option. Signed-off-by: Pablo Neira Ayuso --- src/conntrack.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index e165144..8946ec8 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -223,18 +223,21 @@ exit_tryhelp(int status) exit(status); } -void __attribute__((noreturn)) -exit_error(enum exittype status, const char *msg, ...) +static void free_options(void) { - va_list args; - - /* On error paths, make sure that we don't leak the memory - * reserved during options merging */ if (opts != original_opts) { free(opts); opts = original_opts; global_option_offset = 0; } +} + +void __attribute__((noreturn)) +exit_error(enum exittype status, const char *msg, ...) +{ + va_list args; + + free_options(); va_start(args, msg); fprintf(stderr,"%s v%s (conntrack-tools): ", PROGNAME, VERSION); vfprintf(stderr, msg, args); @@ -1333,16 +1336,12 @@ int main(int argc, char *argv[]) break; } - if (opts != original_opts) { - free(opts); - opts = original_opts; - global_option_offset = 0; - } - if (res < 0) exit_error(OTHER_PROBLEM, "Operation failed: %s", err2str(errno, command)); + free_options(); + if (exit_msg[cmd][0]) { fprintf(stderr, "%s v%s (conntrack-tools): ",PROGNAME,VERSION); fprintf(stderr, exit_msg[cmd], counter); -- cgit v1.2.3 From 1fadc34c80a17e291f5ae86ecb84efbdb2aab265 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 30 Nov 2008 11:40:36 +0100 Subject: config: move `Checksum' inside `Multicast' clause This patch moves `Checksum' into the `Multicast' clause. This property is dependent of the multicast configuration. This patch is required to introduce the redundant dedicated link support that is on the way. Signed-off-by: Pablo Neira Ayuso --- doc/sync/alarm/conntrackd.conf | 13 +++++++------ doc/sync/ftfw/conntrackd.conf | 13 +++++++------ doc/sync/notrack/conntrackd.conf | 13 +++++++------ src/read_config_yy.y | 14 ++++++++++++++ 4 files changed, 35 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/doc/sync/alarm/conntrackd.conf b/doc/sync/alarm/conntrackd.conf index 31a1a4d..dfdc91d 100644 --- a/doc/sync/alarm/conntrackd.conf +++ b/doc/sync/alarm/conntrackd.conf @@ -94,13 +94,14 @@ Sync { # the receiver buffer. # # McastRcvSocketBuffer 1249280 - } - # - # Enable/Disable message checksumming. This is a good property to - # achieve fault-tolerance. In case of doubt, do not modify this value. - # - Checksum on + # + # Enable/Disable message checksumming. This is a good + # property to achieve fault-tolerance. In case of doubt, do + # not modify this value. + # + Checksum on + } } # diff --git a/doc/sync/ftfw/conntrackd.conf b/doc/sync/ftfw/conntrackd.conf index ae2fe78..bf5711e 100644 --- a/doc/sync/ftfw/conntrackd.conf +++ b/doc/sync/ftfw/conntrackd.conf @@ -98,13 +98,14 @@ Sync { # the receiver buffer. # # McastRcvSocketBuffer 1249280 - } - # - # Enable/Disable message checksumming. This is a good property to - # achieve fault-tolerance. In case of doubt, do not modify this value. - # - Checksum on + # + # Enable/Disable message checksumming. This is a good + # property to achieve fault-tolerance. In case of doubt, do + # not modify this value. + # + Checksum on + } } # diff --git a/doc/sync/notrack/conntrackd.conf b/doc/sync/notrack/conntrackd.conf index d0e141c..90189cd 100644 --- a/doc/sync/notrack/conntrackd.conf +++ b/doc/sync/notrack/conntrackd.conf @@ -82,13 +82,14 @@ Sync { # really recommended to increase the buffer size. McastRcvSocketBuffer 1249280 - } - # - # Enable/Disable message checksumming. This is a good property to - # achieve fault-tolerance. In case of doubt, do not modify this value. - # - Checksum on + # + # Enable/Disable message checksumming. This is a good + # property to achieve fault-tolerance. In case of doubt, do + # not modify this value. + # + Checksum on + } } # diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 32ddeff..69a7eff 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -172,11 +172,15 @@ purge: T_PURGE T_NUMBER checksum: T_CHECKSUM T_ON { + fprintf(stderr, "WARNING: The use of `Checksum' outside the " + "`Multicast' clause is ambiguous.\n"); conf.mcast.checksum = 0; }; checksum: T_CHECKSUM T_OFF { + fprintf(stderr, "WARNING: The use of `Checksum' outside the " + "`Multicast' clause is ambiguous.\n"); conf.mcast.checksum = 1; }; @@ -357,6 +361,16 @@ multicast_option: T_MCAST_RCVBUFF T_NUMBER conf.mcast.rcvbuf = $2; }; +multicast_option: T_CHECKSUM T_ON +{ + conf.mcast.checksum = 0; +}; + +multicast_option: T_CHECKSUM T_OFF +{ + conf.mcast.checksum = 1; +}; + hashsize : T_HASHSIZE T_NUMBER { conf.hashsize = $2; -- cgit v1.2.3 From 67994842694e57a42f524e228ca7acc564f2104f Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 30 Nov 2008 14:01:29 +0100 Subject: network: make tx buffer initialization independent of mcast config This patch changes the prototype of mcast_buffered_init() to receive as argument the MTU size instead of the multicast configuration. This decouples the initialization of the tx buffer from the multicast configuration. This patch is needed by the multi-dedicated link support. Signed-off-by: Pablo Neira Ayuso --- include/network.h | 2 +- src/network.c | 6 +++--- src/sync-mode.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/include/network.h b/include/network.h index f24fb5f..5da1db5 100644 --- a/include/network.h +++ b/include/network.h @@ -75,7 +75,7 @@ int mcast_track_is_seq_set(void); struct mcast_conf; -int mcast_buffered_init(struct mcast_conf *mconf); +int mcast_buffered_init(int mtu); void mcast_buffered_destroy(void); int mcast_buffered_send_netmsg(struct mcast_sock *m, void *data, size_t len); ssize_t mcast_buffered_pending_netmsg(struct mcast_sock *m); diff --git a/src/network.c b/src/network.c index 04c9d39..78be1e2 100644 --- a/src/network.c +++ b/src/network.c @@ -85,12 +85,12 @@ static char *tx_buf; #define HEADERSIZ 28 /* IP header (20 bytes) + UDP header 8 (bytes) */ -int mcast_buffered_init(struct mcast_conf *mconf) +int mcast_buffered_init(int if_mtu) { - int mtu = mconf->mtu - HEADERSIZ; + int mtu = if_mtu - HEADERSIZ; /* default to Ethernet MTU 1500 bytes */ - if (mconf->mtu == 0) + if (if_mtu == 0) mtu = 1500 - HEADERSIZ; tx_buf = malloc(mtu); diff --git a/src/sync-mode.c b/src/sync-mode.c index e613111..98867b2 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -233,7 +233,7 @@ static int init_sync(void) dlog(LOG_NOTICE, "multicast client socket sender queue " "has been set to %d bytes", CONFIG(mcast).sndbuf); - if (mcast_buffered_init(&CONFIG(mcast)) == -1) { + if (mcast_buffered_init(CONFIG(mcast).mtu) == -1) { dlog(LOG_ERR, "can't init tx buffer!"); mcast_server_destroy(STATE_SYNC(mcast_server)); mcast_client_destroy(STATE_SYNC(mcast_client)); -- cgit v1.2.3 From 20ef68b7a6090a939a48797b553477e0852c8f49 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 4 Dec 2008 17:15:08 +0100 Subject: conntrack: add new --status EXPECTED to filter expected connections With this patch, you can filter expected connections: # conntrack -L --status EXPECTED Signed-off-by: Pablo Neira Ayuso --- src/conntrack.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index 8946ec8..e8b2c4f 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -363,8 +363,8 @@ static struct parse_parameter { size_t size; unsigned int value[6]; } parse_array[PARSE_MAX] = { - { {"ASSURED", "SEEN_REPLY", "UNSET", "FIXED_TIMEOUT"}, 4, - { IPS_ASSURED, IPS_SEEN_REPLY, 0, IPS_FIXED_TIMEOUT} }, + { {"ASSURED", "SEEN_REPLY", "UNSET", "FIXED_TIMEOUT", "EXPECTED"}, 5, + { IPS_ASSURED, IPS_SEEN_REPLY, 0, IPS_FIXED_TIMEOUT, IPS_EXPECTED} }, { {"ALL", "NEW", "UPDATES", "DESTROY"}, 4, {~0U, NF_NETLINK_CONNTRACK_NEW, NF_NETLINK_CONNTRACK_UPDATE, NF_NETLINK_CONNTRACK_DESTROY} }, -- cgit v1.2.3 From 567222194512c6d42c7e253fc69c3837fe7b078c Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 6 Dec 2008 21:54:24 +0100 Subject: build: do not include NTA_TIMEOUT in the replication messages With this patch, NTA_TIMEOUT is not included in the replication messages anymore. During the fail-over, we set a small timeout to purge the entries that were not recovered successfully (however, unsuccessful recovery should not happen ever). Signed-off-by: Pablo Neira Ayuso --- include/network.h | 2 +- src/build.c | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'src') diff --git a/include/network.h b/include/network.h index 5da1db5..6ab099f 100644 --- a/include/network.h +++ b/include/network.h @@ -185,7 +185,7 @@ enum nta_attr { NTA_PORT, /* struct nfct_attr_grp_port */ NTA_STATE = 4, /* uint8_t */ NTA_STATUS, /* uint32_t */ - NTA_TIMEOUT, /* uint32_t */ + NTA_TIMEOUT, /* uint32_t -- unused */ NTA_MARK, /* uint32_t */ NTA_MASTER_IPV4 = 8, /* struct nfct_attr_grp_ipv4 */ NTA_MASTER_IPV6, /* struct nfct_attr_grp_ipv6 */ diff --git a/src/build.c b/src/build.c index c776de8..84515cf 100644 --- a/src/build.c +++ b/src/build.c @@ -117,8 +117,6 @@ void build_netpld(struct nf_conntrack *ct, struct netpld *pld, int query) if (nfct_attr_is_set(ct, ATTR_TCP_STATE)) __build_u8(ct, ATTR_TCP_STATE, pld, NTA_STATE); - if (nfct_attr_is_set(ct, ATTR_TIMEOUT)) - __build_u32(ct, ATTR_TIMEOUT, pld, NTA_TIMEOUT); if (nfct_attr_is_set(ct, ATTR_MARK)) __build_u32(ct, ATTR_MARK, pld, NTA_MARK); -- cgit v1.2.3 From 65ad316d921930c9d5c1c8640fbf2f05ecd0ca49 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 6 Dec 2008 21:54:43 +0100 Subject: netlink: clone conntrack object while creation/update This patch changes the behaviour of nl_create_conntrack() and nl_update_conntrack() which now clone the conntrack object received as parameter. This was not required as these functions were called inside fork(), thus, they modified a copy of the real conntrack objects in the child process. However, this behaviour is broken following the try-again logic in __do_commit_step. For example, if we try to update an expected conntrack object that has vanished for whatever reason, since nl_update_conntrack() modifies the object (unset the master conntrack information), nl_create_conntrak() will create an entry without the master conntrack information. Signed-off-by: Pablo Neira Ayuso --- include/netlink.h | 4 ++-- src/netlink.c | 28 ++++++++++++++++++++++------ 2 files changed, 24 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/include/netlink.h b/include/netlink.h index 52482c1..7e2b94c 100644 --- a/include/netlink.h +++ b/include/netlink.h @@ -24,9 +24,9 @@ int nl_exist_conntrack(struct nf_conntrack *ct); int nl_get_conntrack(struct nf_conntrack *ct); -int nl_create_conntrack(struct nf_conntrack *ct); +int nl_create_conntrack(const struct nf_conntrack *ct); -int nl_update_conntrack(struct nf_conntrack *ct); +int nl_update_conntrack(const struct nf_conntrack *ct); int nl_destroy_conntrack(struct nf_conntrack *ct); diff --git a/src/netlink.c b/src/netlink.c index 81ac7a1..1a86a21 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -183,10 +183,15 @@ int nl_get_conntrack(struct nf_conntrack *ct) return __nl_get_conntrack(STATE(dump), ct); } -/* This function modifies the conntrack passed as argument! */ -int nl_create_conntrack(struct nf_conntrack *ct) +int nl_create_conntrack(const struct nf_conntrack *orig) { + int ret; uint8_t flags; + struct nf_conntrack *ct; + + ct = nfct_clone(orig); + if (ct == NULL) + return -1; /* we hit error if we try to change the expected bit */ if (nfct_attr_is_set(ct, ATTR_STATUS)) { @@ -206,13 +211,21 @@ int nl_create_conntrack(struct nf_conntrack *ct) nfct_set_attr_u8(ct, ATTR_TCP_FLAGS_REPL, flags); nfct_set_attr_u8(ct, ATTR_TCP_MASK_REPL, flags); - return nfct_query(STATE(dump), NFCT_Q_CREATE_UPDATE, ct); + ret = nfct_query(STATE(dump), NFCT_Q_CREATE_UPDATE, ct); + nfct_destroy(ct); + + return ret; } -/* This function modifies the conntrack passed as argument! */ -int nl_update_conntrack(struct nf_conntrack *ct) +int nl_update_conntrack(const struct nf_conntrack *orig) { + int ret; uint8_t flags; + struct nf_conntrack *ct; + + ct = nfct_clone(orig); + if (ct == NULL) + return -1; /* unset NAT info, otherwise we hit error */ nfct_attr_unset(ct, ATTR_SNAT_IPV4); @@ -249,7 +262,10 @@ int nl_update_conntrack(struct nf_conntrack *ct) nfct_set_attr_u8(ct, ATTR_TCP_FLAGS_REPL, flags); nfct_set_attr_u8(ct, ATTR_TCP_MASK_REPL, flags); - return nfct_query(STATE(dump), NFCT_Q_CREATE_UPDATE, ct); + ret = nfct_query(STATE(dump), NFCT_Q_CREATE_UPDATE, ct); + nfct_destroy(ct); + + return ret; } int nl_destroy_conntrack(struct nf_conntrack *ct) -- cgit v1.2.3 From 2676982afacd502f3119cd323d060bbb88446057 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 7 Dec 2008 12:03:37 +0100 Subject: netlink: use NFCT_Q_[CREATE|UPDATE] instead of NFCT_Q_CREATE_UPDATE This patch uses NFCT_Q_CREATE in nl_create_conntrack() and NFCT_Q_UPDATE in nl_update_conntrack(). The NFCT_Q_CREATE_UPDATE query does not set the NLM_F_EXCL flag, so that it tries to update the entry if we fail to create. Under several scenarios, this may lead to problems. For example, the creation of related conntracks contain the master information. This is fine to create an entry, but an update will hit EOPNOTSUPP as ctnetlink considers that you are trying to change the master of an existing conntrack - and this is not a supported operation, of course. Signed-off-by: Pablo Neira Ayuso --- src/netlink.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/netlink.c b/src/netlink.c index 1a86a21..5929232 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -211,7 +211,7 @@ int nl_create_conntrack(const struct nf_conntrack *orig) nfct_set_attr_u8(ct, ATTR_TCP_FLAGS_REPL, flags); nfct_set_attr_u8(ct, ATTR_TCP_MASK_REPL, flags); - ret = nfct_query(STATE(dump), NFCT_Q_CREATE_UPDATE, ct); + ret = nfct_query(STATE(dump), NFCT_Q_CREATE, ct); nfct_destroy(ct); return ret; @@ -262,7 +262,7 @@ int nl_update_conntrack(const struct nf_conntrack *orig) nfct_set_attr_u8(ct, ATTR_TCP_FLAGS_REPL, flags); nfct_set_attr_u8(ct, ATTR_TCP_MASK_REPL, flags); - ret = nfct_query(STATE(dump), NFCT_Q_CREATE_UPDATE, ct); + ret = nfct_query(STATE(dump), NFCT_Q_UPDATE, ct); nfct_destroy(ct); return ret; -- cgit v1.2.3 From 27ee6a0f1255cb6c7dadc55caf3928fd62354314 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 7 Dec 2008 12:03:42 +0100 Subject: netlink: constify conntrack object parameter of nl_*_conntrack() This patch constifies the first parameter, which is a conntrack object, in all nl_*_conntrack() functions. Signed-off-by: Pablo Neira Ayuso --- include/netlink.h | 6 +++--- src/netlink.c | 9 +++++---- 2 files changed, 8 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/include/netlink.h b/include/netlink.h index 7e2b94c..af98c5e 100644 --- a/include/netlink.h +++ b/include/netlink.h @@ -20,15 +20,15 @@ void nl_resize_socket_buffer(struct nfct_handle *h); int nl_dump_conntrack_table(void); -int nl_exist_conntrack(struct nf_conntrack *ct); +int nl_exist_conntrack(const struct nf_conntrack *ct); -int nl_get_conntrack(struct nf_conntrack *ct); +int nl_get_conntrack(const struct nf_conntrack *ct); int nl_create_conntrack(const struct nf_conntrack *ct); int nl_update_conntrack(const struct nf_conntrack *ct); -int nl_destroy_conntrack(struct nf_conntrack *ct); +int nl_destroy_conntrack(const struct nf_conntrack *ct); static inline int ct_is_related(const struct nf_conntrack *ct) { diff --git a/src/netlink.c b/src/netlink.c index 5929232..89c85d7 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -154,7 +154,8 @@ int nl_overrun_request_resync(void) return nfct_send(STATE(overrun), NFCT_Q_DUMP, &family); } -static int __nl_get_conntrack(struct nfct_handle *h, struct nf_conntrack *ct) +static int +__nl_get_conntrack(struct nfct_handle *h, const struct nf_conntrack *ct) { int ret; char __tmp[nfct_maxsize()]; @@ -172,13 +173,13 @@ static int __nl_get_conntrack(struct nfct_handle *h, struct nf_conntrack *ct) return 1; } -int nl_exist_conntrack(struct nf_conntrack *ct) +int nl_exist_conntrack(const struct nf_conntrack *ct) { return __nl_get_conntrack(STATE(request), ct); } /* get the conntrack and update the cache */ -int nl_get_conntrack(struct nf_conntrack *ct) +int nl_get_conntrack(const struct nf_conntrack *ct) { return __nl_get_conntrack(STATE(dump), ct); } @@ -268,7 +269,7 @@ int nl_update_conntrack(const struct nf_conntrack *orig) return ret; } -int nl_destroy_conntrack(struct nf_conntrack *ct) +int nl_destroy_conntrack(const struct nf_conntrack *ct) { return nfct_query(STATE(dump), NFCT_Q_DESTROY, ct); } -- cgit v1.2.3 From 8663becfe12801a4b5a96137a0db26a8871948a3 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 8 Dec 2008 11:07:51 +0100 Subject: netlink: unset ATTR_HELPER_NAME to avoid EBUSY in nl_update_conntrack() This patch unsets the ATTR_HELPER_NAME attributes, otherwise we hit EBUSY for related conntrack entries while resetting the timers. Signed-off: Pablo Neira Ayuso --- src/netlink.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/netlink.c b/src/netlink.c index 89c85d7..31cee61 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -239,6 +239,9 @@ int nl_update_conntrack(const struct nf_conntrack *orig) status &= ~IPS_NAT_MASK; nfct_set_attr_u32(ct, ATTR_STATUS, status); } + /* we have to unset the helper to avoid EBUSY in reset timers */ + if (nfct_attr_is_set(ct, ATTR_HELPER_NAME)) + nfct_attr_unset(ct, ATTR_HELPER_NAME); /* we hit error if we try to update the master conntrack */ if (ct_is_related(ct)) { -- cgit v1.2.3 From 6042436a188581a327580f7821c0a3b94c4ef5d7 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 8 Dec 2008 11:07:58 +0100 Subject: parse: fix missing master layer 4 protocol number assignation This patch fixes NTA_MASTER_L4PROTO parsing which was missing. This problem was introduced in "network: rework TLV-based protocol", commit id 76ac8ebe5e49385585c8e29fe530ed4baef390bf, ie. somewhere in the development of 0.9.9. This patch also fixes the size of parsing callback array that is NTA_MAX, not ATTR_MAX. This problem does not affect conntrack-tools <= 0.9.8. Signed-off-by: Pablo Neira Ayuso --- include/network.h | 1 + src/parse.c | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/include/network.h b/include/network.h index 6ab099f..3f8123d 100644 --- a/include/network.h +++ b/include/network.h @@ -196,6 +196,7 @@ enum nta_attr { NTA_SPAT_PORT, /* uint16_t */ NTA_DPAT_PORT, /* uint16_t */ NTA_NAT_SEQ_ADJ = 16, /* struct nta_attr_natseqadj */ + NTA_MAX }; struct nta_attr_natseqadj { diff --git a/src/parse.c b/src/parse.c index 0184c5a..4eb74b2 100644 --- a/src/parse.c +++ b/src/parse.c @@ -35,7 +35,7 @@ struct parser { int attr; }; -static struct parser h[ATTR_MAX] = { +static struct parser h[NTA_MAX] = { [NTA_IPV4] = { .parse = parse_group, .attr = ATTR_GRP_ORIG_IPV4, @@ -76,6 +76,10 @@ static struct parser h[ATTR_MAX] = { .parse = parse_group, .attr = ATTR_GRP_MASTER_IPV6, }, + [NTA_MASTER_L4PROTO] = { + .parse = parse_u8, + .attr = ATTR_MASTER_L4PROTO, + }, [NTA_MASTER_PORT] = { .parse = parse_group, .attr = ATTR_GRP_MASTER_PORT, -- cgit v1.2.3 From 29b5df53bcbef17722ab2b389f3352c4e86b4795 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 8 Dec 2008 11:08:19 +0100 Subject: network: remove unused function mcast_send_netmsg() This patch removes the unused function mcast_send_netmsg(). Signed-off-by: Pablo Neira Ayuso --- include/network.h | 1 - src/network.c | 11 ----------- 2 files changed, 12 deletions(-) (limited to 'src') diff --git a/include/network.h b/include/network.h index 3f8123d..b64753c 100644 --- a/include/network.h +++ b/include/network.h @@ -59,7 +59,6 @@ struct mcast_sock; void build_netmsg(struct nf_conntrack *ct, int query, struct nethdr *net); size_t prepare_send_netmsg(struct mcast_sock *m, void *data); -int mcast_send_netmsg(struct mcast_sock *m, void *data); enum { SEQ_UNKNOWN, diff --git a/src/network.c b/src/network.c index 78be1e2..2f83d3b 100644 --- a/src/network.c +++ b/src/network.c @@ -140,17 +140,6 @@ ssize_t mcast_buffered_pending_netmsg(struct mcast_sock *m) return ret; } -int mcast_send_netmsg(struct mcast_sock *m, void *data) -{ - int ret; - size_t len = prepare_send_netmsg(m, data); - - ret = mcast_buffered_send_netmsg(m, data, len); - mcast_buffered_pending_netmsg(m); - - return ret; -} - void build_netmsg(struct nf_conntrack *ct, int query, struct nethdr *net) { struct netpld *pld = NETHDR_DATA(net); -- cgit v1.2.3 From bf6cfeb1dc6652eaff1b7c4edda45e15f5abf361 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 8 Dec 2008 11:09:02 +0100 Subject: network: remove length parameter of mcast_buffered_send_netmsg() This patch simplifies mcast_buffered_send_netmsg() by removing the length parameter. Instead, we use the length field in the nethdr to know the message size to be sent. Signed-off-by: Pablo Neira Ayuso --- include/network.h | 2 +- src/network.c | 5 ++--- src/sync-alarm.c | 2 +- src/sync-ftfw.c | 4 ++-- src/sync-mode.c | 2 +- src/sync-notrack.c | 4 ++-- 6 files changed, 9 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/include/network.h b/include/network.h index b64753c..1195303 100644 --- a/include/network.h +++ b/include/network.h @@ -76,7 +76,7 @@ struct mcast_conf; int mcast_buffered_init(int mtu); void mcast_buffered_destroy(void); -int mcast_buffered_send_netmsg(struct mcast_sock *m, void *data, size_t len); +int mcast_buffered_send_netmsg(struct mcast_sock *m, const struct nethdr *net); ssize_t mcast_buffered_pending_netmsg(struct mcast_sock *m); #define IS_DATA(x) ((x->flags & ~(NET_F_HELLO | NET_F_HELLO_BACK)) == 0) diff --git a/src/network.c b/src/network.c index 2f83d3b..a6ecb7e 100644 --- a/src/network.c +++ b/src/network.c @@ -108,10 +108,9 @@ void mcast_buffered_destroy(void) } /* return 0 if it is not sent, otherwise return 1 */ -int mcast_buffered_send_netmsg(struct mcast_sock *m, void *data, size_t len) +int mcast_buffered_send_netmsg(struct mcast_sock *m, const struct nethdr *net) { - int ret = 0; - struct nethdr *net = data; + int ret = 0, len = ntohs(net->len); retry: if (tx_buflen + len < tx_buflenmax) { diff --git a/src/sync-alarm.c b/src/sync-alarm.c index 4473af2..377af16 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -41,7 +41,7 @@ static void refresher(struct alarm_block *a, void *data) net = BUILD_NETMSG(u->ct, NFCT_Q_UPDATE); len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); + mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); } static void cache_alarm_add(struct us_conntrack *u, void *data) diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index abba1fe..293f9ab 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -495,7 +495,7 @@ static int tx_queue_xmit(void *data1, const void *data2) dp("tx_queue sq: %u fl:%u len:%u\n", ntohl(net->seq), net->flags, ntohs(net->len)); - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); + mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); HDR_NETWORK2HOST(net); if (IS_DATA(net) || IS_ACK(net) || IS_NACK(net)) @@ -518,7 +518,7 @@ static int tx_list_xmit(struct list_head *i, struct us_conntrack *u, int type) list_del_init(i); tx_list_len--; - ret = mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); + ret = mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); ftfw_send(net, u); return ret; diff --git a/src/sync-mode.c b/src/sync-mode.c index 98867b2..ac9d3f3 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -406,7 +406,7 @@ static void mcast_send_sync(struct us_conntrack *u, int query) if (STATE_SYNC(sync)->send) STATE_SYNC(sync)->send(net, u); - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); + mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); } static int purge_step(void *data1, void *data2) diff --git a/src/sync-notrack.c b/src/sync-notrack.c index c7ac9b5..c5ea1e6 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -157,7 +157,7 @@ static int tx_queue_xmit(void *data1, const void *data2) struct nethdr *net = data1; size_t len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); + mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); queue_del(tx_queue, net); return 0; @@ -172,7 +172,7 @@ static int tx_list_xmit(struct list_head *i, struct us_conntrack *u, int type) list_del_init(i); tx_list_len--; - ret = mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len); + ret = mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); return ret; } -- cgit v1.2.3 From 1c7352133af433d3d3881bb21e1de0e9e32f5b8c Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 8 Dec 2008 11:10:14 +0100 Subject: network: remove __do_send() function This patch removes __do_send() and replace it with the mcast_send() call. The debugging information that provides is not useful anymore with the tcpdump plugin. Signed-off-by: Pablo Neira Ayuso --- src/network.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/network.c b/src/network.c index a6ecb7e..ca00881 100644 --- a/src/network.c +++ b/src/network.c @@ -27,16 +27,6 @@ static unsigned int seq_set, cur_seq; -static size_t __do_send(struct mcast_sock *m, void *data, size_t len) -{ - struct nethdr *net = data; - - debug("send sq: %u fl:%u len:%u\n", - ntohl(net->seq), net->flags, ntohs(net->len)); - - return mcast_send(m, net, len); -} - static size_t __do_prepare(struct mcast_sock *m, void *data, size_t len) { struct nethdr *net = data; @@ -117,7 +107,7 @@ retry: memcpy(tx_buf + tx_buflen, net, len); tx_buflen += len; } else { - __do_send(m, tx_buf, tx_buflen); + mcast_send(m, tx_buf, tx_buflen); ret = 1; tx_buflen = 0; goto retry; @@ -133,7 +123,7 @@ ssize_t mcast_buffered_pending_netmsg(struct mcast_sock *m) if (tx_buflen == 0) return 0; - ret = __do_send(m, tx_buf, tx_buflen); + ret = mcast_send(m, tx_buf, tx_buflen); tx_buflen = 0; return ret; -- cgit v1.2.3 From a516e5f8e550a6073aae96491372c45ce340da88 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 8 Dec 2008 11:10:47 +0100 Subject: network: remove the netpld header from the messages This patch simplifies the message format of the replication messages. As a result, we save four bytes. The netpld header was introduced in the early protocol design. Today, it does not have any reason to exist. Signed-off-by: Pablo Neira Ayuso --- include/network.h | 47 +++++++++++++++++------------------ src/build.c | 72 ++++++++++++++++++++++++++---------------------------- src/network.c | 55 +++++++++++++++-------------------------- src/parse.c | 23 +++-------------- src/sync-alarm.c | 2 -- src/sync-ftfw.c | 8 +++--- src/sync-mode.c | 11 +++------ src/sync-notrack.c | 5 ++-- 8 files changed, 90 insertions(+), 133 deletions(-) (limited to 'src') diff --git a/include/network.h b/include/network.h index 1195303..11e65c7 100644 --- a/include/network.h +++ b/include/network.h @@ -9,25 +9,34 @@ struct nf_conntrack; struct nethdr { - uint8_t version; + uint8_t version:4, + type:4; uint8_t flags; uint16_t len; uint32_t seq; }; -#define NETHDR_SIZ sizeof(struct nethdr) +#define NETHDR_SIZ nethdr_align(sizeof(struct nethdr)) + +int nethdr_align(int len); +int nethdr_size(int len); +void nethdr_set(struct nethdr *net, int type); +void nethdr_set_ack(struct nethdr *net); #define NETHDR_DATA(x) \ - (struct netpld *)(((char *)x) + sizeof(struct nethdr)) + (struct netattr *)(((char *)x) + NETHDR_SIZ) +#define NETHDR_TAIL(x) \ + (struct netattr *)(((char *)x) + x->len) struct nethdr_ack { - uint8_t version; + uint8_t version:4, + type:4; uint8_t flags; uint16_t len; uint32_t seq; uint32_t from; uint32_t to; }; -#define NETHDR_ACK_SIZ sizeof(struct nethdr_ack) +#define NETHDR_ACK_SIZ nethdr_align(sizeof(struct nethdr_ack)) enum { NET_F_UNUSED = (1 << 0), @@ -49,17 +58,17 @@ enum { #define BUILD_NETMSG(ct, query) \ ({ \ char __net[4096]; \ - memset(__net, 0, NETHDR_SIZ + NETPLD_SIZ); \ - build_netmsg(ct, query, (struct nethdr *) __net); \ - (struct nethdr *) __net; \ + struct nethdr *__hdr = (struct nethdr *) __net; \ + memset(__hdr, 0, NETHDR_SIZ); \ + nethdr_set(__hdr, query); \ + build_payload(ct, __hdr); \ + HDR_HOST2NETWORK(__hdr); \ + __hdr; \ }) struct us_conntrack; struct mcast_sock; -void build_netmsg(struct nf_conntrack *ct, int query, struct nethdr *net); -size_t prepare_send_netmsg(struct mcast_sock *m, void *data); - enum { SEQ_UNKNOWN, SEQ_UNSET, @@ -129,12 +138,6 @@ static inline int between(uint32_t seq1, uint32_t seq2, uint32_t seq3) return seq3 - seq2 >= seq1 - seq2; } -struct netpld { - uint16_t len; - uint16_t query; -}; -#define NETPLD_SIZ sizeof(struct netpld) - #define PLD_NETWORK2HOST(x) \ ({ \ x->len = ntohs(x->len); \ @@ -158,12 +161,6 @@ struct netattr { x->nta_attr = ntohs(x->nta_attr); \ }) -#define PLD_DATA(x) \ - (struct netattr *)(((char *)x) + sizeof(struct netpld)) - -#define PLD_TAIL(x) \ - (struct netattr *)(((char *)x) + sizeof(struct netpld) + x->len) - #define NTA_DATA(x) \ (void *)(((char *)x) + sizeof(struct netattr)) @@ -207,8 +204,8 @@ struct nta_attr_natseqadj { uint32_t repl_seq_offset_after; }; -void build_netpld(struct nf_conntrack *ct, struct netpld *pld, int query); +void build_payload(const struct nf_conntrack *ct, struct nethdr *n); -int parse_netpld(struct nf_conntrack *ct, struct nethdr *net, int *query, size_t remain); +int parse_payload(struct nf_conntrack *ct, struct nethdr *n, size_t remain); #endif diff --git a/src/build.c b/src/build.c index 84515cf..e094aa0 100644 --- a/src/build.c +++ b/src/build.c @@ -21,12 +21,12 @@ #include "network.h" static inline void * -put_header(struct netpld *pld, int attr, size_t len) +put_header(struct nethdr *n, int attr, size_t len) { - struct netattr *nta = PLD_TAIL(pld); + struct netattr *nta = NETHDR_TAIL(n); int total_size = NTA_ALIGN(NTA_LENGTH(len)); int attr_size = NTA_LENGTH(len); - pld->len += total_size; + n->len += total_size; nta->nta_attr = htons(attr); nta->nta_len = htons(attr_size); memset((unsigned char *)nta + attr_size, 0, total_size - attr_size); @@ -34,45 +34,45 @@ put_header(struct netpld *pld, int attr, size_t len) } static inline void -addattr(struct netpld *pld, int attr, const void *data, size_t len) +addattr(struct nethdr *n, int attr, const void *data, size_t len) { - void *ptr = put_header(pld, attr, len); + void *ptr = put_header(n, attr, len); memcpy(ptr, data, len); } static inline void -__build_u8(const struct nf_conntrack *ct, int a, struct netpld *pld, int b) +__build_u8(const struct nf_conntrack *ct, int a, struct nethdr *n, int b) { - void *ptr = put_header(pld, b, sizeof(uint8_t)); + void *ptr = put_header(n, b, sizeof(uint8_t)); memcpy(ptr, nfct_get_attr(ct, a), sizeof(uint8_t)); } static inline void -__build_u16(const struct nf_conntrack *ct, int a, struct netpld *pld, int b) +__build_u16(const struct nf_conntrack *ct, int a, struct nethdr *n, int b) { uint32_t data = nfct_get_attr_u16(ct, a); data = htons(data); - addattr(pld, b, &data, sizeof(uint16_t)); + addattr(n, b, &data, sizeof(uint16_t)); } static inline void -__build_u32(const struct nf_conntrack *ct, int a, struct netpld *pld, int b) +__build_u32(const struct nf_conntrack *ct, int a, struct nethdr *n, int b) { uint32_t data = nfct_get_attr_u32(ct, a); data = htonl(data); - addattr(pld, b, &data, sizeof(uint32_t)); + addattr(n, b, &data, sizeof(uint32_t)); } static inline void -__build_group(const struct nf_conntrack *ct, int a, struct netpld *pld, +__build_group(const struct nf_conntrack *ct, int a, struct nethdr *n, int b, int size) { - void *ptr = put_header(pld, b, size); + void *ptr = put_header(n, b, size); nfct_get_attr_grp(ct, a, ptr); } static inline void -__build_natseqadj(const struct nf_conntrack *ct, struct netpld *pld) +__build_natseqadj(const struct nf_conntrack *ct, struct nethdr *n) { struct nta_attr_natseqadj data = { .orig_seq_correction_pos = @@ -88,7 +88,7 @@ __build_natseqadj(const struct nf_conntrack *ct, struct netpld *pld) .repl_seq_offset_after = htonl(nfct_get_attr_u32(ct, ATTR_REPL_NAT_SEQ_OFFSET_AFTER)) }; - addattr(pld, NTA_NAT_SEQ_ADJ, &data, sizeof(struct nta_attr_natseqadj)); + addattr(n, NTA_NAT_SEQ_ADJ, &data, sizeof(struct nta_attr_natseqadj)); } static enum nf_conntrack_attr nat_type[] = @@ -97,65 +97,61 @@ static enum nf_conntrack_attr nat_type[] = ATTR_REPL_NAT_SEQ_OFFSET_BEFORE, ATTR_REPL_NAT_SEQ_OFFSET_AFTER }; /* XXX: ICMP not supported */ -void build_netpld(struct nf_conntrack *ct, struct netpld *pld, int query) +void build_payload(const struct nf_conntrack *ct, struct nethdr *n) { if (nfct_attr_grp_is_set(ct, ATTR_GRP_ORIG_IPV4)) { - __build_group(ct, ATTR_GRP_ORIG_IPV4, pld, NTA_IPV4, + __build_group(ct, ATTR_GRP_ORIG_IPV4, n, NTA_IPV4, sizeof(struct nfct_attr_grp_ipv4)); } else if (nfct_attr_grp_is_set(ct, ATTR_GRP_ORIG_IPV6)) { - __build_group(ct, ATTR_GRP_ORIG_IPV6, pld, NTA_IPV6, + __build_group(ct, ATTR_GRP_ORIG_IPV6, n, NTA_IPV6, sizeof(struct nfct_attr_grp_ipv6)); } - __build_u8(ct, ATTR_L4PROTO, pld, NTA_L4PROTO); + __build_u8(ct, ATTR_L4PROTO, n, NTA_L4PROTO); if (nfct_attr_grp_is_set(ct, ATTR_GRP_ORIG_PORT)) { - __build_group(ct, ATTR_GRP_ORIG_PORT, pld, NTA_PORT, + __build_group(ct, ATTR_GRP_ORIG_PORT, n, NTA_PORT, sizeof(struct nfct_attr_grp_port)); } - __build_u32(ct, ATTR_STATUS, pld, NTA_STATUS); + __build_u32(ct, ATTR_STATUS, n, NTA_STATUS); if (nfct_attr_is_set(ct, ATTR_TCP_STATE)) - __build_u8(ct, ATTR_TCP_STATE, pld, NTA_STATE); + __build_u8(ct, ATTR_TCP_STATE, n, NTA_STATE); if (nfct_attr_is_set(ct, ATTR_MARK)) - __build_u32(ct, ATTR_MARK, pld, NTA_MARK); + __build_u32(ct, ATTR_MARK, n, NTA_MARK); /* setup the master conntrack */ if (nfct_attr_grp_is_set(ct, ATTR_GRP_MASTER_IPV4)) { - __build_group(ct, ATTR_GRP_MASTER_IPV4, pld, NTA_MASTER_IPV4, + __build_group(ct, ATTR_GRP_MASTER_IPV4, n, NTA_MASTER_IPV4, sizeof(struct nfct_attr_grp_ipv4)); - __build_u8(ct, ATTR_MASTER_L4PROTO, pld, NTA_MASTER_L4PROTO); + __build_u8(ct, ATTR_MASTER_L4PROTO, n, NTA_MASTER_L4PROTO); if (nfct_attr_grp_is_set(ct, ATTR_GRP_MASTER_PORT)) { __build_group(ct, ATTR_GRP_MASTER_PORT, - pld, NTA_MASTER_PORT, + n, NTA_MASTER_PORT, sizeof(struct nfct_attr_grp_port)); } } else if (nfct_attr_grp_is_set(ct, ATTR_GRP_MASTER_IPV6)) { - __build_group(ct, ATTR_GRP_MASTER_IPV6, pld, NTA_MASTER_IPV6, + __build_group(ct, ATTR_GRP_MASTER_IPV6, n, NTA_MASTER_IPV6, sizeof(struct nfct_attr_grp_ipv6)); - __build_u8(ct, ATTR_MASTER_L4PROTO, pld, NTA_MASTER_L4PROTO); + __build_u8(ct, ATTR_MASTER_L4PROTO, n, NTA_MASTER_L4PROTO); if (nfct_attr_grp_is_set(ct, ATTR_GRP_MASTER_PORT)) { __build_group(ct, ATTR_GRP_MASTER_PORT, - pld, NTA_MASTER_PORT, + n, NTA_MASTER_PORT, sizeof(struct nfct_attr_grp_port)); } } /* NAT */ if (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) - __build_u32(ct, ATTR_REPL_IPV4_DST, pld, NTA_SNAT_IPV4); + __build_u32(ct, ATTR_REPL_IPV4_DST, n, NTA_SNAT_IPV4); if (nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) - __build_u32(ct, ATTR_REPL_IPV4_SRC, pld, NTA_DNAT_IPV4); + __build_u32(ct, ATTR_REPL_IPV4_SRC, n, NTA_DNAT_IPV4); if (nfct_getobjopt(ct, NFCT_GOPT_IS_SPAT)) - __build_u16(ct, ATTR_REPL_PORT_DST, pld, NTA_SPAT_PORT); + __build_u16(ct, ATTR_REPL_PORT_DST, n, NTA_SPAT_PORT); if (nfct_getobjopt(ct, NFCT_GOPT_IS_DPAT)) - __build_u16(ct, ATTR_REPL_PORT_SRC, pld, NTA_DPAT_PORT); + __build_u16(ct, ATTR_REPL_PORT_SRC, n, NTA_DPAT_PORT); /* NAT sequence adjustment */ if (nfct_attr_is_set_array(ct, nat_type, 6)) - __build_natseqadj(ct, pld); - - pld->query = query; - - PLD_HOST2NETWORK(pld); + __build_natseqadj(ct, n); } diff --git a/src/network.c b/src/network.c index ca00881..34992ec 100644 --- a/src/network.c +++ b/src/network.c @@ -25,48 +25,40 @@ #include #include +#define NETHDR_ALIGNTO 4 + static unsigned int seq_set, cur_seq; -static size_t __do_prepare(struct mcast_sock *m, void *data, size_t len) +int nethdr_align(int value) { - struct nethdr *net = data; + return (value + NETHDR_ALIGNTO - 1) & ~(NETHDR_ALIGNTO - 1); +} +int nethdr_size(int len) +{ + return NETHDR_SIZ + len; +} + +static inline void __nethdr_set(struct nethdr *net, int len, int type) +{ if (!seq_set) { seq_set = 1; cur_seq = time(NULL); } - net->version = CONNTRACKD_PROTOCOL_VERSION; - net->len = len; - net->seq = cur_seq++; - HDR_HOST2NETWORK(net); - - return len; + net->version = CONNTRACKD_PROTOCOL_VERSION; + net->type = type; + net->len = len; + net->seq = cur_seq++; } -static size_t __prepare_ctl(struct mcast_sock *m, void *data) +void nethdr_set(struct nethdr *net, int type) { - return __do_prepare(m, data, NETHDR_ACK_SIZ); + __nethdr_set(net, NETHDR_SIZ, type); } -static size_t __prepare_data(struct mcast_sock *m, void *data) +void nethdr_set_ack(struct nethdr *net) { - struct nethdr *net = (struct nethdr *) data; - struct netpld *pld = NETHDR_DATA(net); - - return __do_prepare(m, data, ntohs(pld->len) + NETPLD_SIZ + NETHDR_SIZ); -} - -size_t prepare_send_netmsg(struct mcast_sock *m, void *data) -{ - int ret = 0; - struct nethdr *net = (struct nethdr *) data; - - if (IS_DATA(net)) - ret = __prepare_data(m, data); - else if (IS_CTL(net)) - ret = __prepare_ctl(m, data); - - return ret; + __nethdr_set(net, NETHDR_ACK_SIZ, 0); } static size_t tx_buflenmax; @@ -129,13 +121,6 @@ ssize_t mcast_buffered_pending_netmsg(struct mcast_sock *m) return ret; } -void build_netmsg(struct nf_conntrack *ct, int query, struct nethdr *net) -{ - struct netpld *pld = NETHDR_DATA(net); - - build_netpld(ct, pld, query); -} - static int local_seq_set = 0; /* this function only tracks, it does not update the last sequence received */ diff --git a/src/parse.c b/src/parse.c index 4eb74b2..17a0107 100644 --- a/src/parse.c +++ b/src/parse.c @@ -150,30 +150,16 @@ parse_nat_seq_adj(struct nf_conntrack *ct, int attr, void *data) ntohl(this->orig_seq_correction_pos)); } -int -parse_netpld(struct nf_conntrack *ct, - struct nethdr *net, - int *query, - size_t remain) +int parse_payload(struct nf_conntrack *ct, struct nethdr *net, size_t remain) { int len; struct netattr *attr; - struct netpld *pld; - if (remain < NETHDR_SIZ + sizeof(struct netpld)) + if (remain < net->len) return -1; - pld = NETHDR_DATA(net); - - if (remain < NETHDR_SIZ + sizeof(struct netpld) + ntohs(pld->len)) - return -1; - - if (net->len < NETHDR_SIZ + sizeof(struct netpld) + ntohs(pld->len)) - return -1; - - PLD_NETWORK2HOST(pld); - len = pld->len; - attr = PLD_DATA(pld); + len = net->len - NETHDR_SIZ; + attr = NETHDR_DATA(net); while (len > ssizeof(struct netattr)) { ATTR_NETWORK2HOST(attr); @@ -187,6 +173,5 @@ parse_netpld(struct nf_conntrack *ct, attr = NTA_NEXT(attr, len); } - *query = pld->query; return 0; } diff --git a/src/sync-alarm.c b/src/sync-alarm.c index 377af16..fe3d9af 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -29,7 +29,6 @@ static void refresher(struct alarm_block *a, void *data) { - size_t len; struct nethdr *net; struct us_conntrack *u = data; @@ -40,7 +39,6 @@ static void refresher(struct alarm_block *a, void *data) ((random() % 5 + 1) * 200000) - 1); net = BUILD_NETMSG(u->ct, NFCT_Q_UPDATE); - len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); } diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 293f9ab..a4895d4 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -451,10 +451,9 @@ out: static void ftfw_send(struct nethdr *net, struct us_conntrack *u) { - struct netpld *pld = NETHDR_DATA(net); struct cache_ftfw *cn; - switch(ntohs(pld->query)) { + switch(net->type) { case NFCT_Q_CREATE: case NFCT_Q_UPDATE: case NFCT_Q_DESTROY: @@ -490,7 +489,9 @@ static void ftfw_send(struct nethdr *net, struct us_conntrack *u) static int tx_queue_xmit(void *data1, const void *data2) { struct nethdr *net = data1; - size_t len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); + + nethdr_set_ack(net); + HDR_HOST2NETWORK(net); dp("tx_queue sq: %u fl:%u len:%u\n", ntohl(net->seq), net->flags, ntohs(net->len)); @@ -510,7 +511,6 @@ static int tx_list_xmit(struct list_head *i, struct us_conntrack *u, int type) { int ret; struct nethdr *net = BUILD_NETMSG(u->ct, type); - size_t len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); dp("tx_list sq: %u fl:%u len:%u\n", ntohl(net->seq), net->flags, ntohs(net->len)); diff --git a/src/sync-mode.c b/src/sync-mode.c index ac9d3f3..cfed7f4 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -36,7 +36,6 @@ static void do_mcast_handler_step(struct nethdr *net, size_t remain) { - int query; char __ct[nfct_maxsize()]; struct nf_conntrack *ct = (struct nf_conntrack *)(void*) __ct; struct us_conntrack *u; @@ -62,13 +61,13 @@ static void do_mcast_handler_step(struct nethdr *net, size_t remain) memset(ct, 0, sizeof(__ct)); - if (parse_netpld(ct, net, &query, remain) == -1) { + if (parse_payload(ct, net, remain) == -1) { STATE(malformed)++; dlog(LOG_ERR, "parsing failed: malformed message"); return; } - switch(query) { + switch(net->type) { case NFCT_Q_CREATE: retry: if ((u = cache_add(STATE_SYNC(external), ct))) { @@ -100,7 +99,7 @@ retry: break; default: STATE(malformed)++; - dlog(LOG_ERR, "mcast unknown query %d\n", query); + dlog(LOG_ERR, "mcast unknown query %d\n", net->type); break; } } @@ -109,7 +108,7 @@ retry: static void mcast_handler(void) { ssize_t numbytes; - size_t remain; + ssize_t remain; char __net[65536], *ptr = __net; /* XXX: maximum MTU for IPv4 */ numbytes = mcast_recv(STATE_SYNC(mcast_server), __net, sizeof(__net)); @@ -397,11 +396,9 @@ static void dump_sync(struct nf_conntrack *ct) static void mcast_send_sync(struct us_conntrack *u, int query) { - size_t len; struct nethdr *net; net = BUILD_NETMSG(u->ct, query); - len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); if (STATE_SYNC(sync)->send) STATE_SYNC(sync)->send(net, u); diff --git a/src/sync-notrack.c b/src/sync-notrack.c index c5ea1e6..fdb0c43 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -155,8 +155,8 @@ static int notrack_recv(const struct nethdr *net) static int tx_queue_xmit(void *data1, const void *data2) { struct nethdr *net = data1; - size_t len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); - + nethdr_set_ack(net); + HDR_HOST2NETWORK(net); mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); queue_del(tx_queue, net); @@ -167,7 +167,6 @@ static int tx_list_xmit(struct list_head *i, struct us_conntrack *u, int type) { int ret; struct nethdr *net = BUILD_NETMSG(u->ct, type); - size_t len = prepare_send_netmsg(STATE_SYNC(mcast_client), net); list_del_init(i); tx_list_len--; -- cgit v1.2.3 From 1f5834262c91d835414b538857b67e058a1c1dac Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 8 Dec 2008 23:58:31 +0100 Subject: parse: strict attribute size checking This patch adds strict attribute size checking. This is good to detect corrupted or malformed messages. Signed-off-by: Pablo Neira Ayuso --- include/network.h | 2 ++ src/parse.c | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+) (limited to 'src') diff --git a/include/network.h b/include/network.h index 96a0185..9098e5c 100644 --- a/include/network.h +++ b/include/network.h @@ -161,6 +161,8 @@ struct netattr { x->nta_attr = ntohs(x->nta_attr); \ }) +#define NTA_SIZE(len) NTA_ALIGN(sizeof(struct netattr)) + len + #define NTA_DATA(x) \ (void *)(((char *)x) + NTA_ALIGN(sizeof(struct netattr))) diff --git a/src/parse.c b/src/parse.c index 17a0107..75daac1 100644 --- a/src/parse.c +++ b/src/parse.c @@ -33,75 +33,93 @@ static void parse_nat_seq_adj(struct nf_conntrack *ct, int attr, void *data); struct parser { void (*parse)(struct nf_conntrack *ct, int attr, void *data); int attr; + int size; }; static struct parser h[NTA_MAX] = { [NTA_IPV4] = { .parse = parse_group, .attr = ATTR_GRP_ORIG_IPV4, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_ipv4)), }, [NTA_IPV6] = { .parse = parse_group, .attr = ATTR_GRP_ORIG_IPV6, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_ipv6)), }, [NTA_PORT] = { .parse = parse_group, .attr = ATTR_GRP_ORIG_PORT, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_port)), }, [NTA_L4PROTO] = { .parse = parse_u8, .attr = ATTR_L4PROTO, + .size = NTA_SIZE(sizeof(uint8_t)), }, [NTA_STATE] = { .parse = parse_u8, .attr = ATTR_TCP_STATE, + .size = NTA_SIZE(sizeof(uint8_t)), }, [NTA_STATUS] = { .parse = parse_u32, .attr = ATTR_STATUS, + .size = NTA_SIZE(sizeof(uint32_t)), }, [NTA_MARK] = { .parse = parse_u32, .attr = ATTR_MARK, + .size = NTA_SIZE(sizeof(uint32_t)), }, [NTA_TIMEOUT] = { .parse = parse_u32, .attr = ATTR_TIMEOUT, + .size = NTA_SIZE(sizeof(uint32_t)), }, [NTA_MASTER_IPV4] = { .parse = parse_group, .attr = ATTR_GRP_MASTER_IPV4, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_ipv4)), }, [NTA_MASTER_IPV6] = { .parse = parse_group, .attr = ATTR_GRP_MASTER_IPV6, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_ipv6)), }, [NTA_MASTER_L4PROTO] = { .parse = parse_u8, .attr = ATTR_MASTER_L4PROTO, + .size = NTA_SIZE(sizeof(uint8_t)), }, [NTA_MASTER_PORT] = { .parse = parse_group, .attr = ATTR_GRP_MASTER_PORT, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_port)), }, [NTA_SNAT_IPV4] = { .parse = parse_u32, .attr = ATTR_SNAT_IPV4, + .size = NTA_SIZE(sizeof(uint32_t)), }, [NTA_DNAT_IPV4] = { .parse = parse_u32, .attr = ATTR_DNAT_IPV4, + .size = NTA_SIZE(sizeof(uint32_t)), }, [NTA_SPAT_PORT] = { .parse = parse_u16, .attr = ATTR_SNAT_PORT, + .size = NTA_SIZE(sizeof(uint16_t)), }, [NTA_DPAT_PORT] = { .parse = parse_u16, .attr = ATTR_SNAT_PORT, + .size = NTA_SIZE(sizeof(uint16_t)), }, [NTA_NAT_SEQ_ADJ] = { .parse = parse_nat_seq_adj, + .size = NTA_SIZE(sizeof(struct nta_attr_natseqadj)), }, }; @@ -165,6 +183,8 @@ int parse_payload(struct nf_conntrack *ct, struct nethdr *net, size_t remain) ATTR_NETWORK2HOST(attr); if (attr->nta_len > len) return -1; + if (attr->nta_len != h[attr->nta_attr].size) + return -1; if (h[attr->nta_attr].parse == NULL) { attr = NTA_NEXT(attr, len); continue; -- cgit v1.2.3 From dd93edbbd09af4523dfe0f0c3c92f510daf223e8 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 9 Dec 2008 00:02:44 +0100 Subject: src: recover conntrackd -F operation This patch recovers the option -F for conntrackd. This will be particularly useful to flush the kernel conntrack table without getting the event notification of the conntrack deletions (that will happen with Linux kernel >= 2.6.29). Signed-off-by: Pablo Neira Ayuso --- conntrackd.8 | 4 ++++ include/netlink.h | 1 + src/netlink.c | 5 +++++ src/run.c | 8 ++------ 4 files changed, 12 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/conntrackd.8 b/conntrackd.8 index 769a0f1..2d7b228 100644 --- a/conntrackd.8 +++ b/conntrackd.8 @@ -37,6 +37,10 @@ with "-i" and "-e" parameters. .BI "-f " Flush the internal and the external cache .TP +.BI "-F " +Flush the kernel conntrack table (if you use a Linux kernel >= 2.6.29, this +option will not flush your internal and external cache). +.TP .BI "-k " Kill the daemon .TP diff --git a/include/netlink.h b/include/netlink.h index 52d2480..b44ef21 100644 --- a/include/netlink.h +++ b/include/netlink.h @@ -14,6 +14,7 @@ struct nfct_handle *nl_init_overrun_handler(void); int nl_overrun_request_resync(void); void nl_resize_socket_buffer(struct nfct_handle *h); int nl_dump_conntrack_table(void); +int nl_flush_conntrack_table(void); int nl_exist_conntrack(const struct nf_conntrack *ct); int nl_get_conntrack(const struct nf_conntrack *ct); int nl_create_conntrack(const struct nf_conntrack *ct); diff --git a/src/netlink.c b/src/netlink.c index 31cee61..9d155aa 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -148,6 +148,11 @@ int nl_dump_conntrack_table(void) return nfct_query(STATE(dump), NFCT_Q_DUMP, &CONFIG(family)); } +int nl_flush_conntrack_table(void) +{ + return nfct_query(STATE(request), NFCT_Q_FLUSH, &CONFIG(family)); +} + int nl_overrun_request_resync(void) { int family = CONFIG(family); diff --git a/src/run.c b/src/run.c index 6515e62..4bd0e5b 100644 --- a/src/run.c +++ b/src/run.c @@ -78,12 +78,8 @@ void local_handler(int fd, void *data) switch(type) { case FLUSH_MASTER: - dlog(LOG_WARNING, "`conntrackd -F' is deprecated. " - "Use conntrack -F instead."); - if (fork() == 0) { - execlp("conntrack", "conntrack", "-F", NULL); - exit(EXIT_SUCCESS); - } + dlog(LOG_NOTICE, "flushing kernel conntrack table"); + nl_flush_conntrack_table(); return; case RESYNC_MASTER: dlog(LOG_NOTICE, "resync with master table"); -- cgit v1.2.3 From dc544c894eddf90a77d49565673ea7eb216b3e44 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 10 Dec 2008 13:44:18 +0100 Subject: run: better wait() error handling The current wait() error handling was insufficient. This patch introduce more verbose error reporting. Signed-off-by: Pablo Neira Ayuso --- src/run.c | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/run.c b/src/run.c index 4bd0e5b..8158f10 100644 --- a/src/run.c +++ b/src/run.c @@ -60,7 +60,39 @@ void killer(int foo) static void child(int foo) { - while(wait(NULL) > 0); + int status, ret; + + while ((ret = waitpid(0, &status, WNOHANG)) != 0) { + if (ret == -1) { + if (errno == EINTR) + continue; + if (errno == ECHILD) + break; + dlog(LOG_ERR, "wait has failed (%s)", strerror(errno)); + break; + } + if (!WIFSIGNALED(status)) + continue; + + switch(WTERMSIG(status)) { + case SIGSEGV: + dlog(LOG_ERR, "child process (pid=%u) has aborted, " + "received signal SIGSEGV (crashed)", ret); + break; + case SIGINT: + case SIGTERM: + case SIGKILL: + dlog(LOG_ERR, "child process (pid=%u) has aborted, " + "received termination signal (%u)", + ret, WTERMSIG(status)); + break; + default: + dlog(LOG_NOTICE, "child process (pid=%u) " + "received signal (%u)", + ret, WTERMSIG(status)); + break; + } + } } void local_handler(int fd, void *data) -- cgit v1.2.3 From 98154b7d83d1493ba9c2d1b0a8e4b39b635e3082 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 11 Dec 2008 18:35:03 +0100 Subject: netlink: fix EILSEQ error messages due to process race condition This patch fixes a race condition that triggers EILSEQ errors (wrong sequence message). The problems is triggered when the child process resets the timers at the same time that the parent process requests a resync. Since both the child and the parent process use the same descriptors, the sequence tracking code in libnfnetlink gets confused as it considers that it is receiving out of sequence netlink messages. This patch introduces internal handlers to commit and reset timers so that the parent and the child do not use the same descriptors to operate with the kernel. This patch changes the prototype of all nf_*_conntrack() functions. Now, the nfct handler is passed as first parameter, this change is required to fix this problem. The rest of the changes on the API is done for consistency. Signed-off-by: Pablo Neira Ayuso --- include/netlink.h | 16 +++++++-------- src/cache_iterators.c | 56 ++++++++++++++++++++++++++++++++++++--------------- src/cache_wt.c | 10 ++++----- src/netlink.c | 32 ++++++++++++++--------------- src/run.c | 10 ++++----- 5 files changed, 74 insertions(+), 50 deletions(-) (limited to 'src') diff --git a/include/netlink.h b/include/netlink.h index b44ef21..5feb3e9 100644 --- a/include/netlink.h +++ b/include/netlink.h @@ -11,15 +11,15 @@ struct nfct_handle *nl_init_dump_handler(void); struct nfct_handle *nl_init_request_handler(void); struct nfct_handle *nl_init_overrun_handler(void); -int nl_overrun_request_resync(void); +int nl_overrun_request_resync(struct nfct_handle *h); void nl_resize_socket_buffer(struct nfct_handle *h); -int nl_dump_conntrack_table(void); -int nl_flush_conntrack_table(void); -int nl_exist_conntrack(const struct nf_conntrack *ct); -int nl_get_conntrack(const struct nf_conntrack *ct); -int nl_create_conntrack(const struct nf_conntrack *ct); -int nl_update_conntrack(const struct nf_conntrack *ct); -int nl_destroy_conntrack(const struct nf_conntrack *ct); +int nl_dump_conntrack_table(struct nfct_handle *h); +int nl_flush_conntrack_table(struct nfct_handle *h); +int nl_exist_conntrack(struct nfct_handle *h, const struct nf_conntrack *ct); +int nl_get_conntrack(struct nfct_handle *h, const struct nf_conntrack *ct); +int nl_create_conntrack(struct nfct_handle *h, const struct nf_conntrack *ct); +int nl_update_conntrack(struct nfct_handle *h, const struct nf_conntrack *ct); +int nl_destroy_conntrack(struct nfct_handle *h, const struct nf_conntrack *ct); static inline int ct_is_related(const struct nf_conntrack *ct) { diff --git a/src/cache_iterators.c b/src/cache_iterators.c index fd7aed6..661528f 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -95,7 +95,13 @@ void cache_dump(struct cache *c, int fd, int type) hashtable_iterate(c->h, (void *) &tmp, do_dump); } -static void __do_commit_step(struct cache *c, struct us_conntrack *u) +struct __commit_container { + struct nfct_handle *h; + struct cache *c; +}; + +static void +__do_commit_step(struct __commit_container *tmp, struct us_conntrack *u) { int ret, retry = 1; struct nf_conntrack *ct = u->ct; @@ -107,14 +113,14 @@ static void __do_commit_step(struct cache *c, struct us_conntrack *u) nfct_set_attr_u32(ct, ATTR_TIMEOUT, CONFIG(commit_timeout)); try_again: - ret = nl_exist_conntrack(ct); + ret = nl_exist_conntrack(tmp->h, ct); switch (ret) { case -1: dlog(LOG_ERR, "commit-exist: %s", strerror(errno)); dlog_ct(STATE(log), ct, NFCT_O_PLAIN); break; case 0: - if (nl_create_conntrack(ct) == -1) { + if (nl_create_conntrack(tmp->h, ct) == -1) { if (errno == ENOMEM) { if (retry) { retry = 0; @@ -124,13 +130,13 @@ try_again: } dlog(LOG_ERR, "commit-create: %s", strerror(errno)); dlog_ct(STATE(log), ct, NFCT_O_PLAIN); - c->commit_fail++; + tmp->c->commit_fail++; } else - c->commit_ok++; + tmp->c->commit_ok++; break; case 1: - c->commit_exist++; - if (nl_update_conntrack(ct) == -1) { + tmp->c->commit_exist++; + if (nl_update_conntrack(tmp->h, ct) == -1) { if (errno == ENOMEM || errno == ETIME) { if (retry) { retry = 0; @@ -140,7 +146,7 @@ try_again: } /* try harder, delete the entry and retry */ if (retry) { - ret = nl_destroy_conntrack(ct); + ret = nl_destroy_conntrack(tmp->h, ct); if (ret == 0 || (ret == -1 && errno == ENOENT)) { retry = 0; @@ -148,14 +154,14 @@ try_again: } dlog(LOG_ERR, "commit-rm: %s", strerror(errno)); dlog_ct(STATE(log), ct, NFCT_O_PLAIN); - c->commit_fail++; + tmp->c->commit_fail++; break; } dlog(LOG_ERR, "commit-update: %s", strerror(errno)); dlog_ct(STATE(log), ct, NFCT_O_PLAIN); - c->commit_fail++; + tmp->c->commit_fail++; } else - c->commit_ok++; + tmp->c->commit_ok++; break; } } @@ -188,10 +194,18 @@ void cache_commit(struct cache *c) unsigned int commit_ok = c->commit_ok; unsigned int commit_exist = c->commit_exist; unsigned int commit_fail = c->commit_fail; + struct __commit_container tmp; + + tmp.h = nfct_open(CONNTRACK, 0); + if (tmp.h == NULL) { + dlog(LOG_ERR, "can't create handler to commit entries"); + return; + } + tmp.c = c; /* commit master conntrack first, then related ones */ - hashtable_iterate(c->h, c, do_commit_master); - hashtable_iterate(c->h, c, do_commit_related); + hashtable_iterate(c->h, &tmp, do_commit_master); + hashtable_iterate(c->h, &tmp, do_commit_related); /* calculate new entries committed */ commit_ok = c->commit_ok - commit_ok; @@ -207,16 +221,18 @@ void cache_commit(struct cache *c) if (commit_fail) dlog(LOG_NOTICE, "%u entries can't be " "committed", commit_fail); + nfct_close(tmp.h); } static int do_reset_timers(void *data1, void *data2) { int ret; u_int32_t current_timeout; + struct nfct_handle *h = data1; struct us_conntrack *u = data2; struct nf_conntrack *ct = u->ct; - ret = nl_get_conntrack(ct); + ret = nl_get_conntrack(h, ct); switch (ret) { case -1: /* the kernel table is not in sync with internal cache */ @@ -231,7 +247,7 @@ static int do_reset_timers(void *data1, void *data2) nfct_set_attr_u32(ct, ATTR_TIMEOUT, CONFIG(purge_timeout)); - if (nl_update_conntrack(ct) == -1) { + if (nl_update_conntrack(h, ct) == -1) { if (errno == ETIME || errno == ENOENT) break; dlog(LOG_ERR, "reset-timers-upd: %s", strerror(errno)); @@ -244,7 +260,15 @@ static int do_reset_timers(void *data1, void *data2) void cache_reset_timers(struct cache *c) { - hashtable_iterate(c->h, NULL, do_reset_timers); + struct nfct_handle *h; + + h = nfct_open(CONNTRACK, 0); + if (h == NULL) { + dlog(LOG_ERR, "can't create handler to reset timers"); + return; + } + hashtable_iterate(c->h, h, do_reset_timers); + nfct_close(h); } static int do_flush(void *data1, void *data2) diff --git a/src/cache_wt.c b/src/cache_wt.c index 65a1fc4..d0ae8bb 100644 --- a/src/cache_wt.c +++ b/src/cache_wt.c @@ -31,7 +31,7 @@ static void add_wt(struct us_conntrack *u) char __ct[nfct_maxsize()]; struct nf_conntrack *ct = (struct nf_conntrack *)(void*) __ct; - ret = nl_exist_conntrack(u->ct); + ret = nl_exist_conntrack(STATE(request), u->ct); switch (ret) { case -1: dlog(LOG_ERR, "cache_wt problem: %s", strerror(errno)); @@ -39,14 +39,14 @@ static void add_wt(struct us_conntrack *u) break; case 0: memcpy(ct, u->ct, nfct_maxsize()); - if (nl_create_conntrack(ct) == -1) { + if (nl_create_conntrack(STATE(dump), ct) == -1) { dlog(LOG_ERR, "cache_wt create: %s", strerror(errno)); dlog_ct(STATE(log), u->ct, NFCT_O_PLAIN); } break; case 1: memcpy(ct, u->ct, nfct_maxsize()); - if (nl_update_conntrack(ct) == -1) { + if (nl_update_conntrack(STATE(dump), ct) == -1) { dlog(LOG_ERR, "cache_wt crt-upd: %s", strerror(errno)); dlog_ct(STATE(log), u->ct, NFCT_O_PLAIN); } @@ -61,7 +61,7 @@ static void upd_wt(struct us_conntrack *u) memcpy(ct, u->ct, nfct_maxsize()); - if (nl_update_conntrack(ct) == -1) { + if (nl_update_conntrack(STATE(dump), ct) == -1) { dlog(LOG_ERR, "cache_wt update:%s", strerror(errno)); dlog_ct(STATE(log), u->ct, NFCT_O_PLAIN); } @@ -79,7 +79,7 @@ static void writethrough_update(struct us_conntrack *u, void *data) static void writethrough_destroy(struct us_conntrack *u, void *data) { - nl_destroy_conntrack(u->ct); + nl_destroy_conntrack(STATE(dump), u->ct); } struct cache_feature writethrough_feature = { diff --git a/src/netlink.c b/src/netlink.c index 9d155aa..29281f4 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -143,20 +143,20 @@ void nl_resize_socket_buffer(struct nfct_handle *h) CONFIG(netlink_buffer_size)); } -int nl_dump_conntrack_table(void) +int nl_dump_conntrack_table(struct nfct_handle *h) { - return nfct_query(STATE(dump), NFCT_Q_DUMP, &CONFIG(family)); + return nfct_query(h, NFCT_Q_DUMP, &CONFIG(family)); } -int nl_flush_conntrack_table(void) +int nl_flush_conntrack_table(struct nfct_handle *h) { - return nfct_query(STATE(request), NFCT_Q_FLUSH, &CONFIG(family)); + return nfct_query(h, NFCT_Q_FLUSH, &CONFIG(family)); } -int nl_overrun_request_resync(void) +int nl_overrun_request_resync(struct nfct_handle *h) { int family = CONFIG(family); - return nfct_send(STATE(overrun), NFCT_Q_DUMP, &family); + return nfct_send(h, NFCT_Q_DUMP, &family); } static int @@ -178,18 +178,18 @@ __nl_get_conntrack(struct nfct_handle *h, const struct nf_conntrack *ct) return 1; } -int nl_exist_conntrack(const struct nf_conntrack *ct) +int nl_exist_conntrack(struct nfct_handle *h, const struct nf_conntrack *ct) { - return __nl_get_conntrack(STATE(request), ct); + return __nl_get_conntrack(h, ct); } /* get the conntrack and update the cache */ -int nl_get_conntrack(const struct nf_conntrack *ct) +int nl_get_conntrack(struct nfct_handle *h, const struct nf_conntrack *ct) { - return __nl_get_conntrack(STATE(dump), ct); + return __nl_get_conntrack(h, ct); } -int nl_create_conntrack(const struct nf_conntrack *orig) +int nl_create_conntrack(struct nfct_handle *h, const struct nf_conntrack *orig) { int ret; uint8_t flags; @@ -217,13 +217,13 @@ int nl_create_conntrack(const struct nf_conntrack *orig) nfct_set_attr_u8(ct, ATTR_TCP_FLAGS_REPL, flags); nfct_set_attr_u8(ct, ATTR_TCP_MASK_REPL, flags); - ret = nfct_query(STATE(dump), NFCT_Q_CREATE, ct); + ret = nfct_query(h, NFCT_Q_CREATE, ct); nfct_destroy(ct); return ret; } -int nl_update_conntrack(const struct nf_conntrack *orig) +int nl_update_conntrack(struct nfct_handle *h, const struct nf_conntrack *orig) { int ret; uint8_t flags; @@ -271,13 +271,13 @@ int nl_update_conntrack(const struct nf_conntrack *orig) nfct_set_attr_u8(ct, ATTR_TCP_FLAGS_REPL, flags); nfct_set_attr_u8(ct, ATTR_TCP_MASK_REPL, flags); - ret = nfct_query(STATE(dump), NFCT_Q_UPDATE, ct); + ret = nfct_query(h, NFCT_Q_UPDATE, ct); nfct_destroy(ct); return ret; } -int nl_destroy_conntrack(const struct nf_conntrack *ct) +int nl_destroy_conntrack(struct nfct_handle *h, const struct nf_conntrack *ct) { - return nfct_query(STATE(dump), NFCT_Q_DESTROY, ct); + return nfct_query(h, NFCT_Q_DESTROY, ct); } diff --git a/src/run.c b/src/run.c index 8158f10..ee985f4 100644 --- a/src/run.c +++ b/src/run.c @@ -111,11 +111,11 @@ void local_handler(int fd, void *data) switch(type) { case FLUSH_MASTER: dlog(LOG_NOTICE, "flushing kernel conntrack table"); - nl_flush_conntrack_table(); + nl_flush_conntrack_table(STATE(request)); return; case RESYNC_MASTER: dlog(LOG_NOTICE, "resync with master table"); - nl_dump_conntrack_table(); + nl_dump_conntrack_table(STATE(dump)); return; } @@ -125,7 +125,7 @@ void local_handler(int fd, void *data) static void do_overrun_alarm(struct alarm_block *a, void *data) { - nl_overrun_request_resync(); + nl_overrun_request_resync(STATE(overrun)); add_alarm(&STATE(overrun_alarm), 2, 0); } @@ -218,7 +218,7 @@ init(void) } nfct_callback_register(STATE(dump), NFCT_T_ALL, dump_handler, NULL); - if (nl_dump_conntrack_table() == -1) { + if (nl_dump_conntrack_table(STATE(dump)) == -1) { dlog(LOG_ERR, "can't get kernel conntrack table"); return -1; } @@ -321,7 +321,7 @@ static void __run(struct timeval *next_alarm) * size and resync with master conntrack table. */ nl_resize_socket_buffer(STATE(event)); - nl_overrun_request_resync(); + nl_overrun_request_resync(STATE(overrun)); add_alarm(&STATE(overrun_alarm), 2, 0); break; case ENOENT: -- cgit v1.2.3 From 9369fe5370341f72c15de8d72917d014a6c7e460 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 11 Dec 2008 18:35:04 +0100 Subject: cache_iterators: use a cloned object while resetting timers This patch uses a clone object that includes the original tuple and the new timer to be set. This fixes EINVAL and EBUSY errors reporting while trying to update the timer of some conntrack entries. Signed-off-by: Pablo Neira Ayuso --- src/cache_iterators.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/cache_iterators.c b/src/cache_iterators.c index 661528f..12ffcff 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -231,8 +231,15 @@ static int do_reset_timers(void *data1, void *data2) struct nfct_handle *h = data1; struct us_conntrack *u = data2; struct nf_conntrack *ct = u->ct; + char __tmp[nfct_maxsize()]; + struct nf_conntrack *tmp = (struct nf_conntrack *) (void *)__tmp; - ret = nl_get_conntrack(h, ct); + memset(__tmp, 0, sizeof(__tmp)); + + /* use the original tuple to check if it is there */ + nfct_copy(tmp, ct, NFCT_CP_ORIG); + + ret = nl_get_conntrack(h, tmp); switch (ret) { case -1: /* the kernel table is not in sync with internal cache */ @@ -240,14 +247,15 @@ static int do_reset_timers(void *data1, void *data2) dlog_ct(STATE(log), ct, NFCT_O_PLAIN); break; case 1: + /* use the object that contain the current timer */ current_timeout = nfct_get_attr_u32(ct, ATTR_TIMEOUT); /* already about to die, do not touch it */ if (current_timeout < CONFIG(purge_timeout)) break; - nfct_set_attr_u32(ct, ATTR_TIMEOUT, CONFIG(purge_timeout)); + nfct_set_attr_u32(tmp, ATTR_TIMEOUT, CONFIG(purge_timeout)); - if (nl_update_conntrack(h, ct) == -1) { + if (nl_update_conntrack(h, tmp) == -1) { if (errno == ETIME || errno == ENOENT) break; dlog(LOG_ERR, "reset-timers-upd: %s", strerror(errno)); -- cgit v1.2.3 From cda212571533762c525df18fdcf361a93a1a2c31 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 11 Dec 2008 19:58:55 +0100 Subject: netlink: build TCP flags/mask only if this is a TCP connection This patch includes the TCP flag/mask attributes if this is a TCP connection, otherwise do not include. Signed-off-by: Pablo Neira Ayuso --- src/netlink.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/netlink.c b/src/netlink.c index 29281f4..2fabd8d 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -192,7 +192,6 @@ int nl_get_conntrack(struct nfct_handle *h, const struct nf_conntrack *ct) int nl_create_conntrack(struct nfct_handle *h, const struct nf_conntrack *orig) { int ret; - uint8_t flags; struct nf_conntrack *ct; ct = nfct_clone(orig); @@ -211,11 +210,14 @@ int nl_create_conntrack(struct nfct_handle *h, const struct nf_conntrack *orig) /* * TCP flags to overpass window tracking for recovered connections */ - flags = IP_CT_TCP_FLAG_BE_LIBERAL | IP_CT_TCP_FLAG_SACK_PERM; - nfct_set_attr_u8(ct, ATTR_TCP_FLAGS_ORIG, flags); - nfct_set_attr_u8(ct, ATTR_TCP_MASK_ORIG, flags); - nfct_set_attr_u8(ct, ATTR_TCP_FLAGS_REPL, flags); - nfct_set_attr_u8(ct, ATTR_TCP_MASK_REPL, flags); + if (nfct_attr_is_set(ct, ATTR_TCP_STATE)) { + uint8_t flags = IP_CT_TCP_FLAG_BE_LIBERAL | + IP_CT_TCP_FLAG_SACK_PERM; + nfct_set_attr_u8(ct, ATTR_TCP_FLAGS_ORIG, flags); + nfct_set_attr_u8(ct, ATTR_TCP_MASK_ORIG, flags); + nfct_set_attr_u8(ct, ATTR_TCP_FLAGS_REPL, flags); + nfct_set_attr_u8(ct, ATTR_TCP_MASK_REPL, flags); + } ret = nfct_query(h, NFCT_Q_CREATE, ct); nfct_destroy(ct); -- cgit v1.2.3 From 785b627d0aa06a96d500d32f20c2d6f590b7a55b Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 11 Dec 2008 20:04:44 +0100 Subject: netlink: conditional build of TCP flags/mask for updates This patch includes the TCP flag/mask attributes in update messages if this is a TCP connection. Signed-off-by: Pablo Neira Ayuso --- src/netlink.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/netlink.c b/src/netlink.c index 2fabd8d..8ba4fb7 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -228,7 +228,6 @@ int nl_create_conntrack(struct nfct_handle *h, const struct nf_conntrack *orig) int nl_update_conntrack(struct nfct_handle *h, const struct nf_conntrack *orig) { int ret; - uint8_t flags; struct nf_conntrack *ct; ct = nfct_clone(orig); @@ -267,11 +266,14 @@ int nl_update_conntrack(struct nfct_handle *h, const struct nf_conntrack *orig) /* * TCP flags to overpass window tracking for recovered connections */ - flags = IP_CT_TCP_FLAG_BE_LIBERAL | IP_CT_TCP_FLAG_SACK_PERM; - nfct_set_attr_u8(ct, ATTR_TCP_FLAGS_ORIG, flags); - nfct_set_attr_u8(ct, ATTR_TCP_MASK_ORIG, flags); - nfct_set_attr_u8(ct, ATTR_TCP_FLAGS_REPL, flags); - nfct_set_attr_u8(ct, ATTR_TCP_MASK_REPL, flags); + if (nfct_attr_is_set(ct, ATTR_TCP_STATE)) { + uint8_t flags = IP_CT_TCP_FLAG_BE_LIBERAL | + IP_CT_TCP_FLAG_SACK_PERM; + nfct_set_attr_u8(ct, ATTR_TCP_FLAGS_ORIG, flags); + nfct_set_attr_u8(ct, ATTR_TCP_MASK_ORIG, flags); + nfct_set_attr_u8(ct, ATTR_TCP_FLAGS_REPL, flags); + nfct_set_attr_u8(ct, ATTR_TCP_MASK_REPL, flags); + } ret = nfct_query(h, NFCT_Q_UPDATE, ct); nfct_destroy(ct); -- cgit v1.2.3 From 9f937ba186c8f458f7cd0153a2b1e21ebf5264e5 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 11 Dec 2008 20:19:33 +0100 Subject: netlink: do not build the reply tuple in update messages We do not need to include the reply tuple in the update messages. Signed-off-by: Pablo Neira Ayuso --- src/netlink.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'src') diff --git a/src/netlink.c b/src/netlink.c index 8ba4fb7..8930e39 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -261,8 +261,6 @@ int nl_update_conntrack(struct nfct_handle *h, const struct nf_conntrack *orig) nfct_attr_unset(ct, ATTR_MASTER_PORT_DST); } - nfct_setobjopt(ct, NFCT_SOPT_SETUP_REPLY); - /* * TCP flags to overpass window tracking for recovered connections */ -- cgit v1.2.3 From 8d6efef0daed05925bf9b13c21948afa651482a5 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 13 Dec 2008 16:15:18 +0100 Subject: network: use NET_T_* instead of NFCT_Q_* This patch replaces the use of NFCT_Q_* in the message type by specific network message type NET_T_*. The query types are reserved for libnetfilter_conntrack operations. Signed-off-by: Pablo Neira Ayuso --- include/network.h | 7 +++++++ src/sync-alarm.c | 2 +- src/sync-ftfw.c | 10 +++++----- src/sync-mode.c | 16 ++++++++-------- src/sync-notrack.c | 2 +- 5 files changed, 22 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/include/network.h b/include/network.h index 9098e5c..b6722bd 100644 --- a/include/network.h +++ b/include/network.h @@ -17,6 +17,13 @@ struct nethdr { }; #define NETHDR_SIZ nethdr_align(sizeof(struct nethdr)) +enum nethdr_type { + NET_T_STATE_NEW = 0, + NET_T_STATE_UPD, + NET_T_STATE_DEL, + NET_T_STATE_MAX = NET_T_STATE_DEL, +}; + int nethdr_align(int len); int nethdr_size(int len); void nethdr_set(struct nethdr *net, int type); diff --git a/src/sync-alarm.c b/src/sync-alarm.c index fe3d9af..d871b75 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -38,7 +38,7 @@ static void refresher(struct alarm_block *a, void *data) random() % CONFIG(refresh) + 1, ((random() % 5 + 1) * 200000) - 1); - net = BUILD_NETMSG(u->ct, NFCT_Q_UPDATE); + net = BUILD_NETMSG(u->ct, NET_T_STATE_UPD); mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); } diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index a4895d4..05475ab 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -454,9 +454,9 @@ static void ftfw_send(struct nethdr *net, struct us_conntrack *u) struct cache_ftfw *cn; switch(net->type) { - case NFCT_Q_CREATE: - case NFCT_Q_UPDATE: - case NFCT_Q_DESTROY: + case NET_T_STATE_NEW: + case NET_T_STATE_UPD: + case NET_T_STATE_DEL: cn = (struct cache_ftfw *) cache_get_extra(STATE_SYNC(internal), u); @@ -537,9 +537,9 @@ static void ftfw_run(void) u = cache_get_conntrack(STATE_SYNC(internal), cn); if (alarm_pending(&u->alarm)) - tx_list_xmit(&cn->tx_list, u, NFCT_Q_DESTROY); + tx_list_xmit(&cn->tx_list, u, NET_T_STATE_DEL); else - tx_list_xmit(&cn->tx_list, u, NFCT_Q_UPDATE); + tx_list_xmit(&cn->tx_list, u, NET_T_STATE_UPD); } /* reset alive alarm */ diff --git a/src/sync-mode.c b/src/sync-mode.c index cfed7f4..d5355a7 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -68,7 +68,7 @@ static void do_mcast_handler_step(struct nethdr *net, size_t remain) } switch(net->type) { - case NFCT_Q_CREATE: + case NET_T_STATE_NEW: retry: if ((u = cache_add(STATE_SYNC(external), ct))) { debug_ct(u->ct, "external new"); @@ -85,13 +85,13 @@ retry: debug_ct(ct, "can't add"); } break; - case NFCT_Q_UPDATE: + case NET_T_STATE_UPD: if ((u = cache_update_force(STATE_SYNC(external), ct))) { debug_ct(u->ct, "external update"); } else debug_ct(ct, "can't update"); break; - case NFCT_Q_DESTROY: + case NET_T_STATE_DEL: if (cache_del(STATE_SYNC(external), ct)) debug_ct(ct, "external destroy"); else @@ -415,7 +415,7 @@ static int purge_step(void *data1, void *data2) ret = nfct_query(h, NFCT_Q_GET, u->ct); if (ret == -1 && errno == ENOENT) { debug_ct(u->ct, "overrun purge resync"); - mcast_send_sync(u, NFCT_Q_DESTROY); + mcast_send_sync(u, NET_T_STATE_DEL); __cache_del_timer(STATE_SYNC(internal), u, CONFIG(del_timeout)); } @@ -448,7 +448,7 @@ static int overrun_sync(enum nf_conntrack_msg_type type, if (!cache_test(STATE_SYNC(internal), ct)) { if ((u = cache_update_force(STATE_SYNC(internal), ct))) { debug_ct(u->ct, "overrun resync"); - mcast_send_sync(u, NFCT_Q_UPDATE); + mcast_send_sync(u, NET_T_STATE_UPD); } } @@ -466,7 +466,7 @@ static void event_new_sync(struct nf_conntrack *ct) nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); retry: if ((u = cache_add(STATE_SYNC(internal), ct))) { - mcast_send_sync(u, NFCT_Q_CREATE); + mcast_send_sync(u, NET_T_STATE_NEW); debug_ct(u->ct, "internal new"); } else { if (errno == EEXIST) { @@ -489,7 +489,7 @@ static void event_update_sync(struct nf_conntrack *ct) return; } debug_ct(u->ct, "internal update"); - mcast_send_sync(u, NFCT_Q_UPDATE); + mcast_send_sync(u, NET_T_STATE_UPD); } static int event_destroy_sync(struct nf_conntrack *ct) @@ -502,7 +502,7 @@ static int event_destroy_sync(struct nf_conntrack *ct) return 0; } - mcast_send_sync(u, NFCT_Q_DESTROY); + mcast_send_sync(u, NET_T_STATE_DEL); __cache_del_timer(STATE_SYNC(internal), u, CONFIG(del_timeout)); debug_ct(ct, "internal destroy"); return 1; diff --git a/src/sync-notrack.c b/src/sync-notrack.c index fdb0c43..8e6601a 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -188,7 +188,7 @@ static void notrack_run(void) struct us_conntrack *u; u = cache_get_conntrack(STATE_SYNC(internal), cn); - tx_list_xmit(&cn->tx_list, u, NFCT_Q_UPDATE); + tx_list_xmit(&cn->tx_list, u, NET_T_STATE_UPD); } } -- cgit v1.2.3 From b442b832971f25ad573c6765bcf63640b59342a3 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 13 Dec 2008 16:17:38 +0100 Subject: ftfw: do not check for data messages in tx_queue_xmit This patch removes a IS_DATA(net) in tx_queue_xmit which is not possible to happen anymore since there are no chances to have data in the transmission queue (instead it is all in the transmission list). Signed-off-by: Pablo Neira Ayuso --- src/sync-ftfw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 05475ab..1f445e2 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -499,7 +499,7 @@ static int tx_queue_xmit(void *data1, const void *data2) mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); HDR_NETWORK2HOST(net); - if (IS_DATA(net) || IS_ACK(net) || IS_NACK(net)) + if (IS_ACK(net) || IS_NACK(net)) queue_add(rs_queue, net, net->len); queue_del(tx_queue, net); -- cgit v1.2.3 From 3de8d91c1fa7cadf68108c0c9c03193ac5e82a73 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 13 Dec 2008 16:50:50 +0100 Subject: ftfw: resync messages can be retransmitted This patch includes resync messages in the tx queue. Thus, if a resync message gets lost, it is resent. Signed-off-by: Pablo Neira Ayuso --- src/sync-ftfw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 1f445e2..749ccac 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -499,7 +499,7 @@ static int tx_queue_xmit(void *data1, const void *data2) mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); HDR_NETWORK2HOST(net); - if (IS_ACK(net) || IS_NACK(net)) + if (IS_ACK(net) || IS_NACK(net) || IS_RESYNC(net)) queue_add(rs_queue, net, net->len); queue_del(tx_queue, net); -- cgit v1.2.3 From 74455dae1d095178b09ea3f1b1e8b005076e7a94 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 13 Dec 2008 17:24:27 +0100 Subject: network: do more strict message type checking This patch adds more strict checking in the message type. We add a new message type NET_T_CTL for control messages. Signed-off-by: Pablo Neira Ayuso --- include/network.h | 12 +++++++----- src/network.c | 2 +- src/sync-ftfw.c | 1 + src/sync-notrack.c | 1 + 4 files changed, 10 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/include/network.h b/include/network.h index b6722bd..f9756db 100644 --- a/include/network.h +++ b/include/network.h @@ -22,6 +22,7 @@ enum nethdr_type { NET_T_STATE_UPD, NET_T_STATE_DEL, NET_T_STATE_MAX = NET_T_STATE_DEL, + NET_T_CTL = 10, }; int nethdr_align(int len); @@ -95,11 +96,12 @@ void mcast_buffered_destroy(void); int mcast_buffered_send_netmsg(struct mcast_sock *m, const struct nethdr *net); ssize_t mcast_buffered_pending_netmsg(struct mcast_sock *m); -#define IS_DATA(x) ((x->flags & ~(NET_F_HELLO | NET_F_HELLO_BACK)) == 0) -#define IS_ACK(x) (x->flags & NET_F_ACK) -#define IS_NACK(x) (x->flags & NET_F_NACK) -#define IS_RESYNC(x) (x->flags & NET_F_RESYNC) -#define IS_ALIVE(x) (x->flags & NET_F_ALIVE) +#define IS_DATA(x) (x->type <= NET_T_STATE_MAX && \ + (x->flags & ~(NET_F_HELLO | NET_F_HELLO_BACK)) == 0) +#define IS_ACK(x) (x->type == NET_T_CTL && x->flags & NET_F_ACK) +#define IS_NACK(x) (x->type == NET_T_CTL && x->flags & NET_F_NACK) +#define IS_RESYNC(x) (x->type == NET_T_CTL && x->flags & NET_F_RESYNC) +#define IS_ALIVE(x) (x->type == NET_T_CTL && x->flags & NET_F_ALIVE) #define IS_CTL(x) IS_ACK(x) || IS_NACK(x) || IS_RESYNC(x) || IS_ALIVE(x) #define IS_HELLO(x) (x->flags & NET_F_HELLO) #define IS_HELLO_BACK(x)(x->flags & NET_F_HELLO_BACK) diff --git a/src/network.c b/src/network.c index 34992ec..98df5ea 100644 --- a/src/network.c +++ b/src/network.c @@ -58,7 +58,7 @@ void nethdr_set(struct nethdr *net, int type) void nethdr_set_ack(struct nethdr *net) { - __nethdr_set(net, NETHDR_ACK_SIZ, 0); + __nethdr_set(net, NETHDR_ACK_SIZ, NET_T_CTL); } static size_t tx_buflenmax; diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 749ccac..014cebd 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -97,6 +97,7 @@ static struct cache_extra cache_ftfw_extra = { static void tx_queue_add_ctlmsg(uint32_t flags, uint32_t from, uint32_t to) { struct nethdr_ack ack = { + .type = NET_T_CTL, .flags = flags, .from = from, .to = to, diff --git a/src/sync-notrack.c b/src/sync-notrack.c index 8e6601a..700e272 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -61,6 +61,7 @@ static struct cache_extra cache_notrack_extra = { static void tx_queue_add_ctlmsg(uint32_t flags, uint32_t from, uint32_t to) { struct nethdr_ack ack = { + .type = NET_T_CTL, .flags = flags, .from = from, .to = to, -- cgit v1.2.3 From 08f59121eb907802d490601f5e54dcd0fbc1d695 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 13 Dec 2008 17:24:47 +0100 Subject: ftfw: shrink alive message size This patch reduces the size of alive messages by removing the "from" and "to" fields which are not of any help. This patch also removes the IS_CTL() macro since it does not return true for the control messages anymore but only for IS_ACK(), IS_NACK() and IS_RESYNC(). Signed-off-by: Pablo Neira Ayuso --- include/network.h | 6 +++--- src/network.c | 5 +++++ src/sync-ftfw.c | 36 ++++++++++++++++++++++++++++++++++-- src/sync-mode.c | 2 +- 4 files changed, 43 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/include/network.h b/include/network.h index f9756db..40bb2b2 100644 --- a/include/network.h +++ b/include/network.h @@ -29,6 +29,7 @@ int nethdr_align(int len); int nethdr_size(int len); void nethdr_set(struct nethdr *net, int type); void nethdr_set_ack(struct nethdr *net); +void nethdr_set_ctl(struct nethdr *net); #define NETHDR_DATA(x) \ (struct netattr *)(((char *)x) + NETHDR_SIZ) @@ -102,7 +103,6 @@ ssize_t mcast_buffered_pending_netmsg(struct mcast_sock *m); #define IS_NACK(x) (x->type == NET_T_CTL && x->flags & NET_F_NACK) #define IS_RESYNC(x) (x->type == NET_T_CTL && x->flags & NET_F_RESYNC) #define IS_ALIVE(x) (x->type == NET_T_CTL && x->flags & NET_F_ALIVE) -#define IS_CTL(x) IS_ACK(x) || IS_NACK(x) || IS_RESYNC(x) || IS_ALIVE(x) #define IS_HELLO(x) (x->flags & NET_F_HELLO) #define IS_HELLO_BACK(x)(x->flags & NET_F_HELLO_BACK) @@ -110,7 +110,7 @@ ssize_t mcast_buffered_pending_netmsg(struct mcast_sock *m); ({ \ x->len = ntohs(x->len); \ x->seq = ntohl(x->seq); \ - if (IS_CTL(x)) { \ + if (IS_ACK(x) || IS_NACK(x) || IS_RESYNC(x)) { \ struct nethdr_ack *__ack = (struct nethdr_ack *) x; \ __ack->from = ntohl(__ack->from); \ __ack->to = ntohl(__ack->to); \ @@ -119,7 +119,7 @@ ssize_t mcast_buffered_pending_netmsg(struct mcast_sock *m); #define HDR_HOST2NETWORK(x) \ ({ \ - if (IS_CTL(x)) { \ + if (IS_ACK(x) || IS_NACK(x) || IS_RESYNC(x)) { \ struct nethdr_ack *__ack = (struct nethdr_ack *) x; \ __ack->from = htonl(__ack->from); \ __ack->to = htonl(__ack->to); \ diff --git a/src/network.c b/src/network.c index 98df5ea..090dec8 100644 --- a/src/network.c +++ b/src/network.c @@ -61,6 +61,11 @@ void nethdr_set_ack(struct nethdr *net) __nethdr_set(net, NETHDR_ACK_SIZ, NET_T_CTL); } +void nethdr_set_ctl(struct nethdr *net) +{ + __nethdr_set(net, NETHDR_SIZ, NET_T_CTL); +} + static size_t tx_buflenmax; static size_t tx_buflen = 0; static char *tx_buf; diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 014cebd..4758710 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -121,6 +121,31 @@ static void tx_queue_add_ctlmsg(uint32_t flags, uint32_t from, uint32_t to) write_evfd(STATE_SYNC(evfd)); } +static void tx_queue_add_ctlmsg2(uint32_t flags) +{ + struct nethdr ctl = { + .type = NET_T_CTL, + .flags = flags, + }; + + switch(hello_state) { + case HELLO_INIT: + hello_state = HELLO_SAY; + /* fall through */ + case HELLO_SAY: + ctl.flags |= NET_F_HELLO; + break; + } + + if (say_hello_back) { + ctl.flags |= NET_F_HELLO_BACK; + say_hello_back = 0; + } + + queue_add(tx_queue, &ctl, NETHDR_SIZ); + write_evfd(STATE_SYNC(evfd)); +} + /* this function is called from the alarm framework */ static void do_alive_alarm(struct alarm_block *a, void *data) { @@ -131,7 +156,7 @@ static void do_alive_alarm(struct alarm_block *a, void *data) STATE_SYNC(last_seq_recv)); ack_from_set = 0; } else - tx_queue_add_ctlmsg(NET_F_ALIVE, 0, 0); + tx_queue_add_ctlmsg2(NET_F_ALIVE); } static int ftfw_init(void) @@ -491,7 +516,14 @@ static int tx_queue_xmit(void *data1, const void *data2) { struct nethdr *net = data1; - nethdr_set_ack(net); + if (IS_ACK(net) || IS_NACK(net) || IS_RESYNC(net)) { + nethdr_set_ack(net); + } else if (IS_ALIVE(net)) { + nethdr_set_ctl(net); + } else { + dlog(LOG_ERR, "sending unknown control message?"); + return 0; + } HDR_HOST2NETWORK(net); dp("tx_queue sq: %u fl:%u len:%u\n", diff --git a/src/sync-mode.c b/src/sync-mode.c index d5355a7..b2b78ad 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -131,7 +131,7 @@ static void mcast_handler(void) break; } - if (IS_CTL(net)) { + if (IS_ACK(net) || IS_NACK(net) || IS_RESYNC(net)) { if (remain < NETHDR_ACK_SIZ) { STATE(malformed)++; dlog(LOG_WARNING, "no room for ctl message"); -- cgit v1.2.3 From aa36f86194a51c776810ced5c3a6dcead30243fa Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 13 Dec 2008 19:45:53 +0100 Subject: sync-mode: check if message type is >= NET_T_STATE_MAX before parsing This patch adds a message-type checking before we parse the message. Thus, we skip the parsing of messages with bad types. Signed-off-by: Pablo Neira Ayuso --- src/sync-mode.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src') diff --git a/src/sync-mode.c b/src/sync-mode.c index b2b78ad..6aad8f7 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -59,6 +59,11 @@ static void do_mcast_handler_step(struct nethdr *net, size_t remain) break; } + if (net->type > NET_T_STATE_MAX) { + STATE(malformed)++; + dlog(LOG_ERR, "bad state message type"); + return; + } memset(ct, 0, sizeof(__ct)); if (parse_payload(ct, net, remain) == -1) { -- cgit v1.2.3 From 4e9cccfa0071ff51b489629bf2d69eefe6196ded Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 17 Dec 2008 12:42:00 +0100 Subject: src: cleanup, rename hashtable_test() by hashtable_find() This patch renames the function hashtable_test() by hashtable_find() which is a better name IMO to describe this function. Signed-off-by: Pablo Neira Ayuso --- include/hash.h | 2 +- src/cache.c | 8 ++++---- src/filter.c | 8 ++++---- src/hash.c | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/include/hash.h b/include/hash.h index caad412..d260f65 100644 --- a/include/hash.h +++ b/include/hash.h @@ -38,7 +38,7 @@ hashtable_create(int hashsize, int limit, int datasize, void hashtable_destroy(struct hashtable *h); void *hashtable_add(struct hashtable *table, void *data); -void *hashtable_test(struct hashtable *table, const void *data); +void *hashtable_find(struct hashtable *table, const void *data); int hashtable_del(struct hashtable *table, void *data); int hashtable_flush(struct hashtable *table); int hashtable_iterate(struct hashtable *table, void *data, diff --git a/src/cache.c b/src/cache.c index 1d39fd5..c87aafa 100644 --- a/src/cache.c +++ b/src/cache.c @@ -254,7 +254,7 @@ static struct us_conntrack *__update(struct cache *c, struct nf_conntrack *ct) u->ct = ct; - u = (struct us_conntrack *) hashtable_test(c->h, u); + u = (struct us_conntrack *) hashtable_find(c->h, u); if (u) { __cache_update(c, u, ct); return u; @@ -341,7 +341,7 @@ int cache_test(struct cache *c, struct nf_conntrack *ct) u->ct = ct; - ret = hashtable_test(c->h, u); + ret = hashtable_find(c->h, u); return ret != NULL; } @@ -354,7 +354,7 @@ int cache_del(struct cache *c, struct nf_conntrack *ct) u->ct = ct; - u = (struct us_conntrack *) hashtable_test(c->h, u); + u = (struct us_conntrack *) hashtable_find(c->h, u); if (u) { __cache_del(c, u); return 1; @@ -401,7 +401,7 @@ struct us_conntrack *cache_find(struct cache *c, struct nf_conntrack *ct) u->ct = ct; - return ((struct us_conntrack *) hashtable_test(c->h, u)); + return ((struct us_conntrack *) hashtable_find(c->h, u)); } struct us_conntrack *cache_get_conntrack(struct cache *c, void *data) diff --git a/src/filter.c b/src/filter.c index 5a8b5d8..4e24fb5 100644 --- a/src/filter.c +++ b/src/filter.c @@ -221,15 +221,15 @@ static inline int __ct_filter_test_ipv4(struct ct_filter *f, struct nf_conntrack *ct) { /* we only use the real source and destination address */ - return (hashtable_test(f->h, nfct_get_attr(ct, ATTR_ORIG_IPV4_SRC)) || - hashtable_test(f->h, nfct_get_attr(ct, ATTR_REPL_IPV4_SRC))); + return (hashtable_find(f->h, nfct_get_attr(ct, ATTR_ORIG_IPV4_SRC)) || + hashtable_find(f->h, nfct_get_attr(ct, ATTR_REPL_IPV4_SRC))); } static inline int __ct_filter_test_ipv6(struct ct_filter *f, struct nf_conntrack *ct) { - return (hashtable_test(f->h6, nfct_get_attr(ct, ATTR_ORIG_IPV6_SRC)) || - hashtable_test(f->h6, nfct_get_attr(ct, ATTR_REPL_IPV6_SRC))); + return (hashtable_find(f->h6, nfct_get_attr(ct, ATTR_ORIG_IPV6_SRC)) || + hashtable_find(f->h6, nfct_get_attr(ct, ATTR_REPL_IPV6_SRC))); } static int diff --git a/src/hash.c b/src/hash.c index cf64df4..eb099dc 100644 --- a/src/hash.c +++ b/src/hash.c @@ -113,7 +113,7 @@ void *hashtable_add(struct hashtable *table, void *data) return n->data; } -void *hashtable_test(struct hashtable *table, const void *data) +void *hashtable_find(struct hashtable *table, const void *data) { struct slist_head *e; uint32_t id; -- cgit v1.2.3 From 7a7742b5dfe89caefa62a79f12dc0be971057d45 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 17 Dec 2008 12:49:48 +0100 Subject: cache: cleanup, rename __del2() by __del() This patch renames __del2() by __del(). The name of this function is a reminiscent of a removed __del() function time ago. Signed-off-by: Pablo Neira Ayuso --- src/cache.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/cache.c b/src/cache.c index c87aafa..40c7b1d 100644 --- a/src/cache.c +++ b/src/cache.c @@ -276,7 +276,7 @@ struct us_conntrack *cache_update(struct cache *c, struct nf_conntrack *ct) return NULL; } -static void __del2(struct cache *c, struct us_conntrack *u) +static void __del(struct cache *c, struct us_conntrack *u) { unsigned i; char *data = u->data; @@ -306,7 +306,7 @@ static void __cache_del(struct cache *c, struct us_conntrack *u) c->active--; } del_alarm(&u->alarm); - __del2(c, u); + __del(c, u); } struct us_conntrack *cache_update_force(struct cache *c, @@ -368,7 +368,7 @@ static void __del_timeout(struct alarm_block *a, void *data) { struct us_conntrack *u = (struct us_conntrack *) data; - __del2(u->cache, u); + __del(u->cache, u); } int -- cgit v1.2.3 From 2d4cd609f22dc156b5b6e2a5db2d3d11bdb8163d Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 17 Dec 2008 18:35:21 +0100 Subject: netlink: log report initial netlink event socket buffer size This patch adds an initial log message to report the initial netlink event socket buffer size. Signed-off-by: Pablo Neira Ayuso --- src/netlink.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/netlink.c b/src/netlink.c index 8930e39..4fe0498 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -53,10 +53,10 @@ struct nfct_handle *nl_init_event_handler(void) fcntl(nfct_fd(h), F_SETFL, O_NONBLOCK); /* set up socket buffer size */ - if (CONFIG(netlink_buffer_size)) - nfnl_rcvbufsiz(nfct_nfnlh(h), - CONFIG(netlink_buffer_size)); - else { + if (CONFIG(netlink_buffer_size)) { + CONFIG(netlink_buffer_size) = + nfnl_rcvbufsiz(nfct_nfnlh(h), CONFIG(netlink_buffer_size)); + } else { socklen_t socklen = sizeof(unsigned int); unsigned int read_size; @@ -67,6 +67,9 @@ struct nfct_handle *nl_init_event_handler(void) CONFIG(netlink_buffer_size) = read_size; } + dlog(LOG_NOTICE, "netlink event socket buffer size has been set " + "to %u bytes", CONFIG(netlink_buffer_size)); + /* ensure that maximum grown size is >= than maximum size */ if (CONFIG(netlink_buffer_size_max_grown) < CONFIG(netlink_buffer_size)) CONFIG(netlink_buffer_size_max_grown) = @@ -138,9 +141,8 @@ void nl_resize_socket_buffer(struct nfct_handle *h) CONFIG(netlink_buffer_size) = nfnl_rcvbufsiz(nfct_nfnlh(h), s); /* notify the sysadmin */ - dlog(LOG_NOTICE, "netlink socket buffer size " - "has been set to %u bytes", - CONFIG(netlink_buffer_size)); + dlog(LOG_NOTICE, "netlink socket buffer size has been increased " + "to %u bytes", CONFIG(netlink_buffer_size)); } int nl_dump_conntrack_table(struct nfct_handle *h) -- cgit v1.2.3 From 5147e92af9234ecac2f4d14bc0f0cb46af752040 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 17 Dec 2008 19:41:37 +0100 Subject: netlink: fix type in warning message on SocketBufferSizeMaxGrowth This patch fixes a type in a warning message. Signed-off-by: Pablo Neira Ayuso --- src/netlink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/netlink.c b/src/netlink.c index 4fe0498..e164dd7 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -132,7 +132,7 @@ void nl_resize_socket_buffer(struct nfct_handle *h) "unsynchronized replicas. Please, consider " "increasing netlink socket buffer size via " "SocketBufferSize and " - "SocketBufferSizeMaxGrown clauses in " + "SocketBufferSizeMaxGrowth clauses in " "conntrackd.conf"); s = CONFIG(netlink_buffer_size_max_grown); warned = 1; -- cgit v1.2.3 From 7b3f57d5007dd2cf4127c2c3a9a7cd0f64d5d6e9 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 21 Dec 2008 19:39:39 +0100 Subject: src: add network statistics via `-s network' This patch adds networks statistics that you can check via `conntrackd -s network'. This information is useful for trouble-shooting. This patch replaces several log messages that can be triggered in runtime. The idea behind this patch is to avoid log message flooding under errors. Signed-off-by: Pablo Neira Ayuso --- conntrackd.8 | 5 ++-- include/conntrackd.h | 18 ++++++++++-- src/main.c | 20 +++++++++++-- src/network.c | 7 +++-- src/sync-ftfw.c | 4 +-- src/sync-mode.c | 83 +++++++++++++++++++++++++++++++++++++++------------- 6 files changed, 104 insertions(+), 33 deletions(-) (limited to 'src') diff --git a/conntrackd.8 b/conntrackd.8 index 2d7b228..ab834fb 100644 --- a/conntrackd.8 +++ b/conntrackd.8 @@ -44,8 +44,9 @@ option will not flush your internal and external cache). .BI "-k " Kill the daemon .TP -.BI "-s " -Dump statistics +.BI "-s " "[|network]" +Dump statistics. If no parameter is passed, it displays the general statistics. +If "network" is passed as parameter it displays the networking statistics. .TP .BI "-R " Force a resync against the kernel connection tracking table diff --git a/include/conntrackd.h b/include/conntrackd.h index 3b5620e..7199985 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -26,6 +26,7 @@ #define DUMP_EXT_XML 25 /* dump external cache in XML */ #define RESET_TIMERS 26 /* reset kernel timers */ #define DEBUG_INFO 27 /* show debug info (if any) */ +#define STATS_NETWORK 28 /* extended network stats */ #define DEFAULT_CONFIGFILE "/etc/conntrackd/conntrackd.conf" #define DEFAULT_LOCKFILE "/var/lock/conntrackd.lock" @@ -109,7 +110,6 @@ struct ct_general_state { struct fds *fds; /* statistics */ - uint64_t malformed; uint64_t bytes[NFCT_DIR_MAX]; uint64_t packets[NFCT_DIR_MAX]; }; @@ -126,10 +126,22 @@ struct ct_sync_state { struct sync_mode *sync; /* sync mode */ + /* statistics */ + struct { + uint64_t msg_rcv_malformed; + uint32_t msg_rcv_bad_version; + uint32_t msg_rcv_bad_payload; + uint32_t msg_rcv_bad_header; + uint32_t msg_rcv_bad_type; + uint32_t msg_rcv_truncated; + uint32_t msg_rcv_bad_size; + uint32_t msg_snd_malformed; + uint64_t msg_rcv_lost; + uint64_t msg_rcv_before; + } error; + uint32_t last_seq_sent; /* last sequence number sent */ uint32_t last_seq_recv; /* last sequence number recv */ - uint64_t packets_replayed; /* number of replayed packets */ - uint64_t packets_lost; /* lost packets: sequence tracking */ }; #define STATE_STATS(x) state.stats->x diff --git a/src/main.c b/src/main.c index f811acf..022915d 100644 --- a/src/main.c +++ b/src/main.c @@ -43,7 +43,7 @@ static const char usage_client_commands[] = " -i, display content of the internal cache\n" " -e, display the content of the external cache\n" " -k, kill conntrack daemon\n" - " -s, dump statistics\n" + " -s [|network], dump statistics\n" " -R, resync with kernel conntrack table\n" " -n, request resync with other node (only FT-FW and NOTRACK modes)\n" " -x, dump cache in XML format (requires -i or -e)" @@ -155,7 +155,23 @@ int main(int argc, char *argv[]) break; case 's': set_operation_mode(&type, REQUEST, argv); - action = STATS; + /* we've got a parameter */ + if (i+1 < argc && argv[i+1][0] != '-') { + if (strncmp(argv[i+1], "network", + strlen(argv[i+1])) == 0) { + action = STATS_NETWORK; + i++; + } else { + fprintf(stderr, "ERROR: unknown " + "parameter `%s' for " + "option `-s'\n", + argv[i+1]); + exit(EXIT_FAILURE); + } + } else { + /* default to general statistics */ + action = STATS; + } break; case 'S': fprintf(stderr, "WARNING: -S option is obsolete. " diff --git a/src/network.c b/src/network.c index 090dec8..598195f 100644 --- a/src/network.c +++ b/src/network.c @@ -147,14 +147,17 @@ int mcast_track_seq(uint32_t seq, uint32_t *exp_seq) /* out of sequence: some messages got lost */ if (after(seq, STATE_SYNC(last_seq_recv)+1)) { - STATE_SYNC(packets_lost) += seq-STATE_SYNC(last_seq_recv)+1; + STATE_SYNC(error).msg_rcv_lost += + seq - STATE_SYNC(last_seq_recv) + 1; ret = SEQ_AFTER; goto out; } /* out of sequence: replayed/delayed packet? */ - if (before(seq, STATE_SYNC(last_seq_recv)+1)) + if (before(seq, STATE_SYNC(last_seq_recv)+1)) { + STATE_SYNC(error).msg_rcv_before++; ret = SEQ_BEFORE; + } out: *exp_seq = STATE_SYNC(last_seq_recv)+1; diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 4758710..44e8f2f 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -441,8 +441,6 @@ static int ftfw_recv(const struct nethdr *net) case SEQ_BEFORE: /* we don't accept delayed packets */ - dlog(LOG_WARNING, "Received seq=%u before expected seq=%u", - net->seq, exp_seq); ret = MSG_DROP; break; @@ -521,7 +519,7 @@ static int tx_queue_xmit(void *data1, const void *data2) } else if (IS_ALIVE(net)) { nethdr_set_ctl(net); } else { - dlog(LOG_ERR, "sending unknown control message?"); + STATE_SYNC(error).msg_snd_malformed++; return 0; } HDR_HOST2NETWORK(net); diff --git a/src/sync-mode.c b/src/sync-mode.c index 6aad8f7..e7b9359 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -41,8 +41,8 @@ static void do_mcast_handler_step(struct nethdr *net, size_t remain) struct us_conntrack *u; if (net->version != CONNTRACKD_PROTOCOL_VERSION) { - STATE(malformed)++; - dlog(LOG_WARNING, "wrong protocol version `%u'", net->version); + STATE_SYNC(error).msg_rcv_malformed++; + STATE_SYNC(error).msg_rcv_bad_version++; return; } @@ -53,22 +53,23 @@ static void do_mcast_handler_step(struct nethdr *net, size_t remain) case MSG_CTL: return; case MSG_BAD: - STATE(malformed)++; + STATE_SYNC(error).msg_rcv_malformed++; + STATE_SYNC(error).msg_rcv_bad_header++; return; default: break; } if (net->type > NET_T_STATE_MAX) { - STATE(malformed)++; - dlog(LOG_ERR, "bad state message type"); + STATE_SYNC(error).msg_rcv_malformed++; + STATE_SYNC(error).msg_rcv_bad_type++; return; } memset(ct, 0, sizeof(__ct)); if (parse_payload(ct, net, remain) == -1) { - STATE(malformed)++; - dlog(LOG_ERR, "parsing failed: malformed message"); + STATE_SYNC(error).msg_rcv_malformed++; + STATE_SYNC(error).msg_rcv_bad_payload++; return; } @@ -103,8 +104,8 @@ retry: debug_ct(ct, "can't destroy"); break; default: - STATE(malformed)++; - dlog(LOG_ERR, "mcast unknown query %d\n", net->type); + STATE_SYNC(error).msg_rcv_malformed++; + STATE_SYNC(error).msg_rcv_bad_type++; break; } } @@ -125,31 +126,31 @@ static void mcast_handler(void) struct nethdr *net = (struct nethdr *) ptr; if (remain < NETHDR_SIZ) { - STATE(malformed)++; - dlog(LOG_WARNING, "no room for header"); + STATE_SYNC(error).msg_rcv_malformed++; + STATE_SYNC(error).msg_rcv_truncated++; break; } if (ntohs(net->len) > remain) { - STATE(malformed)++; - dlog(LOG_WARNING, "fragmented message"); + STATE_SYNC(error).msg_rcv_malformed++; + STATE_SYNC(error).msg_rcv_bad_size++; break; } if (IS_ACK(net) || IS_NACK(net) || IS_RESYNC(net)) { if (remain < NETHDR_ACK_SIZ) { - STATE(malformed)++; - dlog(LOG_WARNING, "no room for ctl message"); + STATE_SYNC(error).msg_rcv_malformed++; + STATE_SYNC(error).msg_rcv_truncated++; } if (ntohs(net->len) < NETHDR_ACK_SIZ) { - STATE(malformed)++; - dlog(LOG_WARNING, "ctl header too small"); + STATE_SYNC(error).msg_rcv_malformed++; + STATE_SYNC(error).msg_rcv_bad_size++; } } else { if (ntohs(net->len) < NETHDR_SIZ) { - STATE(malformed)++; - dlog(LOG_WARNING, "header too small"); + STATE_SYNC(error).msg_rcv_malformed++; + STATE_SYNC(error).msg_rcv_bad_size++; } } @@ -304,8 +305,43 @@ static void dump_stats_sync(int fd) size = sprintf(buf, "multicast sequence tracking:\n" "%20llu Pckts mfrm " "%20llu Pckts lost\n\n", - (unsigned long long)STATE(malformed), - (unsigned long long)STATE_SYNC(packets_lost)); + (unsigned long long)STATE_SYNC(error).msg_rcv_malformed, + (unsigned long long)STATE_SYNC(error).msg_rcv_lost); + + send(fd, buf, size, 0); +} + +static void dump_stats_sync_extended(int fd) +{ + char buf[512]; + int size; + + size = snprintf(buf, sizeof(buf), + "network statistics:\n" + "\trecv:\n" + "\t\tMalformed messages:\t%20llu\n" + "\t\tWrong protocol version:\t%20u\n" + "\t\tMalformed header:\t%20u\n" + "\t\tMalformed payload:\t%20u\n" + "\t\tBad message type:\t%20u\n" + "\t\tTruncated message:\t%20u\n" + "\t\tBad message size:\t%20u\n" + "\tsend:\n" + "\t\tMalformed messages:\t%20u\n\n" + "sequence tracking statistics:\n" + "\trecv:\n" + "\t\tPackets lost:\t\t%20llu\n" + "\t\tPackets before:\t\t%20llu\n\n", + (unsigned long long)STATE_SYNC(error).msg_rcv_malformed, + STATE_SYNC(error).msg_rcv_bad_version, + STATE_SYNC(error).msg_rcv_bad_header, + STATE_SYNC(error).msg_rcv_bad_payload, + STATE_SYNC(error).msg_rcv_bad_type, + STATE_SYNC(error).msg_rcv_truncated, + STATE_SYNC(error).msg_rcv_bad_size, + STATE_SYNC(error).msg_snd_malformed, + (unsigned long long)STATE_SYNC(error).msg_rcv_lost, + (unsigned long long)STATE_SYNC(error).msg_rcv_before); send(fd, buf, size, 0); } @@ -377,6 +413,11 @@ static int local_handler_sync(int fd, int type, void *data) STATE_SYNC(mcast_server)); dump_stats_sync(fd); break; + case STATS_NETWORK: + dump_stats_sync_extended(fd); + mcast_dump_stats(fd, STATE_SYNC(mcast_client), + STATE_SYNC(mcast_server)); + break; default: if (STATE_SYNC(sync)->local) ret = STATE_SYNC(sync)->local(fd, type, data); -- cgit v1.2.3 From 036a0a65c6a3ba95cff48035a25e0bdba6aa0452 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 21 Dec 2008 19:47:02 +0100 Subject: src: add cache statistics via `-s cache' This patch adds cache statistics that you can check via `conntrackd -s cache'. This information is useful for trouble-shooting. This patch replaces several log messages that can be triggered in runtime. The idea behind this patch is to avoid log message flooding under errors. Signed-off-by: Pablo Neira Ayuso --- conntrackd.8 | 3 +- include/cache.h | 38 +++++++++++++--------- include/conntrackd.h | 1 + src/cache.c | 89 +++++++++++++++++++++++++++++++++++++++------------ src/cache_iterators.c | 26 +++++++-------- src/main.c | 6 +++- src/stats-mode.c | 3 ++ src/sync-mode.c | 7 ++-- 8 files changed, 119 insertions(+), 54 deletions(-) (limited to 'src') diff --git a/conntrackd.8 b/conntrackd.8 index ab834fb..7d38740 100644 --- a/conntrackd.8 +++ b/conntrackd.8 @@ -44,9 +44,10 @@ option will not flush your internal and external cache). .BI "-k " Kill the daemon .TP -.BI "-s " "[|network]" +.BI "-s " "[|network|cache]" Dump statistics. If no parameter is passed, it displays the general statistics. If "network" is passed as parameter it displays the networking statistics. +If "cache" is passed as parameter, it shows the extended cache statistics. .TP .BI "-R " Force a resync against the kernel connection tracking table diff --git a/include/cache.h b/include/cache.h index 45c3b7e..ebed70a 100644 --- a/include/cache.h +++ b/include/cache.h @@ -50,21 +50,28 @@ struct cache { unsigned int extra_offset; /* statistics */ - unsigned int active; - - unsigned int add_ok; - unsigned int del_ok; - unsigned int upd_ok; - - unsigned int add_fail; - unsigned int del_fail; - unsigned int upd_fail; - - unsigned int commit_ok; - unsigned int commit_exist; - unsigned int commit_fail; - - unsigned int flush; + struct { + uint32_t active; + + uint32_t add_ok; + uint32_t del_ok; + uint32_t upd_ok; + + uint32_t add_fail; + uint32_t del_fail; + uint32_t upd_fail; + + uint32_t add_fail_enomem; + uint32_t add_fail_enospc; + uint32_t del_fail_enoent; + uint32_t upd_fail_enoent; + + uint32_t commit_ok; + uint32_t commit_exist; + uint32_t commit_fail; + + uint32_t flush; + } stats; }; struct cache_extra { @@ -88,6 +95,7 @@ int __cache_del_timer(struct cache *c, struct us_conntrack *u, int timeout); struct us_conntrack *cache_find(struct cache *c, struct nf_conntrack *ct); int cache_test(struct cache *c, struct nf_conntrack *ct); void cache_stats(const struct cache *c, int fd); +void cache_stats_extended(const struct cache *c, int fd); struct us_conntrack *cache_get_conntrack(struct cache *, void *); void *cache_get_extra(struct cache *, void *); void cache_iterate(struct cache *c, void *data, int (*iterate)(void *data1, void *data2)); diff --git a/include/conntrackd.h b/include/conntrackd.h index 7199985..98934ce 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -27,6 +27,7 @@ #define RESET_TIMERS 26 /* reset kernel timers */ #define DEBUG_INFO 27 /* show debug info (if any) */ #define STATS_NETWORK 28 /* extended network stats */ +#define STATS_CACHE 29 /* extended cache stats */ #define DEFAULT_CONFIGFILE "/etc/conntrackd/conntrackd.conf" #define DEFAULT_LOCKFILE "/var/lock/conntrackd.lock" diff --git a/src/cache.c b/src/cache.c index 40c7b1d..5e7d738 100644 --- a/src/cache.c +++ b/src/cache.c @@ -206,7 +206,7 @@ static struct us_conntrack *__add(struct cache *c, struct nf_conntrack *ct) if (c->extra && c->extra->add) c->extra->add(u, ((char *) u) + c->extra_offset); - c->active++; + c->stats.active++; return u; } free(newct); @@ -220,11 +220,16 @@ struct us_conntrack *cache_add(struct cache *c, struct nf_conntrack *ct) u = __add(c, ct); if (u) { - c->add_ok++; + c->stats.add_ok++; return u; } - if (errno != EEXIST) - c->add_fail++; + if (errno != EEXIST) { + c->stats.add_fail++; + if (errno == ENOSPC) + c->stats.add_fail_enospc++; + if (errno == ENOMEM) + c->stats.add_fail_enomem++; + } return NULL; } @@ -268,10 +273,12 @@ struct us_conntrack *cache_update(struct cache *c, struct nf_conntrack *ct) u = __update(c, ct); if (u) { - c->upd_ok++; + c->stats.upd_ok++; return u; } - c->upd_fail++; + c->stats.upd_fail++; + if (errno == ENOENT) + c->stats.upd_fail_enoent++; return NULL; } @@ -302,8 +309,8 @@ static void __cache_del(struct cache *c, struct us_conntrack *u) * __cache_del_timer. */ if (!alarm_pending(&u->alarm)) { - c->del_ok++; - c->active--; + c->stats.del_ok++; + c->stats.active--; } del_alarm(&u->alarm); __del(c, u); @@ -317,7 +324,7 @@ struct us_conntrack *cache_update_force(struct cache *c, u = cache_find(c, ct); if (u) { if (!alarm_pending(&u->alarm)) { - c->upd_ok++; + c->stats.upd_ok++; __cache_update(c, u, ct); return u; } else { @@ -325,10 +332,15 @@ struct us_conntrack *cache_update_force(struct cache *c, } } if ((u = __add(c, ct)) != NULL) { - c->add_ok++; + c->stats.add_ok++; return u; } - c->add_fail++; + c->stats.add_fail++; + if (errno == ENOSPC) + c->stats.add_fail_enospc++; + if (errno == ENOMEM) + c->stats.add_fail_enomem++; + return NULL; } @@ -359,7 +371,9 @@ int cache_del(struct cache *c, struct nf_conntrack *ct) __cache_del(c, u); return 1; } - c->del_fail++; + c->stats.del_fail++; + if (errno == ENOENT) + c->stats.del_fail_enoent++; return 0; } @@ -386,8 +400,8 @@ __cache_del_timer(struct cache *c, struct us_conntrack *u, int timeout) * that the replication protocol does not work * properly. */ - c->del_ok++; - c->active--; + c->stats.del_ok++; + c->stats.active--; return 1; } return 0; @@ -425,13 +439,46 @@ void cache_stats(const struct cache *c, int fd) "connections updated:\t\t%12u\tfailed:\t%12u\n" "connections destroyed:\t\t%12u\tfailed:\t%12u\n\n", c->name, - c->active, - c->add_ok, - c->add_fail, - c->upd_ok, - c->upd_fail, - c->del_ok, - c->del_fail); + c->stats.active, + c->stats.add_ok, + c->stats.add_fail, + c->stats.upd_ok, + c->stats.upd_fail, + c->stats.del_ok, + c->stats.del_fail); + send(fd, buf, size, 0); +} + +void cache_stats_extended(const struct cache *c, int fd) +{ + char buf[512]; + int size; + + size = snprintf(buf, sizeof(buf), + "cache:%s\tactive connections:\t%12u\n" + "\tcreation OK:\t\t\t%12u\n" + "\tcreation failed:\t\t%12u\n" + "\t\tno memory available:\t%12u\n" + "\t\tno space left in cache:\t%12u\n" + "\tupdate OK:\t\t\t%12u\n" + "\tupdate failed:\t\t\t%12u\n" + "\t\tentry not found:\t%12u\n" + "\tdeletion created:\t\t%12u\n" + "\tdeletion failed:\t\t%12u\n" + "\t\tentry not found:\t%12u\n", + c->name, + c->stats.active, + c->stats.add_ok, + c->stats.add_fail, + c->stats.add_fail_enomem, + c->stats.add_fail_enospc, + c->stats.upd_ok, + c->stats.upd_fail, + c->stats.upd_fail_enoent, + c->stats.del_ok, + c->stats.del_fail, + c->stats.del_fail_enoent); + send(fd, buf, size, 0); } diff --git a/src/cache_iterators.c b/src/cache_iterators.c index 12ffcff..8ad9612 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -130,12 +130,12 @@ try_again: } dlog(LOG_ERR, "commit-create: %s", strerror(errno)); dlog_ct(STATE(log), ct, NFCT_O_PLAIN); - tmp->c->commit_fail++; + tmp->c->stats.commit_fail++; } else - tmp->c->commit_ok++; + tmp->c->stats.commit_ok++; break; case 1: - tmp->c->commit_exist++; + tmp->c->stats.commit_exist++; if (nl_update_conntrack(tmp->h, ct) == -1) { if (errno == ENOMEM || errno == ETIME) { if (retry) { @@ -154,14 +154,14 @@ try_again: } dlog(LOG_ERR, "commit-rm: %s", strerror(errno)); dlog_ct(STATE(log), ct, NFCT_O_PLAIN); - tmp->c->commit_fail++; + tmp->c->stats.commit_fail++; break; } dlog(LOG_ERR, "commit-update: %s", strerror(errno)); dlog_ct(STATE(log), ct, NFCT_O_PLAIN); - tmp->c->commit_fail++; + tmp->c->stats.commit_fail++; } else - tmp->c->commit_ok++; + tmp->c->stats.commit_ok++; break; } } @@ -191,9 +191,9 @@ static int do_commit_master(void *data1, void *data2) /* no need to clone, called from child process */ void cache_commit(struct cache *c) { - unsigned int commit_ok = c->commit_ok; - unsigned int commit_exist = c->commit_exist; - unsigned int commit_fail = c->commit_fail; + unsigned int commit_ok = c->stats.commit_ok; + unsigned int commit_exist = c->stats.commit_exist; + unsigned int commit_fail = c->stats.commit_fail; struct __commit_container tmp; tmp.h = nfct_open(CONNTRACK, 0); @@ -208,9 +208,9 @@ void cache_commit(struct cache *c) hashtable_iterate(c->h, &tmp, do_commit_related); /* calculate new entries committed */ - commit_ok = c->commit_ok - commit_ok; - commit_fail = c->commit_fail - commit_fail; - commit_exist = c->commit_exist - commit_exist; + commit_ok = c->stats.commit_ok - commit_ok; + commit_fail = c->stats.commit_fail - commit_fail; + commit_exist = c->stats.commit_exist - commit_exist; /* log results */ dlog(LOG_NOTICE, "Committed %u new entries", commit_ok); @@ -292,5 +292,5 @@ static int do_flush(void *data1, void *data2) void cache_flush(struct cache *c) { hashtable_iterate(c->h, c, do_flush); - c->flush++; + c->stats.flush++; } diff --git a/src/main.c b/src/main.c index 022915d..f621a2e 100644 --- a/src/main.c +++ b/src/main.c @@ -43,7 +43,7 @@ static const char usage_client_commands[] = " -i, display content of the internal cache\n" " -e, display the content of the external cache\n" " -k, kill conntrack daemon\n" - " -s [|network], dump statistics\n" + " -s [|network|cache], dump statistics\n" " -R, resync with kernel conntrack table\n" " -n, request resync with other node (only FT-FW and NOTRACK modes)\n" " -x, dump cache in XML format (requires -i or -e)" @@ -161,6 +161,10 @@ int main(int argc, char *argv[]) strlen(argv[i+1])) == 0) { action = STATS_NETWORK; i++; + } else if (strncmp(argv[i+1], "cache", + strlen(argv[i+1])) == 0) { + action = STATS_CACHE; + i++; } else { fprintf(stderr, "ERROR: unknown " "parameter `%s' for " diff --git a/src/stats-mode.c b/src/stats-mode.c index ad28008..d340b0d 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -79,6 +79,9 @@ static int local_handler_stats(int fd, int type, void *data) cache_stats(STATE_STATS(cache), fd); dump_traffic_stats(fd); break; + case STATS_CACHE: + cache_stats_extended(STATE_STATS(cache), fd); + break; default: ret = 0; break; diff --git a/src/sync-mode.c b/src/sync-mode.c index e7b9359..6779487 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -418,6 +418,10 @@ static int local_handler_sync(int fd, int type, void *data) mcast_dump_stats(fd, STATE_SYNC(mcast_client), STATE_SYNC(mcast_server)); break; + case STATS_CACHE: + cache_stats_extended(STATE_SYNC(internal), fd); + cache_stats_extended(STATE_SYNC(external), fd); + break; default: if (STATE_SYNC(sync)->local) ret = STATE_SYNC(sync)->local(fd, type, data); @@ -519,9 +523,6 @@ retry: cache_del(STATE_SYNC(internal), ct); goto retry; } - - dlog(LOG_ERR, "can't add to internal cache: " - "%s\n", strerror(errno)); debug_ct(ct, "can't add"); } } -- cgit v1.2.3 From 3641d2351ab42bef56e341ccca007331410822f2 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 21 Dec 2008 19:47:03 +0100 Subject: src: add run-time statistics via `-s runtime' This patch adds run-time statistics that you can check via `conntrackd -s runtime'. This information is useful for trouble-shooting. This patch replaces several log messages that can be triggered in runtime. The idea behind this patch is to avoid log message flooding under errors. Signed-off-by: Pablo Neira Ayuso --- conntrackd.8 | 3 +- include/conntrackd.h | 29 +++++++++++++- src/main.c | 6 ++- src/run.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++----- src/traffic_stats.c | 16 ++++---- 5 files changed, 137 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/conntrackd.8 b/conntrackd.8 index 7d38740..cd1e2bd 100644 --- a/conntrackd.8 +++ b/conntrackd.8 @@ -44,10 +44,11 @@ option will not flush your internal and external cache). .BI "-k " Kill the daemon .TP -.BI "-s " "[|network|cache]" +.BI "-s " "[|network|cache|runtime]" Dump statistics. If no parameter is passed, it displays the general statistics. If "network" is passed as parameter it displays the networking statistics. If "cache" is passed as parameter, it shows the extended cache statistics. +If "runtime" is passed as parameter, it shows the run-time statistics. .TP .BI "-R " Force a resync against the kernel connection tracking table diff --git a/include/conntrackd.h b/include/conntrackd.h index 98934ce..df36ec4 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -28,6 +28,7 @@ #define DEBUG_INFO 27 /* show debug info (if any) */ #define STATS_NETWORK 28 /* extended network stats */ #define STATS_CACHE 29 /* extended cache stats */ +#define STATS_RUNTIME 30 /* extended runtime stats */ #define DEFAULT_CONFIGFILE "/etc/conntrackd/conntrackd.conf" #define DEFAULT_LOCKFILE "/var/lock/conntrackd.lock" @@ -111,8 +112,32 @@ struct ct_general_state { struct fds *fds; /* statistics */ - uint64_t bytes[NFCT_DIR_MAX]; - uint64_t packets[NFCT_DIR_MAX]; + struct { + uint64_t bytes[NFCT_DIR_MAX]; + uint64_t packets[NFCT_DIR_MAX]; + + time_t daemon_start_time; + + uint64_t nl_events_received; + uint64_t nl_events_filtered; + uint32_t nl_events_unknown_type; + uint32_t nl_catch_event_failed; + uint32_t nl_overrun; + uint32_t nl_dump_unknown_type; + uint32_t nl_kernel_table_flush; + uint32_t nl_kernel_table_resync; + + uint32_t child_process_failed; + uint32_t child_process_error_segfault; + uint32_t child_process_error_term; + + uint32_t select_failed; + uint32_t wait_failed; + + uint32_t local_read_failed; + uint32_t local_unknown_request; + + } stats; }; #define STATE_SYNC(x) state.sync->x diff --git a/src/main.c b/src/main.c index f621a2e..ebd975b 100644 --- a/src/main.c +++ b/src/main.c @@ -43,7 +43,7 @@ static const char usage_client_commands[] = " -i, display content of the internal cache\n" " -e, display the content of the external cache\n" " -k, kill conntrack daemon\n" - " -s [|network|cache], dump statistics\n" + " -s [|network|cache|runtime], dump statistics\n" " -R, resync with kernel conntrack table\n" " -n, request resync with other node (only FT-FW and NOTRACK modes)\n" " -x, dump cache in XML format (requires -i or -e)" @@ -165,6 +165,10 @@ int main(int argc, char *argv[]) strlen(argv[i+1])) == 0) { action = STATS_CACHE; i++; + } else if (strncmp(argv[i+1], "runtime", + strlen(argv[i+1])) == 0) { + action = STATS_RUNTIME; + i++; } else { fprintf(stderr, "ERROR: unknown " "parameter `%s' for " diff --git a/src/run.c b/src/run.c index ee985f4..5b01dc7 100644 --- a/src/run.c +++ b/src/run.c @@ -32,6 +32,7 @@ #include #include #include +#include void killer(int foo) { @@ -68,7 +69,7 @@ static void child(int foo) continue; if (errno == ECHILD) break; - dlog(LOG_ERR, "wait has failed (%s)", strerror(errno)); + STATE(stats).wait_failed++; break; } if (!WIFSIGNALED(status)) @@ -78,6 +79,8 @@ static void child(int foo) case SIGSEGV: dlog(LOG_ERR, "child process (pid=%u) has aborted, " "received signal SIGSEGV (crashed)", ret); + STATE(stats).child_process_failed++; + STATE(stats).child_process_error_segfault++; break; case SIGINT: case SIGTERM: @@ -85,16 +88,87 @@ static void child(int foo) dlog(LOG_ERR, "child process (pid=%u) has aborted, " "received termination signal (%u)", ret, WTERMSIG(status)); + STATE(stats).child_process_failed++; + STATE(stats).child_process_error_term++; break; default: dlog(LOG_NOTICE, "child process (pid=%u) " "received signal (%u)", ret, WTERMSIG(status)); + STATE(stats).child_process_failed++; break; } } } +static void uptime(char *buf, size_t bufsiz) +{ + time_t tmp; + int updays, upminutes, uphours; + size_t size = 0; + + time(&tmp); + tmp = tmp - STATE(stats).daemon_start_time; + updays = (int) tmp / (60*60*24); + if (updays) { + size = snprintf(buf, bufsiz, "%d day%s ", + updays, (updays != 1) ? "s" : ""); + } + upminutes = (int) tmp / 60; + uphours = (upminutes / 60) % 24; + upminutes %= 60; + if(uphours) { + snprintf(buf + size, bufsiz, "%d h %d min", uphours, upminutes); + } else { + snprintf(buf + size, bufsiz, "%d min", upminutes); + } +} + +static void dump_stats_runtime(int fd) +{ + char buf[1024], uptime_string[512]; + int size; + + uptime(uptime_string, sizeof(uptime_string)); + size = snprintf(buf, sizeof(buf), + "daemon uptime: %s\n\n" + "netlink stats:\n" + "\tevents received:\t%20llu\n" + "\tevents filtered:\t%20llu\n" + "\tevents unknown type:\t\t%12u\n" + "\tcatch event failed:\t\t%12u\n" + "\tdump unknown type:\t\t%12u\n" + "\tnetlink overrun:\t\t%12u\n" + "\tflush kernel table:\t\t%12u\n" + "\tresync with kernel table:\t%12u\n\n" + "runtime stats:\n" + "\tchild process failed:\t\t%12u\n" + "\t\tchild process segfault:\t%12u\n" + "\t\tchild process termsig:\t%12u\n" + "\tselect failed:\t\t\t%12u\n" + "\twait failed:\t\t\t%12u\n" + "\tlocal read failed:\t\t%12u\n" + "\tlocal unknown request:\t\t%12u\n\n", + uptime_string, + (unsigned long long)STATE(stats).nl_events_received, + (unsigned long long)STATE(stats).nl_events_filtered, + STATE(stats).nl_events_unknown_type, + STATE(stats).nl_catch_event_failed, + STATE(stats).nl_dump_unknown_type, + STATE(stats).nl_overrun, + STATE(stats).nl_kernel_table_flush, + STATE(stats).nl_kernel_table_resync, + STATE(stats).child_process_failed, + STATE(stats).child_process_error_segfault, + STATE(stats).child_process_error_term, + STATE(stats).select_failed, + STATE(stats).wait_failed, + STATE(stats).local_read_failed, + STATE(stats).local_unknown_request); + + send(fd, buf, size, 0); +} + void local_handler(int fd, void *data) { int ret; @@ -102,7 +176,7 @@ void local_handler(int fd, void *data) ret = read(fd, &type, sizeof(type)); if (ret == -1) { - dlog(LOG_ERR, "can't read from unix socket"); + STATE(stats).local_read_failed++; return; } if (ret == 0) @@ -110,17 +184,22 @@ void local_handler(int fd, void *data) switch(type) { case FLUSH_MASTER: + STATE(stats).nl_kernel_table_flush++; dlog(LOG_NOTICE, "flushing kernel conntrack table"); nl_flush_conntrack_table(STATE(request)); return; case RESYNC_MASTER: + STATE(stats).nl_kernel_table_resync++; dlog(LOG_NOTICE, "resync with master table"); nl_dump_conntrack_table(STATE(dump)); return; + case STATS_RUNTIME: + dump_stats_runtime(fd); + return; } if (!STATE(mode)->local(fd, type, data)) - dlog(LOG_WARNING, "unknown local request %d", type); + STATE(stats).local_unknown_request++; } static void do_overrun_alarm(struct alarm_block *a, void *data) @@ -133,9 +212,13 @@ static int event_handler(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data) { + STATE(stats).nl_events_received++; + /* skip user-space filtering if already do it in the kernel */ - if (ct_filter_conntrack(ct, !CONFIG(filter_from_kernelspace))) + if (ct_filter_conntrack(ct, !CONFIG(filter_from_kernelspace))) { + STATE(stats).nl_events_filtered++; return NFCT_CB_STOP; + } switch(type) { case NFCT_T_NEW: @@ -149,7 +232,7 @@ static int event_handler(enum nf_conntrack_msg_type type, update_traffic_stats(ct); break; default: - dlog(LOG_WARNING, "unknown msg from ctnetlink\n"); + STATE(stats).nl_events_unknown_type++; break; } @@ -168,7 +251,7 @@ static int dump_handler(enum nf_conntrack_msg_type type, STATE(mode)->dump(ct); break; default: - dlog(LOG_WARNING, "unknown msg from ctnetlink"); + STATE(stats).nl_dump_unknown_type++; break; } return NFCT_CB_CONTINUE; @@ -281,6 +364,8 @@ init(void) if (signal(SIGCHLD, child) == SIG_ERR) return -1; + time(&STATE(stats).daemon_start_time); + dlog(LOG_NOTICE, "initialization completed"); return 0; @@ -297,7 +382,7 @@ static void __run(struct timeval *next_alarm) if (errno == EINTR) return; - dlog(LOG_WARNING, "select failed: %s", strerror(errno)); + STATE(stats).select_failed++; return; } @@ -323,6 +408,8 @@ static void __run(struct timeval *next_alarm) nl_resize_socket_buffer(STATE(event)); nl_overrun_request_resync(STATE(overrun)); add_alarm(&STATE(overrun_alarm), 2, 0); + STATE(stats).nl_catch_event_failed++; + STATE(stats).nl_overrun++; break; case ENOENT: /* @@ -334,8 +421,7 @@ static void __run(struct timeval *next_alarm) case EAGAIN: break; default: - dlog(LOG_WARNING, - "event catch says: %s", strerror(errno)); + STATE(stats).nl_catch_event_failed++; break; } } diff --git a/src/traffic_stats.c b/src/traffic_stats.c index 9e40d53..52ca09a 100644 --- a/src/traffic_stats.c +++ b/src/traffic_stats.c @@ -21,13 +21,13 @@ void update_traffic_stats(struct nf_conntrack *ct) { - STATE(bytes)[NFCT_DIR_ORIGINAL] += + STATE(stats).bytes[NFCT_DIR_ORIGINAL] += nfct_get_attr_u32(ct, ATTR_ORIG_COUNTER_BYTES); - STATE(bytes)[NFCT_DIR_REPLY] += + STATE(stats).bytes[NFCT_DIR_REPLY] += nfct_get_attr_u32(ct, ATTR_REPL_COUNTER_BYTES); - STATE(packets)[NFCT_DIR_ORIGINAL] += + STATE(stats).packets[NFCT_DIR_ORIGINAL] += nfct_get_attr_u32(ct, ATTR_ORIG_COUNTER_PACKETS); - STATE(packets)[NFCT_DIR_REPLY] += + STATE(stats).packets[NFCT_DIR_REPLY] += nfct_get_attr_u32(ct, ATTR_REPL_COUNTER_PACKETS); } @@ -35,10 +35,10 @@ void dump_traffic_stats(int fd) { char buf[512]; int size; - uint64_t bytes = STATE(bytes)[NFCT_DIR_ORIGINAL] + - STATE(bytes)[NFCT_DIR_REPLY]; - uint64_t packets = STATE(packets)[NFCT_DIR_ORIGINAL] + - STATE(packets)[NFCT_DIR_REPLY]; + uint64_t bytes = STATE(stats).bytes[NFCT_DIR_ORIGINAL] + + STATE(stats).bytes[NFCT_DIR_REPLY]; + uint64_t packets = STATE(stats).packets[NFCT_DIR_ORIGINAL] + + STATE(stats).packets[NFCT_DIR_REPLY]; size = sprintf(buf, "traffic processed:\n"); size += sprintf(buf+size, "%20llu Bytes ", (unsigned long long)bytes); -- cgit v1.2.3 From fa603abfe2ab157756969b584a223f1ed618b965 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 21 Dec 2008 19:47:04 +0100 Subject: sync-mode: remove unnecessary split lines This patch removes unnecessary split lines in several log messages. Signed-off-by: Pablo Neira Ayuso --- src/sync-mode.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/sync-mode.c b/src/sync-mode.c index 6779487..ad2e2ff 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -197,8 +197,7 @@ static int init_sync(void) STATE_SYNC(sync)->internal_cache_extra); if (!STATE_SYNC(internal)) { - dlog(LOG_ERR, "can't allocate memory for " - "the internal cache"); + dlog(LOG_ERR, "can't allocate memory for the internal cache"); return -1; } @@ -212,8 +211,7 @@ static int init_sync(void) NULL); if (!STATE_SYNC(external)) { - dlog(LOG_ERR, "can't allocate memory for the " - "external cache"); + dlog(LOG_ERR, "can't allocate memory for the external cache"); return -1; } @@ -383,8 +381,7 @@ static int local_handler_sync(int fd, int type, void *data) case COMMIT: ret = fork(); if (ret == 0) { - dlog(LOG_NOTICE, - "committing external cache"); + dlog(LOG_NOTICE, "committing external cache"); cache_commit(STATE_SYNC(external)); exit(EXIT_SUCCESS); } -- cgit v1.2.3 From fa2e890e5216be401a73e346ca93c24144b764fc Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 21 Dec 2008 19:47:04 +0100 Subject: conntrackd: fix missing \n in conntrackd -h This patch fixes a missing \n in the help message displayed with conntrackd -h. Signed-off-by: Pablo Neira Ayuso --- src/main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/main.c b/src/main.c index ebd975b..929b5c9 100644 --- a/src/main.c +++ b/src/main.c @@ -46,9 +46,9 @@ static const char usage_client_commands[] = " -s [|network|cache|runtime], dump statistics\n" " -R, resync with kernel conntrack table\n" " -n, request resync with other node (only FT-FW and NOTRACK modes)\n" - " -x, dump cache in XML format (requires -i or -e)" - " -t, reset the kernel timeout (see PurgeTimeout clause)" - " -v, show internal debugging information (if any)"; + " -x, dump cache in XML format (requires -i or -e)\n" + " -t, reset the kernel timeout (see PurgeTimeout clause)\n" + " -v, show internal debugging information (if any)\n"; static const char usage_options[] = "Options:\n" -- cgit v1.2.3 From c7243650c18ec4317a0897e9b406193854955201 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 21 Dec 2008 20:19:46 +0100 Subject: cache_iterators: display the commit time taken in the logs This patch reports to the logfile the time taken to commit the entries. The output is expressed in seconds.microseconds. Signed-off-by: Pablo Neira Ayuso --- src/cache_iterators.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src') diff --git a/src/cache_iterators.c b/src/cache_iterators.c index 8ad9612..a14f428 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -195,6 +195,7 @@ void cache_commit(struct cache *c) unsigned int commit_exist = c->stats.commit_exist; unsigned int commit_fail = c->stats.commit_fail; struct __commit_container tmp; + struct timeval commit_start, commit_stop, res; tmp.h = nfct_open(CONNTRACK, 0); if (tmp.h == NULL) { @@ -203,9 +204,12 @@ void cache_commit(struct cache *c) } tmp.c = c; + gettimeofday(&commit_start, NULL); /* commit master conntrack first, then related ones */ hashtable_iterate(c->h, &tmp, do_commit_master); hashtable_iterate(c->h, &tmp, do_commit_related); + gettimeofday(&commit_stop, NULL); + timersub(&commit_stop, &commit_start, &res); /* calculate new entries committed */ commit_ok = c->stats.commit_ok - commit_ok; @@ -222,6 +226,9 @@ void cache_commit(struct cache *c) dlog(LOG_NOTICE, "%u entries can't be " "committed", commit_fail); nfct_close(tmp.h); + + dlog(LOG_NOTICE, "commit has taken %llu.%06llu seconds", + res.tv_sec, res.tv_usec); } static int do_reset_timers(void *data1, void *data2) -- cgit v1.2.3 From f90efb777e087ed2c24af080cb033a256969e766 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 22 Dec 2008 12:45:58 +0100 Subject: cache_iterators: add total entries available in the cache to stats This patch adds the total number of entries currently living in the cache. Currently, we have two type of entries, active and inactive. The inactive ones talk about an ended connection. This is useful for trouble-shooting if we hit enospc when adding new entries. Signed-off-by: Pablo Neira Ayuso --- src/cache.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/cache.c b/src/cache.c index 5e7d738..6106d28 100644 --- a/src/cache.c +++ b/src/cache.c @@ -455,7 +455,7 @@ void cache_stats_extended(const struct cache *c, int fd) int size; size = snprintf(buf, sizeof(buf), - "cache:%s\tactive connections:\t%12u\n" + "cache:%s\tactive/total entries:\t%12u/%12u\n" "\tcreation OK:\t\t\t%12u\n" "\tcreation failed:\t\t%12u\n" "\t\tno memory available:\t%12u\n" @@ -467,7 +467,7 @@ void cache_stats_extended(const struct cache *c, int fd) "\tdeletion failed:\t\t%12u\n" "\t\tentry not found:\t%12u\n", c->name, - c->stats.active, + c->stats.active, hashtable_counter(c->h), c->stats.add_ok, c->stats.add_fail, c->stats.add_fail_enomem, -- cgit v1.2.3 From a6281c6f10110bf64e51c04a37c0fe9f9508482e Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 22 Dec 2008 13:03:55 +0100 Subject: cache: fix ENOSPC errors due to over-population of inactive entries This patch fixes a problem that can result in cache over-population with inactive entries due to mismatching in the comparison. This may result in lots of ENOSPC errors while trying to add new entries to the internal cache. We may have entries in the internal cache that with the same original tuple, but different reply tuple due to NAT port adjustment. Thus, the comparison that happens during the entry hashtable lookup fails and we add a new entry while keeping the old one. Signed-off-by: Pablo Neira Ayuso --- src/cache.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/cache.c b/src/cache.c index 6106d28..525832b 100644 --- a/src/cache.c +++ b/src/cache.c @@ -88,7 +88,7 @@ static int compare(const void *data1, const void *data2) const struct us_conntrack *u1 = data1; const struct us_conntrack *u2 = data2; - return nfct_cmp(u1->ct, u2->ct, NFCT_CMP_ORIG | NFCT_CMP_REPL); + return nfct_cmp(u1->ct, u2->ct, NFCT_CMP_ORIG); } struct cache_feature *cache_feature[CACHE_MAX_FEATURE] = { -- cgit v1.2.3 From b176d7178aa929c4644bdfd0752cf531384447c9 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 14 Jan 2009 13:50:58 +0100 Subject: filter: skip filtering by state if the event has no state info This patch fixes a bug that may result in wrong filtering of destroy events which usually don't contain the state information. In that case, skip the filtering. Signed-off-by: Pablo Neira Ayuso --- src/filter.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/filter.c b/src/filter.c index 4e24fb5..218ba0c 100644 --- a/src/filter.c +++ b/src/filter.c @@ -318,7 +318,8 @@ static int ct_filter_check(struct ct_filter *f, struct nf_conntrack *ct) if (f->logic[CT_FILTER_STATE] != -1) { ret = __ct_filter_test_state(f, ct); - if (ret ^ f->logic[CT_FILTER_STATE]) + /* ret is -1 if we don't know what to do */ + if (ret != -1 && ret ^ f->logic[CT_FILTER_STATE]) return 0; } -- cgit v1.2.3 From 7a817e883baad98069d31bc846383f18bbfca33e Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 14 Jan 2009 14:29:48 +0100 Subject: run: show current netlink buffer size in `-s runtime' This patch shows the current netlink buffer size via `-s runtime'. # conntrackd -s ru ... current buffer size (in bytes): 204800 Signed-off-by: Pablo Neira Ayuso --- src/run.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/run.c b/src/run.c index 5b01dc7..7958665 100644 --- a/src/run.c +++ b/src/run.c @@ -140,7 +140,8 @@ static void dump_stats_runtime(int fd) "\tdump unknown type:\t\t%12u\n" "\tnetlink overrun:\t\t%12u\n" "\tflush kernel table:\t\t%12u\n" - "\tresync with kernel table:\t%12u\n\n" + "\tresync with kernel table:\t%12u\n" + "\tcurrent buffer size (in bytes):\t%12u\n\n" "runtime stats:\n" "\tchild process failed:\t\t%12u\n" "\t\tchild process segfault:\t%12u\n" @@ -158,6 +159,7 @@ static void dump_stats_runtime(int fd) STATE(stats).nl_overrun, STATE(stats).nl_kernel_table_flush, STATE(stats).nl_kernel_table_resync, + CONFIG(netlink_buffer_size), STATE(stats).child_process_failed, STATE(stats).child_process_error_segfault, STATE(stats).child_process_error_term, -- cgit v1.2.3 From 6ceaa21f2a40cce6a9c45e99a9164618250fe6a3 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 14 Jan 2009 14:29:48 +0100 Subject: netlink: don't double the netlink buffer twice during resize The Linux kernel doubles the the size of the buffer by default. See sock_setsockopt() in net/core/sock.c. We don't need to multiply the current size by two. Signed-off-by: Pablo Neira Ayuso --- src/netlink.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/netlink.c b/src/netlink.c index e164dd7..92fbf00 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -118,7 +118,8 @@ static int warned = 0; void nl_resize_socket_buffer(struct nfct_handle *h) { - unsigned int s = CONFIG(netlink_buffer_size) * 2; + /* sock_setsockopt in net/core/sock.c doubles the size of the buffer */ + unsigned int s = CONFIG(netlink_buffer_size); /* already warned that we have reached the maximum buffer size */ if (warned) -- cgit v1.2.3 From 3e353c58a138d87ae31a9a18ec716c08ba3dc3cf Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 14 Jan 2009 20:06:29 +0100 Subject: src: constify hashtable parameter in hash() callbacks This patch constifies the hashtable parameter that is passed to the hash callbacks registered when the hashtable is created. Signed-off-by: Pablo Neira Ayuso --- include/hash.h | 7 ++++--- src/cache.c | 8 +++++--- src/filter.c | 4 ++-- src/hash.c | 3 ++- 4 files changed, 13 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/include/hash.h b/include/hash.h index d260f65..2fb0a27 100644 --- a/include/hash.h +++ b/include/hash.h @@ -17,8 +17,8 @@ struct hashtable { uint32_t initval; uint32_t datasize; - uint32_t (*hash)(const void *data, struct hashtable *table); - int (*compare)(const void *data1, const void *data2); + uint32_t (*hash)(const void *data, const struct hashtable *table); + int (*compare)(const void *data1, const void *data2); struct slist_head members[0]; }; @@ -33,7 +33,8 @@ void hashtable_destroy_node(struct hashtable_node *h); struct hashtable * hashtable_create(int hashsize, int limit, int datasize, - uint32_t (*hash)(const void *data, struct hashtable *table), + uint32_t (*hash)(const void *data, + const struct hashtable *table), int (*compare)(const void *data1, const void *data2)); void hashtable_destroy(struct hashtable *h); diff --git a/src/cache.c b/src/cache.c index 525832b..553dddf 100644 --- a/src/cache.c +++ b/src/cache.c @@ -28,7 +28,8 @@ #include #include -static uint32_t __hash4(const struct nf_conntrack *ct, struct hashtable *table) +static uint32_t +__hash4(const struct nf_conntrack *ct, const struct hashtable *table) { uint32_t a[4] = { [0] = nfct_get_attr_u32(ct, ATTR_IPV4_SRC), @@ -49,7 +50,8 @@ static uint32_t __hash4(const struct nf_conntrack *ct, struct hashtable *table) return ((uint64_t)jhash2(a, 4, 0) * table->hashsize) >> 32; } -static uint32_t __hash6(const struct nf_conntrack *ct, struct hashtable *table) +static uint32_t +__hash6(const struct nf_conntrack *ct, const struct hashtable *table) { uint32_t a[10]; @@ -63,7 +65,7 @@ static uint32_t __hash6(const struct nf_conntrack *ct, struct hashtable *table) return ((uint64_t)jhash2(a, 10, 0) * table->hashsize) >> 32; } -static uint32_t hash(const void *data, struct hashtable *table) +static uint32_t hash(const void *data, const struct hashtable *table) { int ret = 0; const struct us_conntrack *u = data; diff --git a/src/filter.c b/src/filter.c index 218ba0c..a3432a2 100644 --- a/src/filter.c +++ b/src/filter.c @@ -44,14 +44,14 @@ struct ct_filter { #define FILTER_POOL_SIZE 128 #define FILTER_POOL_LIMIT INT_MAX -static uint32_t hash(const void *data, struct hashtable *table) +static uint32_t hash(const void *data, const struct hashtable *table) { const uint32_t *f = data; return jhash_1word(*f, 0) % table->hashsize; } -static uint32_t hash6(const void *data, struct hashtable *table) +static uint32_t hash6(const void *data, const struct hashtable *table) { return jhash2(data, 4, 0) % table->hashsize; } diff --git a/src/hash.c b/src/hash.c index eb099dc..efc6a18 100644 --- a/src/hash.c +++ b/src/hash.c @@ -46,7 +46,8 @@ void hashtable_destroy_node(struct hashtable_node *h) struct hashtable * hashtable_create(int hashsize, int limit, int datasize, - uint32_t (*hash)(const void *data, struct hashtable *table), + uint32_t (*hash)(const void *data, + const struct hashtable *table), int (*compare)(const void *data1, const void *data2)) { int i; -- cgit v1.2.3 From 3c3256c5c0ca81486df3aaddf95e76d73849ba7f Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 14 Jan 2009 20:07:47 +0100 Subject: hashtable: use calloc instead of malloc + memset This patch is a cleanup, use calloc instead of malloc + memset. Signed-off-by: Pablo Neira Ayuso --- src/hash.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/hash.c b/src/hash.c index efc6a18..a7c7536 100644 --- a/src/hash.c +++ b/src/hash.c @@ -30,10 +30,9 @@ struct hashtable_node *hashtable_alloc_node(int datasize, void *data) struct hashtable_node *n; int size = sizeof(struct hashtable_node) + datasize; - n = malloc(size); + n = calloc(size, 1); if (!n) return NULL; - memset(n, 0, size); memcpy(n->data, data, datasize); return n; @@ -55,13 +54,12 @@ hashtable_create(int hashsize, int limit, int datasize, int size = sizeof(struct hashtable) + hashsize * sizeof(struct slist_head); - h = (struct hashtable *) malloc(size); + h = (struct hashtable *) calloc(size, 1); if (!h) { errno = ENOMEM; return NULL; } - memset(h, 0, size); for (i=0; imembers[i]); -- cgit v1.2.3 From e351346da584402647a147514610a744ee064d8e Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 14 Jan 2009 20:09:06 +0100 Subject: hashtable: check NULL instead of ! for pointers This patch is a cleanup. Check NULL instead of using ! for null pointers. Signed-off-by: Pablo Neira Ayuso --- src/hash.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/hash.c b/src/hash.c index a7c7536..1edb977 100644 --- a/src/hash.c +++ b/src/hash.c @@ -31,7 +31,7 @@ struct hashtable_node *hashtable_alloc_node(int datasize, void *data) int size = sizeof(struct hashtable_node) + datasize; n = calloc(size, 1); - if (!n) + if (n == NULL) return NULL; memcpy(n->data, data, datasize); @@ -55,7 +55,7 @@ hashtable_create(int hashsize, int limit, int datasize, + hashsize * sizeof(struct slist_head); h = (struct hashtable *) calloc(size, 1); - if (!h) { + if (h == NULL) { errno = ENOMEM; return NULL; } -- cgit v1.2.3 From 4556b3fb39dd80e958ff70f3496d06ec04f3839d Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 14 Jan 2009 20:09:37 +0100 Subject: filter: add prefix ct_filter_ to hash and compare functions This patch adds the prefix ct_filter_ to the hash and compare functions. This is useful to disambiguate when interpreting the oprofile reports. Note that without this patch there are two functions called hash and compare in the source tree. Signed-off-by: Pablo Neira Ayuso --- src/filter.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/filter.c b/src/filter.c index a3432a2..c6e24a9 100644 --- a/src/filter.c +++ b/src/filter.c @@ -44,19 +44,19 @@ struct ct_filter { #define FILTER_POOL_SIZE 128 #define FILTER_POOL_LIMIT INT_MAX -static uint32_t hash(const void *data, const struct hashtable *table) +static uint32_t ct_filter_hash(const void *data, const struct hashtable *table) { const uint32_t *f = data; return jhash_1word(*f, 0) % table->hashsize; } -static uint32_t hash6(const void *data, const struct hashtable *table) +static uint32_t ct_filter_hash6(const void *data, const struct hashtable *table) { return jhash2(data, 4, 0) % table->hashsize; } -static int compare(const void *data1, const void *data2) +static int ct_filter_compare(const void *data1, const void *data2) { const uint32_t *f1 = data1; const uint32_t *f2 = data2; @@ -64,7 +64,7 @@ static int compare(const void *data1, const void *data2) return *f1 == *f2; } -static int compare6(const void *data1, const void *data2) +static int ct_filter_compare6(const void *data1, const void *data2) { return memcmp(data1, data2, sizeof(uint32_t)*4) == 0; } @@ -81,8 +81,8 @@ struct ct_filter *ct_filter_create(void) filter->h = hashtable_create(FILTER_POOL_SIZE, FILTER_POOL_LIMIT, sizeof(uint32_t), - hash, - compare); + ct_filter_hash, + ct_filter_compare); if (!filter->h) { free(filter); return NULL; @@ -91,8 +91,8 @@ struct ct_filter *ct_filter_create(void) filter->h6 = hashtable_create(FILTER_POOL_SIZE, FILTER_POOL_LIMIT, sizeof(uint32_t)*4, - hash6, - compare6); + ct_filter_hash6, + ct_filter_compare6); if (!filter->h6) { free(filter->h); free(filter); -- cgit v1.2.3 From b28224b0326636ff5832b38817b7720f48070ee7 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 15 Jan 2009 23:19:35 +0100 Subject: run: limit the number of iterations over the event handling Currently, the event handling can starve other event file descriptors. This patch limits the number of event handling iterations. The parameter is tunable via configuration file. Signed-off-by: Pablo Neira Ayuso --- doc/sync/alarm/conntrackd.conf | 11 +++++++++++ doc/sync/ftfw/conntrackd.conf | 11 +++++++++++ doc/sync/notrack/conntrackd.conf | 11 +++++++++++ include/conntrackd.h | 2 ++ src/read_config_lex.l | 1 + src/read_config_yy.y | 11 ++++++++++- src/run.c | 11 ++++++++--- 7 files changed, 54 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/doc/sync/alarm/conntrackd.conf b/doc/sync/alarm/conntrackd.conf index f42a799..f16f439 100644 --- a/doc/sync/alarm/conntrackd.conf +++ b/doc/sync/alarm/conntrackd.conf @@ -164,6 +164,17 @@ General { # SocketBufferSizeMaxGrowth 8388608 + # + # The daemon prioritizes the handling of state-change events coming + # from the core. With this clause, you can set the maximum number of + # state-change events (those coming from kernel-space) that the daemon + # will handle after which it will handle other events coming from the + # network or userspace. A low value improves interactivity (in terms of + # real-time behaviour) at the cost of extra CPU consumption. + # Default (if not set) is 100. + # + # EventIterationLimit 100 + # # Event filtering: This clause allows you to filter certain traffic, # There are currently three filter-sets: Protocol, Address and diff --git a/doc/sync/ftfw/conntrackd.conf b/doc/sync/ftfw/conntrackd.conf index e12a745..d85fc28 100644 --- a/doc/sync/ftfw/conntrackd.conf +++ b/doc/sync/ftfw/conntrackd.conf @@ -172,6 +172,17 @@ General { # SocketBufferSizeMaxGrowth 8388608 + # + # The daemon prioritizes the handling of state-change events coming + # from the core. With this clause, you can set the maximum number of + # state-change events (those coming from kernel-space) that the daemon + # will handle after which it will handle other events coming from the + # network or userspace. A low value improves interactivity (in terms of + # real-time behaviour) at the cost of extra CPU consumption. + # Default (if not set) is 100. + # + # EventIterationLimit 100 + # # Event filtering: This clause allows you to filter certain traffic, # There are currently three filter-sets: Protocol, Address and diff --git a/doc/sync/notrack/conntrackd.conf b/doc/sync/notrack/conntrackd.conf index cbc26ee..4d03234 100644 --- a/doc/sync/notrack/conntrackd.conf +++ b/doc/sync/notrack/conntrackd.conf @@ -154,6 +154,17 @@ General { # SocketBufferSizeMaxGrowth 8388608 + # + # The daemon prioritizes the handling of state-change events coming + # from the core. With this clause, you can set the maximum number of + # state-change events (those coming from kernel-space) that the daemon + # will handle after which it will handle other events coming from the + # network or userspace. A low value improves interactivity (in terms of + # real-time behaviour) at the cost of extra CPU consumption. + # Default (if not set) is 100. + # + # EventIterationLimit 100 + # # Event filtering: This clause allows you to filter certain traffic, # There are currently three filter-sets: Protocol, Address and diff --git a/include/conntrackd.h b/include/conntrackd.h index df36ec4..67397b8 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -84,6 +84,7 @@ struct ct_conf { unsigned int window_size; int cache_write_through; int filter_from_kernelspace; + int event_iterations_limit; struct { char logfile[FILENAME_MAXLEN]; int syslog_facility; @@ -103,6 +104,7 @@ struct ct_general_state { struct nfct_handle *event; /* event handler */ struct nfct_filter *filter; /* event filter */ + int event_iterations_limit; struct nfct_handle *dump; /* dump handler */ struct nfct_handle *request; /* request handler */ diff --git a/src/read_config_lex.l b/src/read_config_lex.l index 67c95d3..f8b0ba1 100644 --- a/src/read_config_lex.l +++ b/src/read_config_lex.l @@ -117,6 +117,7 @@ notrack [N|n][O|o][T|t][R|r][A|a][C|c][K|k] "From" { return T_FROM; } "Userspace" { return T_USERSPACE; } "Kernelspace" { return T_KERNELSPACE; } +"EventIterationLimit" { return T_EVENT_ITER_LIMIT; } {is_on} { return T_ON; } {is_off} { return T_OFF; } diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 69a7eff..274bfc3 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -59,7 +59,7 @@ static void __kernel_filter_add_state(int value); %token T_SYSLOG T_WRITE_THROUGH T_STAT_BUFFER_SIZE T_DESTROY_TIMEOUT %token T_MCAST_RCVBUFF T_MCAST_SNDBUFF T_NOTRACK %token T_FILTER T_ADDRESS T_PROTOCOL T_STATE T_ACCEPT T_IGNORE -%token T_FROM T_USERSPACE T_KERNELSPACE +%token T_FROM T_USERSPACE T_KERNELSPACE T_EVENT_ITER_LIMIT %token T_IP T_PATH_VAL %token T_NUMBER @@ -681,6 +681,7 @@ general_line: hashsize | netlink_buffer_size | netlink_buffer_size_max_grown | family + | event_iterations_limit | filter ; @@ -702,6 +703,11 @@ family : T_FAMILY T_STRING conf.family = AF_INET; }; +event_iterations_limit : T_EVENT_ITER_LIMIT T_NUMBER +{ + CONFIG(event_iterations_limit) = $2; +}; + filter : T_FILTER '{' filter_list '}' { CONFIG(filter_from_kernelspace) = 0; @@ -1096,5 +1102,8 @@ init_config(char *filename) if (conf.flags & CTD_SYNC_FTFW && CONFIG(del_timeout) == 0) CONFIG(del_timeout) = 240; + if (CONFIG(event_iterations_limit) == 0) + CONFIG(event_iterations_limit) = 100; + return 0; } diff --git a/src/run.c b/src/run.c index 7958665..caf0b38 100644 --- a/src/run.c +++ b/src/run.c @@ -219,7 +219,7 @@ static int event_handler(enum nf_conntrack_msg_type type, /* skip user-space filtering if already do it in the kernel */ if (ct_filter_conntrack(ct, !CONFIG(filter_from_kernelspace))) { STATE(stats).nl_events_filtered++; - return NFCT_CB_STOP; + goto out; } switch(type) { @@ -238,7 +238,12 @@ static int event_handler(enum nf_conntrack_msg_type type, break; } - return NFCT_CB_CONTINUE; +out: + if (STATE(event_iterations_limit)-- <= 0) { + STATE(event_iterations_limit) = CONFIG(event_iterations_limit); + return NFCT_CB_STOP; + } else + return NFCT_CB_CONTINUE; } static int dump_handler(enum nf_conntrack_msg_type type, @@ -397,7 +402,7 @@ static void __run(struct timeval *next_alarm) /* conntrack event has happened */ if (FD_ISSET(nfct_fd(STATE(event)), &readfds)) { - while ((ret = nfct_catch(STATE(event))) != -1); + ret = nfct_catch(STATE(event)); if (ret == -1) { switch(errno) { case ENOBUFS: -- cgit v1.2.3 From 50339f96638eed35dac2b673b64cc6f1eb96406c Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 15 Jan 2009 23:19:57 +0100 Subject: src: rework of the hash-cache infrastructure Currently, the caching system is implemented in a two layer architecture: hashtable (inner layer) and cache (upper layer). This patch reworks the hash-cache infrastructure to solve some initial design problems to make it more flexible, the main strong points of this patch are: * Memory handling is done in the cache layer, not in the inner hashtable layer. This removes one of the main dependencies between the hashtable and the cache classes. * Remove excessive encapsulation: the former cache used to hide a lot of details of the inner hashtable implementation. * Fix over-hashing of some operations: lookup-delete-add required three hash calculations. Similarly, the update-or-add operation required two hash calculations. Now, we calculate the hash once and re-use the value how many times as we need. This patch simplifies the caching system. As a result, we save ~130 lines of code. Small code means and less complexity means less chance to have bugs. Signed-off-by: Pablo Neira Ayuso --- include/Makefile.am | 4 +- include/cache.h | 43 +++++--- include/filter.h | 11 ++ include/hash.h | 22 ++-- include/network.h | 1 - include/slist.h | 41 -------- include/sync.h | 4 +- include/us-conntrack.h | 14 --- src/cache.c | 273 +++++++++++++++++++------------------------------ src/cache_iterators.c | 65 ++++++------ src/cache_lifetime.c | 10 +- src/cache_timer.c | 36 +++---- src/cache_wt.c | 33 +++--- src/filter.c | 57 +++++++++-- src/hash.c | 136 +++++++----------------- src/stats-mode.c | 55 +++++----- src/sync-alarm.c | 27 +++-- src/sync-ftfw.c | 40 ++++---- src/sync-mode.c | 116 +++++++++++---------- src/sync-notrack.c | 19 ++-- 20 files changed, 440 insertions(+), 567 deletions(-) delete mode 100644 include/slist.h delete mode 100644 include/us-conntrack.h (limited to 'src') diff --git a/include/Makefile.am b/include/Makefile.am index 13f7e37..c3f8904 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -1,6 +1,6 @@ -noinst_HEADERS = alarm.h jhash.h slist.h cache.h linux_list.h linux_rbtree.h \ - sync.h conntrackd.h local.h us-conntrack.h \ +noinst_HEADERS = alarm.h jhash.h cache.h linux_list.h linux_rbtree.h \ + sync.h conntrackd.h local.h \ debug.h log.h hash.h mcast.h conntrack.h \ network.h filter.h queue.h vector.h cidr.h \ traffic_stats.h netlink.h fds.h event.h bitops.h diff --git a/include/cache.h b/include/cache.h index ebed70a..dcd6bcd 100644 --- a/include/cache.h +++ b/include/cache.h @@ -3,6 +3,8 @@ #include #include +#include "hash.h" +#include "alarm.h" /* cache features */ enum { @@ -22,14 +24,20 @@ enum { #define CACHE_MAX_FEATURE __CACHE_MAX_FEATURE struct cache; -struct us_conntrack; +struct cache_object { + struct hashtable_node hashnode; + struct nf_conntrack *ct; + struct cache *cache; + struct alarm_block alarm; + char data[0]; +}; struct cache_feature { size_t size; - void (*add)(struct us_conntrack *u, void *data); - void (*update)(struct us_conntrack *u, void *data); - void (*destroy)(struct us_conntrack *u, void *data); - int (*dump)(struct us_conntrack *u, void *data, char *buf, int type); + void (*add)(struct cache_object *obj, void *data); + void (*update)(struct cache_object *obj, void *data); + void (*destroy)(struct cache_object *obj, void *data); + int (*dump)(struct cache_object *obj, void *data, char *buf, int type); }; extern struct cache_feature lifetime_feature; @@ -48,6 +56,7 @@ struct cache { unsigned int *feature_offset; struct cache_extra *extra; unsigned int extra_offset; + size_t object_size; /* statistics */ struct { @@ -77,9 +86,9 @@ struct cache { struct cache_extra { unsigned int size; - void (*add)(struct us_conntrack *u, void *data); - void (*update)(struct us_conntrack *u, void *data); - void (*destroy)(struct us_conntrack *u, void *data); + void (*add)(struct cache_object *obj, void *data); + void (*update)(struct cache_object *obj, void *data); + void (*destroy)(struct cache_object *obj, void *data); }; struct nf_conntrack; @@ -87,16 +96,18 @@ struct nf_conntrack; struct cache *cache_create(const char *name, unsigned int features, struct cache_extra *extra); void cache_destroy(struct cache *e); -struct us_conntrack *cache_add(struct cache *c, struct nf_conntrack *ct); -struct us_conntrack *cache_update(struct cache *c, struct nf_conntrack *ct); -struct us_conntrack *cache_update_force(struct cache *c, struct nf_conntrack *ct); -int cache_del(struct cache *c, struct nf_conntrack *ct); -int __cache_del_timer(struct cache *c, struct us_conntrack *u, int timeout); -struct us_conntrack *cache_find(struct cache *c, struct nf_conntrack *ct); -int cache_test(struct cache *c, struct nf_conntrack *ct); +struct cache_object *cache_object_new(struct cache *c, struct nf_conntrack *ct); +void cache_object_free(struct cache_object *obj); + +int cache_add(struct cache *c, struct cache_object *obj, int id); +void cache_update(struct cache *c, struct cache_object *obj, int id, struct nf_conntrack *ct); +struct cache_object *cache_update_force(struct cache *c, struct nf_conntrack *ct); +void cache_del(struct cache *c, struct cache_object *obj); +int cache_del_timer(struct cache *c, struct cache_object *obj, int timeout); +struct cache_object *cache_find(struct cache *c, struct nf_conntrack *ct, int *pos); void cache_stats(const struct cache *c, int fd); void cache_stats_extended(const struct cache *c, int fd); -struct us_conntrack *cache_get_conntrack(struct cache *, void *); +struct cache_object *cache_data_get_object(struct cache *c, void *data); void *cache_get_extra(struct cache *, void *); void cache_iterate(struct cache *c, void *data, int (*iterate)(void *data1, void *data2)); diff --git a/include/filter.h b/include/filter.h index 9c2cf66..72c2aa4 100644 --- a/include/filter.h +++ b/include/filter.h @@ -4,6 +4,7 @@ #include #include #include +#include enum ct_filter_type { CT_FILTER_L4PROTO, @@ -17,6 +18,16 @@ enum ct_filter_logic { CT_FILTER_POSITIVE = 1, }; +struct ct_filter_ipv4_hnode { + struct hashtable_node node; + uint32_t ip; +}; + +struct ct_filter_ipv6_hnode { + struct hashtable_node node; + uint32_t ipv6[4]; +}; + struct ct_filter_netmask_ipv4 { uint32_t ip; uint32_t mask; diff --git a/include/hash.h b/include/hash.h index 2fb0a27..68d618b 100644 --- a/include/hash.h +++ b/include/hash.h @@ -2,7 +2,6 @@ #define _NF_SET_HASH_H_ #include -#include "slist.h" #include "linux_list.h" #include @@ -15,35 +14,30 @@ struct hashtable { uint32_t limit; uint32_t count; uint32_t initval; - uint32_t datasize; uint32_t (*hash)(const void *data, const struct hashtable *table); int (*compare)(const void *data1, const void *data2); - struct slist_head members[0]; + struct list_head members[0]; }; struct hashtable_node { - struct slist_head head; - char data[0]; + struct list_head head; }; -struct hashtable_node *hashtable_alloc_node(int datasize, void *data); -void hashtable_destroy_node(struct hashtable_node *h); - struct hashtable * -hashtable_create(int hashsize, int limit, int datasize, +hashtable_create(int hashsize, int limit, uint32_t (*hash)(const void *data, const struct hashtable *table), int (*compare)(const void *data1, const void *data2)); void hashtable_destroy(struct hashtable *h); - -void *hashtable_add(struct hashtable *table, void *data); -void *hashtable_find(struct hashtable *table, const void *data); -int hashtable_del(struct hashtable *table, void *data); +int hashtable_hash(const struct hashtable *table, const void *data); +struct hashtable_node *hashtable_find(const struct hashtable *table, const void *data, int id); +int hashtable_add(struct hashtable *table, struct hashtable_node *n, int id); +void hashtable_del(struct hashtable *table, struct hashtable_node *node); int hashtable_flush(struct hashtable *table); int hashtable_iterate(struct hashtable *table, void *data, - int (*iterate)(void *data1, void *data2)); + int (*iterate)(void *data, struct hashtable_node *n)); unsigned int hashtable_counter(const struct hashtable *table); #endif diff --git a/include/network.h b/include/network.h index 40bb2b2..619ce3e 100644 --- a/include/network.h +++ b/include/network.h @@ -75,7 +75,6 @@ enum { __hdr; \ }) -struct us_conntrack; struct mcast_sock; enum { diff --git a/include/slist.h b/include/slist.h deleted file mode 100644 index 257b627..0000000 --- a/include/slist.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef _SLIST_H_ -#define _SLIST_H_ - -#include "linux_list.h" - -#define INIT_SLIST_HEAD(ptr) ((ptr).next = NULL) - -struct slist_head { - struct slist_head *next; -}; - -static inline int slist_empty(const struct slist_head *h) -{ - return !h->next; -} - -static inline void slist_del(struct slist_head *t, struct slist_head *prev) -{ - prev->next = t->next; - t->next = LIST_POISON1; -} - -static inline void slist_add(struct slist_head *head, struct slist_head *t) -{ - struct slist_head *tmp = head->next; - head->next = t; - t->next = tmp; -} - -#define slist_entry(ptr, type, member) container_of(ptr,type,member) - -#define slist_for_each(pos, head) \ - for (pos = (head)->next; pos; \ - pos = pos->next) - -#define slist_for_each_safe(pos, prev, next, head) \ - for (pos = (head)->next, prev = (head); \ - pos && ({ next = pos->next; 1; }); \ - ({ prev = (prev->next != next) ? prev->next : prev; }), pos = next) - -#endif diff --git a/include/sync.h b/include/sync.h index fc06c93..60c9fae 100644 --- a/include/sync.h +++ b/include/sync.h @@ -2,7 +2,7 @@ #define _SYNC_HOOKS_H_ struct nethdr; -struct us_conntrack; +struct cache_object; struct sync_mode { int internal_cache_flags; @@ -14,7 +14,7 @@ struct sync_mode { void (*kill)(void); int (*local)(int fd, int type, void *data); int (*recv)(const struct nethdr *net); - void (*send)(struct nethdr *net, struct us_conntrack *u); + void (*send)(struct nethdr *net, struct cache_object *obj); void (*run)(void); }; diff --git a/include/us-conntrack.h b/include/us-conntrack.h deleted file mode 100644 index 9eafa3b..0000000 --- a/include/us-conntrack.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef _US_CONNTRACK_H_ -#define _US_CONNTRACK_H_ - -#include "alarm.h" -#include - -struct us_conntrack { - struct nf_conntrack *ct; - struct cache *cache; - struct alarm_block alarm; - char data[0]; -}; - -#endif diff --git a/src/cache.c b/src/cache.c index 553dddf..621a3f4 100644 --- a/src/cache.c +++ b/src/cache.c @@ -1,5 +1,5 @@ /* - * (C) 2006-2007 by Pablo Neira Ayuso + * (C) 2006-2009 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 @@ -20,7 +20,6 @@ #include "jhash.h" #include "hash.h" #include "log.h" -#include "us-conntrack.h" #include "conntrackd.h" #include @@ -68,14 +67,14 @@ __hash6(const struct nf_conntrack *ct, const struct hashtable *table) static uint32_t hash(const void *data, const struct hashtable *table) { int ret = 0; - const struct us_conntrack *u = data; + const struct nf_conntrack *ct = data; - switch(nfct_get_attr_u8(u->ct, ATTR_L3PROTO)) { + switch(nfct_get_attr_u8(ct, ATTR_L3PROTO)) { case AF_INET: - ret = __hash4(u->ct, table); + ret = __hash4(ct, table); break; case AF_INET6: - ret = __hash6(u->ct, table); + ret = __hash6(ct, table); break; default: dlog(LOG_ERR, "unknown layer 3 proto in hash"); @@ -87,10 +86,10 @@ static uint32_t hash(const void *data, const struct hashtable *table) static int compare(const void *data1, const void *data2) { - const struct us_conntrack *u1 = data1; - const struct us_conntrack *u2 = data2; + const struct cache_object *obj = data1; + const struct nf_conntrack *ct = data2; - return nfct_cmp(u1->ct, u2->ct, NFCT_CMP_ORIG); + return nfct_cmp(obj->ct, ct, NFCT_CMP_ORIG); } struct cache_feature *cache_feature[CACHE_MAX_FEATURE] = { @@ -103,7 +102,7 @@ struct cache *cache_create(const char *name, unsigned int features, struct cache_extra *extra) { - size_t size = sizeof(struct us_conntrack); + size_t size = sizeof(struct cache_object); int i, j = 0; struct cache *c; struct cache_feature *feature_array[CACHE_MAX_FEATURE] = {}; @@ -152,7 +151,6 @@ struct cache *cache_create(const char *name, c->h = hashtable_create(CONFIG(hashsize), CONFIG(limit), - size, hash, compare); @@ -162,6 +160,7 @@ struct cache *cache_create(const char *name, free(c); return NULL; } + c->object_size = size; return c; } @@ -177,225 +176,165 @@ void cache_destroy(struct cache *c) static void __del_timeout(struct alarm_block *a, void *data); -static struct us_conntrack *__add(struct cache *c, struct nf_conntrack *ct) +struct cache_object *cache_object_new(struct cache *c, struct nf_conntrack *ct) { - unsigned i; - size_t size = c->h->datasize; - char buf[size]; - struct us_conntrack *u = (struct us_conntrack *) buf; - struct nf_conntrack *newct; + struct cache_object *obj; - memset(u, 0, size); + obj = calloc(c->object_size, 1); + if (obj == NULL) { + errno = ENOMEM; + c->stats.add_fail_enomem++; + return NULL; + } + obj->cache = c; + init_alarm(&obj->alarm, obj, __del_timeout); - u->cache = c; - if ((u->ct = newct = nfct_new()) == NULL) { + if ((obj->ct = nfct_new()) == NULL) { + free(obj); errno = ENOMEM; - return 0; + c->stats.add_fail_enomem++; + return NULL; } - memcpy(u->ct, ct, nfct_sizeof(ct)); + memcpy(obj->ct, ct, nfct_sizeof(ct)); - u = hashtable_add(c->h, u); - if (u) { - char *data = u->data; + return obj; +} - init_alarm(&u->alarm, u, __del_timeout); +void cache_object_free(struct cache_object *obj) +{ + nfct_destroy(obj->ct); + free(obj); +} - for (i = 0; i < c->num_features; i++) { - c->features[i]->add(u, data); - data += c->features[i]->size; - } +static int __add(struct cache *c, struct cache_object *obj, int id) +{ + int ret; + unsigned int i; + char *data = obj->data; - if (c->extra && c->extra->add) - c->extra->add(u, ((char *) u) + c->extra_offset); + ret = hashtable_add(c->h, &obj->hashnode, id); + if (ret == -1) + return -1; - c->stats.active++; - return u; + for (i = 0; i < c->num_features; i++) { + c->features[i]->add(obj, data); + data += c->features[i]->size; } - free(newct); - return NULL; + if (c->extra && c->extra->add) + c->extra->add(obj, ((char *) obj) + c->extra_offset); + + c->stats.active++; + return 0; } -struct us_conntrack *cache_add(struct cache *c, struct nf_conntrack *ct) +int cache_add(struct cache *c, struct cache_object *obj, int id) { - struct us_conntrack *u; + int ret; - u = __add(c, ct); - if (u) { - c->stats.add_ok++; - return u; - } - if (errno != EEXIST) { + ret = __add(c, obj, id); + if (ret == -1) { c->stats.add_fail++; if (errno == ENOSPC) c->stats.add_fail_enospc++; - if (errno == ENOMEM) - c->stats.add_fail_enomem++; + return -1; } - - return NULL; + c->stats.add_ok++; + return 0; } -static void -__cache_update(struct cache *c, struct us_conntrack *u, struct nf_conntrack *ct) +void cache_update(struct cache *c, struct cache_object *obj, int id, + struct nf_conntrack *ct) { - unsigned i; - char *data = u->data; + char *data = obj->data; + unsigned int i; - nfct_copy(u->ct, ct, NFCT_CP_META); + nfct_copy(obj->ct, ct, NFCT_CP_META); for (i = 0; i < c->num_features; i++) { - c->features[i]->update(u, data); + c->features[i]->update(obj, data); data += c->features[i]->size; } if (c->extra && c->extra->update) - c->extra->update(u, ((char *) u) + c->extra_offset); -} - -static struct us_conntrack *__update(struct cache *c, struct nf_conntrack *ct) -{ - size_t size = c->h->datasize; - char buf[size]; - struct us_conntrack *u = (struct us_conntrack *) buf; - - u->ct = ct; - - u = (struct us_conntrack *) hashtable_find(c->h, u); - if (u) { - __cache_update(c, u, ct); - return u; - } - return NULL; -} + c->extra->update(obj, ((char *) obj) + c->extra_offset); -struct us_conntrack *cache_update(struct cache *c, struct nf_conntrack *ct) -{ - struct us_conntrack *u; - - u = __update(c, ct); - if (u) { - c->stats.upd_ok++; - return u; - } - c->stats.upd_fail++; - if (errno == ENOENT) - c->stats.upd_fail_enoent++; - - return NULL; + c->stats.upd_ok++; } -static void __del(struct cache *c, struct us_conntrack *u) +static void __del(struct cache *c, struct cache_object *obj) { unsigned i; - char *data = u->data; - struct nf_conntrack *p = u->ct; + char *data = obj->data; for (i = 0; i < c->num_features; i++) { - c->features[i]->destroy(u, data); + c->features[i]->destroy(obj, data); data += c->features[i]->size; } if (c->extra && c->extra->destroy) - c->extra->destroy(u, ((char *) u) + c->extra_offset); + c->extra->destroy(obj, ((char *) obj) + c->extra_offset); - hashtable_del(c->h, u); - free(p); + hashtable_del(c->h, &obj->hashnode); } -static void __cache_del(struct cache *c, struct us_conntrack *u) +void cache_del(struct cache *c, struct cache_object *obj) { /* * Do not increase stats if we are trying to * kill an entry was previously deleted via * __cache_del_timer. */ - if (!alarm_pending(&u->alarm)) { + if (!alarm_pending(&obj->alarm)) { c->stats.del_ok++; c->stats.active--; } - del_alarm(&u->alarm); - __del(c, u); + del_alarm(&obj->alarm); + __del(c, obj); } -struct us_conntrack *cache_update_force(struct cache *c, - struct nf_conntrack *ct) +struct cache_object * +cache_update_force(struct cache *c, struct nf_conntrack *ct) { - struct us_conntrack *u; - - u = cache_find(c, ct); - if (u) { - if (!alarm_pending(&u->alarm)) { - c->stats.upd_ok++; - __cache_update(c, u, ct); - return u; + struct cache_object *obj; + int id; + + obj = cache_find(c, ct, &id); + if (obj) { + if (!alarm_pending(&obj->alarm)) { + cache_update(c, obj, id, ct); + return obj; } else { - __cache_del(c, u); + cache_del(c, obj); + cache_object_free(obj); } } - if ((u = __add(c, ct)) != NULL) { - c->stats.add_ok++; - return u; - } - c->stats.add_fail++; - if (errno == ENOSPC) - c->stats.add_fail_enospc++; - if (errno == ENOMEM) - c->stats.add_fail_enomem++; - - return NULL; -} - -int cache_test(struct cache *c, struct nf_conntrack *ct) -{ - size_t size = c->h->datasize; - char buf[size]; - struct us_conntrack *u = (struct us_conntrack *) buf; - void *ret; - - u->ct = ct; - - ret = hashtable_find(c->h, u); - - return ret != NULL; -} - -int cache_del(struct cache *c, struct nf_conntrack *ct) -{ - size_t size = c->h->datasize; - char buf[size]; - struct us_conntrack *u = (struct us_conntrack *) buf; - - u->ct = ct; + obj = cache_object_new(c, ct); + if (obj == NULL) + return NULL; - u = (struct us_conntrack *) hashtable_find(c->h, u); - if (u) { - __cache_del(c, u); - return 1; - } - c->stats.del_fail++; - if (errno == ENOENT) - c->stats.del_fail_enoent++; + if (cache_add(c, obj, id) == -1) + return NULL; - return 0; + return obj; } static void __del_timeout(struct alarm_block *a, void *data) { - struct us_conntrack *u = (struct us_conntrack *) data; - - __del(u->cache, u); + struct cache_object *obj = (struct cache_object *) data; + __del(obj->cache, obj); + cache_object_free(obj); } -int -__cache_del_timer(struct cache *c, struct us_conntrack *u, int timeout) +int cache_del_timer(struct cache *c, struct cache_object *obj, int timeout) { if (timeout <= 0) { - __cache_del(c, u); + cache_del(c, obj); + cache_object_free(obj); return 1; } - if (!alarm_pending(&u->alarm)) { - add_alarm(&u->alarm, timeout, 0); + if (!alarm_pending(&obj->alarm)) { + add_alarm(&obj->alarm, timeout, 0); /* * increase stats even if this entry was not really * removed yet. We do not want to make people think @@ -409,20 +348,16 @@ __cache_del_timer(struct cache *c, struct us_conntrack *u, int timeout) return 0; } -struct us_conntrack *cache_find(struct cache *c, struct nf_conntrack *ct) +struct cache_object * +cache_find(struct cache *c, struct nf_conntrack *ct, int *id) { - size_t size = c->h->datasize; - char buf[size]; - struct us_conntrack *u = (struct us_conntrack *) buf; - - u->ct = ct; - - return ((struct us_conntrack *) hashtable_find(c->h, u)); + *id = hashtable_hash(c->h, ct); + return ((struct cache_object *) hashtable_find(c->h, ct, *id)); } -struct us_conntrack *cache_get_conntrack(struct cache *c, void *data) +struct cache_object *cache_data_get_object(struct cache *c, void *data) { - return (struct us_conntrack *)((char*)data - c->extra_offset); + return (struct cache_object *)((char*)data - c->extra_offset); } void *cache_get_extra(struct cache *c, void *data) diff --git a/src/cache_iterators.c b/src/cache_iterators.c index a14f428..4773889 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -21,7 +21,6 @@ #include "log.h" #include "conntrackd.h" #include "netlink.h" -#include "us-conntrack.h" #include #include @@ -33,13 +32,13 @@ struct __dump_container { int type; }; -static int do_dump(void *data1, void *data2) +static int do_dump(void *data1, struct hashtable_node *n) { char buf[1024]; int size; struct __dump_container *container = data1; - struct us_conntrack *u = data2; - char *data = u->data; + struct cache_object *obj = (struct cache_object *)n; + char *data = obj->data; unsigned i; /* @@ -52,28 +51,28 @@ static int do_dump(void *data1, void *data2) * specific and it breaks conntrackd modularity. Probably * there's a nicer way to do this but until I come up with it... */ - if (CONFIG(flags) & CTD_SYNC_FTFW && alarm_pending(&u->alarm)) + if (CONFIG(flags) & CTD_SYNC_FTFW && alarm_pending(&obj->alarm)) return 0; /* do not show cached timeout, this may confuse users */ - if (nfct_attr_is_set(u->ct, ATTR_TIMEOUT)) - nfct_attr_unset(u->ct, ATTR_TIMEOUT); + if (nfct_attr_is_set(obj->ct, ATTR_TIMEOUT)) + nfct_attr_unset(obj->ct, ATTR_TIMEOUT); memset(buf, 0, sizeof(buf)); size = nfct_snprintf(buf, sizeof(buf), - u->ct, + obj->ct, NFCT_T_UNKNOWN, container->type, 0); - for (i = 0; i < u->cache->num_features; i++) { - if (u->cache->features[i]->dump) { - size += u->cache->features[i]->dump(u, - data, - buf+size, - container->type); - data += u->cache->features[i]->size; + for (i = 0; i < obj->cache->num_features; i++) { + if (obj->cache->features[i]->dump) { + size += obj->cache->features[i]->dump(obj, + data, + buf+size, + container->type); + data += obj->cache->features[i]->size; } } size += sprintf(buf+size, "\n"); @@ -101,10 +100,10 @@ struct __commit_container { }; static void -__do_commit_step(struct __commit_container *tmp, struct us_conntrack *u) +__do_commit_step(struct __commit_container *tmp, struct cache_object *obj) { int ret, retry = 1; - struct nf_conntrack *ct = u->ct; + struct nf_conntrack *ct = obj->ct; /* * Set a reduced timeout for candidate-to-be-committed @@ -166,25 +165,25 @@ try_again: } } -static int do_commit_related(void *data1, void *data2) +static int do_commit_related(void *data, struct hashtable_node *n) { - struct us_conntrack *u = data2; + struct cache_object *obj = (struct cache_object *)n; - if (ct_is_related(u->ct)) - __do_commit_step(data1, u); + if (ct_is_related(obj->ct)) + __do_commit_step(data, obj); /* keep iterating even if we have found errors */ return 0; } -static int do_commit_master(void *data1, void *data2) +static int do_commit_master(void *data, struct hashtable_node *n) { - struct us_conntrack *u = data2; + struct cache_object *obj = (struct cache_object *)n; - if (ct_is_related(u->ct)) + if (ct_is_related(obj->ct)) return 0; - __do_commit_step(data1, u); + __do_commit_step(data, obj); return 0; } @@ -231,13 +230,13 @@ void cache_commit(struct cache *c) res.tv_sec, res.tv_usec); } -static int do_reset_timers(void *data1, void *data2) +static int do_reset_timers(void *data1, struct hashtable_node *n) { int ret; u_int32_t current_timeout; struct nfct_handle *h = data1; - struct us_conntrack *u = data2; - struct nf_conntrack *ct = u->ct; + struct cache_object *obj = (struct cache_object *)n; + struct nf_conntrack *ct = obj->ct; char __tmp[nfct_maxsize()]; struct nf_conntrack *tmp = (struct nf_conntrack *) (void *)__tmp; @@ -286,13 +285,13 @@ void cache_reset_timers(struct cache *c) nfct_close(h); } -static int do_flush(void *data1, void *data2) +static int do_flush(void *data, struct hashtable_node *n) { - struct cache *c = data1; - struct us_conntrack *u = data2; - - cache_del(c, u->ct); + struct cache *c = data; + struct cache_object *obj = (struct cache_object *)n; + cache_del(c, obj); + cache_object_free(obj); return 0; } diff --git a/src/cache_lifetime.c b/src/cache_lifetime.c index ad3416a..639d8c1 100644 --- a/src/cache_lifetime.c +++ b/src/cache_lifetime.c @@ -17,12 +17,12 @@ */ #include -#include "us-conntrack.h" #include "cache.h" #include #include +#include -static void lifetime_add(struct us_conntrack *u, void *data) +static void lifetime_add(struct cache_object *obj, void *data) { long *lifetime = data; struct timeval tv; @@ -32,15 +32,15 @@ static void lifetime_add(struct us_conntrack *u, void *data) *lifetime = tv.tv_sec; } -static void lifetime_update(struct us_conntrack *u, void *data) +static void lifetime_update(struct cache_object *obj, void *data) { } -static void lifetime_destroy(struct us_conntrack *u, void *data) +static void lifetime_destroy(struct cache_object *obj, void *data) { } -static int lifetime_dump(struct us_conntrack *u, +static int lifetime_dump(struct cache_object *obj, void *data, char *buf, int type) diff --git a/src/cache_timer.c b/src/cache_timer.c index 44482b7..a9e3e3d 100644 --- a/src/cache_timer.c +++ b/src/cache_timer.c @@ -18,7 +18,6 @@ #include "cache.h" #include "conntrackd.h" -#include "us-conntrack.h" #include "alarm.h" #include "debug.h" @@ -26,45 +25,46 @@ static void timeout(struct alarm_block *a, void *data) { - struct us_conntrack *u = data; + struct cache_object *obj = data; - debug_ct(u->ct, "expired timeout"); - cache_del(u->cache, u->ct); + debug_ct(obj->ct, "expired timeout"); + cache_del(obj->cache, obj); + cache_object_free(obj); } -static void timer_add(struct us_conntrack *u, void *data) +static void timer_add(struct cache_object *obj, void *data) { - struct alarm_block *alarm = data; + struct alarm_block *a = data; - init_alarm(alarm, u, timeout); - add_alarm(alarm, CONFIG(cache_timeout), 0); + init_alarm(a, obj, timeout); + add_alarm(a, CONFIG(cache_timeout), 0); } -static void timer_update(struct us_conntrack *u, void *data) +static void timer_update(struct cache_object *obj, void *data) { - struct alarm_block *alarm = data; - add_alarm(alarm, CONFIG(cache_timeout), 0); + struct alarm_block *a = data; + add_alarm(a, CONFIG(cache_timeout), 0); } -static void timer_destroy(struct us_conntrack *u, void *data) +static void timer_destroy(struct cache_object *obj, void *data) { - struct alarm_block *alarm = data; - del_alarm(alarm); + struct alarm_block *a = data; + del_alarm(a); } -static int timer_dump(struct us_conntrack *u, void *data, char *buf, int type) +static int timer_dump(struct cache_object *obj, void *data, char *buf, int type) { struct timeval tv, tmp; - struct alarm_block *alarm = data; + struct alarm_block *a = data; if (type == NFCT_O_XML) return 0; - if (!alarm_pending(alarm)) + if (!alarm_pending(a)) return 0; gettimeofday(&tv, NULL); - timersub(&alarm->tv, &tv, &tmp); + timersub(&a->tv, &tv, &tmp); return sprintf(buf, " [expires in %lds]", tmp.tv_sec); } diff --git a/src/cache_wt.c b/src/cache_wt.c index d0ae8bb..84a816f 100644 --- a/src/cache_wt.c +++ b/src/cache_wt.c @@ -19,67 +19,66 @@ #include "conntrackd.h" #include "cache.h" #include "netlink.h" -#include "us-conntrack.h" #include "log.h" #include #include -static void add_wt(struct us_conntrack *u) +static void add_wt(struct cache_object *obj) { int ret; char __ct[nfct_maxsize()]; struct nf_conntrack *ct = (struct nf_conntrack *)(void*) __ct; - ret = nl_exist_conntrack(STATE(request), u->ct); + ret = nl_exist_conntrack(STATE(request), obj->ct); switch (ret) { case -1: dlog(LOG_ERR, "cache_wt problem: %s", strerror(errno)); - dlog_ct(STATE(log), u->ct, NFCT_O_PLAIN); + dlog_ct(STATE(log), obj->ct, NFCT_O_PLAIN); break; case 0: - memcpy(ct, u->ct, nfct_maxsize()); + memcpy(ct, obj->ct, nfct_maxsize()); if (nl_create_conntrack(STATE(dump), ct) == -1) { dlog(LOG_ERR, "cache_wt create: %s", strerror(errno)); - dlog_ct(STATE(log), u->ct, NFCT_O_PLAIN); + dlog_ct(STATE(log), obj->ct, NFCT_O_PLAIN); } break; case 1: - memcpy(ct, u->ct, nfct_maxsize()); + memcpy(ct, obj->ct, nfct_maxsize()); if (nl_update_conntrack(STATE(dump), ct) == -1) { dlog(LOG_ERR, "cache_wt crt-upd: %s", strerror(errno)); - dlog_ct(STATE(log), u->ct, NFCT_O_PLAIN); + dlog_ct(STATE(log), obj->ct, NFCT_O_PLAIN); } break; } } -static void upd_wt(struct us_conntrack *u) +static void upd_wt(struct cache_object *obj) { char __ct[nfct_maxsize()]; struct nf_conntrack *ct = (struct nf_conntrack *)(void*) __ct; - memcpy(ct, u->ct, nfct_maxsize()); + memcpy(ct, obj->ct, nfct_maxsize()); if (nl_update_conntrack(STATE(dump), ct) == -1) { dlog(LOG_ERR, "cache_wt update:%s", strerror(errno)); - dlog_ct(STATE(log), u->ct, NFCT_O_PLAIN); + dlog_ct(STATE(log), obj->ct, NFCT_O_PLAIN); } } -static void writethrough_add(struct us_conntrack *u, void *data) +static void writethrough_add(struct cache_object *obj, void *data) { - add_wt(u); + add_wt(obj); } -static void writethrough_update(struct us_conntrack *u, void *data) +static void writethrough_update(struct cache_object *obj, void *data) { - upd_wt(u); + upd_wt(obj); } -static void writethrough_destroy(struct us_conntrack *u, void *data) +static void writethrough_destroy(struct cache_object *obj, void *data) { - nl_destroy_conntrack(STATE(dump), u->ct); + nl_destroy_conntrack(STATE(dump), obj->ct); } struct cache_feature writethrough_feature = { diff --git a/src/filter.c b/src/filter.c index c6e24a9..6a09c77 100644 --- a/src/filter.c +++ b/src/filter.c @@ -58,15 +58,17 @@ static uint32_t ct_filter_hash6(const void *data, const struct hashtable *table) static int ct_filter_compare(const void *data1, const void *data2) { - const uint32_t *f1 = data1; + const struct ct_filter_ipv4_hnode *f1 = data1; const uint32_t *f2 = data2; - return *f1 == *f2; + return f1->ip == *f2; } static int ct_filter_compare6(const void *data1, const void *data2) { - return memcmp(data1, data2, sizeof(uint32_t)*4) == 0; + const struct ct_filter_ipv6_hnode *f = data1; + + return memcmp(f->ipv6, data2, sizeof(uint32_t)*4) == 0; } struct ct_filter *ct_filter_create(void) @@ -80,7 +82,6 @@ struct ct_filter *ct_filter_create(void) filter->h = hashtable_create(FILTER_POOL_SIZE, FILTER_POOL_LIMIT, - sizeof(uint32_t), ct_filter_hash, ct_filter_compare); if (!filter->h) { @@ -90,7 +91,6 @@ struct ct_filter *ct_filter_create(void) filter->h6 = hashtable_create(FILTER_POOL_SIZE, FILTER_POOL_LIMIT, - sizeof(uint32_t)*4, ct_filter_hash6, ct_filter_compare6); if (!filter->h6) { @@ -155,16 +155,33 @@ void ct_filter_set_logic(struct ct_filter *filter, int ct_filter_add_ip(struct ct_filter *filter, void *data, uint8_t family) { + int id; filter = __filter_alloc(filter); switch(family) { case AF_INET: - if (!hashtable_add(filter->h, data)) + id = hashtable_hash(filter->h, data); + if (!hashtable_find(filter->h, data, id)) { + struct ct_filter_ipv4_hnode *n; + n = malloc(sizeof(struct ct_filter_ipv4_hnode)); + if (n == NULL) + return 0; + memcpy(&n->ip, data, sizeof(uint32_t)); + hashtable_add(filter->h, &n->node, id); return 0; + } break; case AF_INET6: - if (!hashtable_add(filter->h6, data)) + id = hashtable_hash(filter->h6, data); + if (!hashtable_find(filter->h6, data, id)) { + struct ct_filter_ipv6_hnode *n; + n = malloc(sizeof(struct ct_filter_ipv6_hnode)); + if (n == NULL) + return 0; + memcpy(n->ipv6, data, sizeof(uint32_t)*4); + hashtable_add(filter->h6, &n->node, id); return 0; + } break; } return 1; @@ -220,16 +237,34 @@ void ct_filter_add_state(struct ct_filter *f, int protonum, int val) static inline int __ct_filter_test_ipv4(struct ct_filter *f, struct nf_conntrack *ct) { + int id_src, id_dst; + uint32_t src, dst; + /* we only use the real source and destination address */ - return (hashtable_find(f->h, nfct_get_attr(ct, ATTR_ORIG_IPV4_SRC)) || - hashtable_find(f->h, nfct_get_attr(ct, ATTR_REPL_IPV4_SRC))); + src = nfct_get_attr_u32(ct, ATTR_ORIG_IPV4_SRC); + dst = nfct_get_attr_u32(ct, ATTR_REPL_IPV4_SRC); + + id_src = hashtable_hash(f->h, &src); + id_dst = hashtable_hash(f->h, &dst); + + return hashtable_find(f->h, &src, id_src) || + hashtable_find(f->h, &dst, id_dst); } static inline int __ct_filter_test_ipv6(struct ct_filter *f, struct nf_conntrack *ct) { - return (hashtable_find(f->h6, nfct_get_attr(ct, ATTR_ORIG_IPV6_SRC)) || - hashtable_find(f->h6, nfct_get_attr(ct, ATTR_REPL_IPV6_SRC))); + int id_src, id_dst; + const uint32_t *src, *dst; + + src = nfct_get_attr(ct, ATTR_ORIG_IPV6_SRC); + dst = nfct_get_attr(ct, ATTR_REPL_IPV6_SRC); + + id_src = hashtable_hash(f->h6, src); + id_dst = hashtable_hash(f->h6, dst); + + return hashtable_find(f->h6, src, id_src) || + hashtable_find(f->h6, dst, id_dst); } static int diff --git a/src/hash.c b/src/hash.c index 1edb977..9c9ea5b 100644 --- a/src/hash.c +++ b/src/hash.c @@ -1,5 +1,5 @@ /* - * (C) 2006-2007 by Pablo Neira Ayuso + * (C) 2006-2009 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 @@ -19,32 +19,13 @@ */ #include "hash.h" -#include "slist.h" #include #include #include -struct hashtable_node *hashtable_alloc_node(int datasize, void *data) -{ - struct hashtable_node *n; - int size = sizeof(struct hashtable_node) + datasize; - - n = calloc(size, 1); - if (n == NULL) - return NULL; - memcpy(n->data, data, datasize); - - return n; -} - -void hashtable_destroy_node(struct hashtable_node *h) -{ - free(h); -} - struct hashtable * -hashtable_create(int hashsize, int limit, int datasize, +hashtable_create(int hashsize, int limit, uint32_t (*hash)(const void *data, const struct hashtable *table), int (*compare)(const void *data1, const void *data2)) @@ -52,7 +33,7 @@ hashtable_create(int hashsize, int limit, int datasize, int i; struct hashtable *h; int size = sizeof(struct hashtable) - + hashsize * sizeof(struct slist_head); + + hashsize * sizeof(struct list_head); h = (struct hashtable *) calloc(size, 1); if (h == NULL) { @@ -61,11 +42,10 @@ hashtable_create(int hashsize, int limit, int datasize, } for (i=0; imembers[i]); + INIT_LIST_HEAD(&h->members[i]); h->hashsize = hashsize; h->limit = limit; - h->datasize = datasize; h->hash = hash; h->compare = compare; @@ -74,112 +54,74 @@ hashtable_create(int hashsize, int limit, int datasize, void hashtable_destroy(struct hashtable *h) { - hashtable_flush(h); free(h); } -void *hashtable_add(struct hashtable *table, void *data) +int hashtable_hash(const struct hashtable *table, const void *data) { - struct slist_head *e; - struct hashtable_node *n; - uint32_t id; - - /* hash table is full */ - if (table->count >= table->limit) { - errno = ENOSPC; - return NULL; - } - - id = table->hash(data, table); - - slist_for_each(e, &table->members[id]) { - n = slist_entry(e, struct hashtable_node, head); - if (table->compare(n->data, data)) { - errno = EEXIST; - return NULL; - } - } - - n = hashtable_alloc_node(table->datasize, data); - if (n == NULL) { - errno = ENOMEM; - return NULL; - } - - slist_add(&table->members[id], &n->head); - table->count++; - - return n->data; + return table->hash(data, table); } -void *hashtable_find(struct hashtable *table, const void *data) +struct hashtable_node * +hashtable_find(const struct hashtable *table, const void *data, int id) { - struct slist_head *e; - uint32_t id; + struct list_head *e; struct hashtable_node *n; - id = table->hash(data, table); - - slist_for_each(e, &table->members[id]) { - n = slist_entry(e, struct hashtable_node, head); - if (table->compare(n->data, data)) - return n->data; + list_for_each(e, &table->members[id]) { + n = list_entry(e, struct hashtable_node, head); + if (table->compare(n, data)) { + return n; + } } - errno = ENOENT; return NULL; } -int hashtable_del(struct hashtable *table, void *data) +int hashtable_add(struct hashtable *table, struct hashtable_node *n, int id) { - struct slist_head *e, *next, *prev; - uint32_t id; - struct hashtable_node *n; - - id = table->hash(data, table); - - slist_for_each_safe(e, prev, next, &table->members[id]) { - n = slist_entry(e, struct hashtable_node, head); - if (table->compare(n->data, data)) { - slist_del(e, prev); - hashtable_destroy_node(n); - table->count--; - return 0; - } + /* hash table is full */ + if (table->count >= table->limit) { + errno = ENOSPC; + return -1; } - errno = ENOENT; - return -1; + list_add(&n->head, &table->members[id]); + table->count++; + return 0; +} + +void hashtable_del(struct hashtable *table, struct hashtable_node *n) +{ + list_del(&n->head); + table->count--; } int hashtable_flush(struct hashtable *table) { uint32_t i; - struct slist_head *e, *next, *prev; + struct list_head *e, *tmp; struct hashtable_node *n; - for (i=0; i < table->hashsize; i++) - slist_for_each_safe(e, prev, next, &table->members[i]) { - n = slist_entry(e, struct hashtable_node, head); - slist_del(e, prev); - hashtable_destroy_node(n); + for (i=0; i < table->hashsize; i++) { + list_for_each_safe(e, tmp, &table->members[i]) { + n = list_entry(e, struct hashtable_node, head); + free(n); } - - table->count = 0; - + } return 0; } int hashtable_iterate(struct hashtable *table, void *data, - int (*iterate)(void *data1, void *data2)) + int (*iterate)(void *data1, struct hashtable_node *n)) { uint32_t i; - struct slist_head *e, *next, *prev; + struct list_head *e, *tmp; struct hashtable_node *n; for (i=0; i < table->hashsize; i++) { - slist_for_each_safe(e, prev, next, &table->members[i]) { - n = slist_entry(e, struct hashtable_node, head); - if (iterate(data, n->data) == -1) + list_for_each_safe(e, tmp, &table->members[i]) { + n = list_entry(e, struct hashtable_node, head); + if (iterate(data, n) == -1) return -1; } } diff --git a/src/stats-mode.c b/src/stats-mode.c index d340b0d..679a50c 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -22,7 +22,6 @@ #include "cache.h" #include "log.h" #include "conntrackd.h" -#include "us-conntrack.h" #include #include @@ -118,9 +117,8 @@ static int overrun_stats(enum nf_conntrack_msg_type type, nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); nfct_attr_unset(ct, ATTR_USE); - if (!cache_test(STATE_STATS(cache), ct)) - if (!cache_update_force(STATE_STATS(cache), ct)) - debug_ct(ct, "overrun stats resync"); + if (!cache_update_force(STATE_STATS(cache), ct)) + debug_ct(ct, "overrun stats resync"); return NFCT_CB_CONTINUE; } @@ -128,12 +126,13 @@ static int overrun_stats(enum nf_conntrack_msg_type type, static int purge_step(void *data1, void *data2) { int ret; - struct us_conntrack *u = data2; + struct cache_object *obj = data2; - ret = nfct_query(STATE(dump), NFCT_Q_GET, u->ct); + ret = nfct_query(STATE(dump), NFCT_Q_GET, obj->ct); if (ret == -1 && errno == ENOENT) { - debug_ct(u->ct, "overrun purge stats"); - cache_del(STATE_STATS(cache), u->ct); + debug_ct(obj->ct, "overrun purge stats"); + cache_del(STATE_STATS(cache), obj); + cache_object_free(obj); } return 0; @@ -148,42 +147,46 @@ static int purge_stats(void) static void event_new_stats(struct nf_conntrack *ct) { + int id; + struct cache_object *obj; + nfct_attr_unset(ct, ATTR_TIMEOUT); - if (cache_add(STATE_STATS(cache), ct)) { - debug_ct(ct, "cache new"); - } else { - if (errno != EEXIST) { - dlog(LOG_ERR, - "can't add to cache cache: %s\n", strerror(errno)); - debug_ct(ct, "can't add"); + obj = cache_find(STATE_STATS(cache), ct, &id); + if (obj == NULL) { + obj = cache_object_new(STATE_STATS(cache), ct); + if (obj == NULL) + return; + + if (cache_add(STATE_STATS(cache), obj, id) == -1) { + cache_object_free(obj); + return; } } + return; } static void event_update_stats(struct nf_conntrack *ct) { nfct_attr_unset(ct, ATTR_TIMEOUT); - - if (!cache_update_force(STATE_STATS(cache), ct)) { - debug_ct(ct, "can't update"); - return; - } - debug_ct(ct, "update"); + cache_update_force(STATE_STATS(cache), ct); } static int event_destroy_stats(struct nf_conntrack *ct) { + int id; + struct cache_object *obj; + nfct_attr_unset(ct, ATTR_TIMEOUT); - if (cache_del(STATE_STATS(cache), ct)) { - debug_ct(ct, "cache destroy"); + obj = cache_find(STATE_STATS(cache), ct, &id); + if (obj) { + cache_del(STATE_STATS(cache), obj); dlog_ct(STATE(stats_log), ct, NFCT_O_PLAIN); + cache_object_free(obj); return 1; - } else { - debug_ct(ct, "can't destroy!"); - return 0; } + return 0; } struct ct_mode stats_mode = { diff --git a/src/sync-alarm.c b/src/sync-alarm.c index d871b75..34937fe 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -19,7 +19,6 @@ #include "conntrackd.h" #include "sync.h" #include "network.h" -#include "us-conntrack.h" #include "alarm.h" #include "cache.h" #include "debug.h" @@ -30,40 +29,40 @@ static void refresher(struct alarm_block *a, void *data) { struct nethdr *net; - struct us_conntrack *u = data; + struct cache_object *obj = data; - debug_ct(u->ct, "persistence update"); + debug_ct(obj->ct, "persistence update"); add_alarm(a, random() % CONFIG(refresh) + 1, ((random() % 5 + 1) * 200000) - 1); - net = BUILD_NETMSG(u->ct, NET_T_STATE_UPD); + net = BUILD_NETMSG(obj->ct, NET_T_STATE_UPD); mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); } -static void cache_alarm_add(struct us_conntrack *u, void *data) +static void cache_alarm_add(struct cache_object *obj, void *data) { - struct alarm_block *alarm = data; + struct alarm_block *a = data; - init_alarm(alarm, u, refresher); - add_alarm(alarm, + init_alarm(a, obj, refresher); + add_alarm(a, random() % CONFIG(refresh) + 1, ((random() % 5 + 1) * 200000) - 1); } -static void cache_alarm_update(struct us_conntrack *u, void *data) +static void cache_alarm_update(struct cache_object *obj, void *data) { - struct alarm_block *alarm = data; - add_alarm(alarm, + struct alarm_block *a = data; + add_alarm(a, random() % CONFIG(refresh) + 1, ((random() % 5 + 1) * 200000) - 1); } -static void cache_alarm_destroy(struct us_conntrack *u, void *data) +static void cache_alarm_destroy(struct cache_object *obj, void *data) { - struct alarm_block *alarm = data; - del_alarm(alarm); + struct alarm_block *a = data; + del_alarm(a); } static struct cache_extra cache_alarm_extra = { diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 44e8f2f..bddc18c 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -18,7 +18,6 @@ #include "conntrackd.h" #include "sync.h" -#include "us-conntrack.h" #include "queue.h" #include "debug.h" #include "network.h" @@ -64,7 +63,7 @@ struct cache_ftfw { uint32_t seq; }; -static void cache_ftfw_add(struct us_conntrack *u, void *data) +static void cache_ftfw_add(struct cache_object *obj, void *data) { struct cache_ftfw *cn = data; /* These nodes are not inserted in the list */ @@ -72,7 +71,7 @@ static void cache_ftfw_add(struct us_conntrack *u, void *data) INIT_LIST_HEAD(&cn->tx_list); } -static void cache_ftfw_del(struct us_conntrack *u, void *data) +static void cache_ftfw_del(struct cache_object *obj, void *data) { struct cache_ftfw *cn = data; @@ -190,8 +189,8 @@ static void ftfw_kill(void) static int do_cache_to_tx(void *data1, void *data2) { - struct us_conntrack *u = data2; - struct cache_ftfw *cn = cache_get_extra(STATE_SYNC(internal), u); + struct cache_object *obj = data2; + struct cache_ftfw *cn = cache_get_extra(STATE_SYNC(internal), obj); /* repeated request for resync? */ if (!list_empty(&cn->tx_list)) @@ -226,9 +225,6 @@ static void debug_rs_dump(int fd) size = sprintf(buf, "resent list (len=%u):\n", rs_list_len); send(fd, buf, size, 0); list_for_each_entry_safe(cn, tmp, &rs_list, rs_list) { - struct us_conntrack *u; - - u = cache_get_conntrack(STATE_SYNC(internal), cn); size = sprintf(buf, "seq:%u\n", cn->seq); send(fd, buf, size, 0); } @@ -305,9 +301,9 @@ static void rs_list_to_tx(struct cache *c, unsigned int from, unsigned int to) struct cache_ftfw *cn, *tmp; list_for_each_entry_safe(cn, tmp, &rs_list, rs_list) { - struct us_conntrack *u; + struct cache_object *obj;; - u = cache_get_conntrack(STATE_SYNC(internal), cn); + obj = cache_data_get_object(STATE_SYNC(internal), cn); if (before(cn->seq, from)) continue; else if (after(cn->seq, to)) @@ -330,9 +326,9 @@ static void rs_list_empty(struct cache *c, unsigned int from, unsigned int to) struct cache_ftfw *cn, *tmp; list_for_each_entry_safe(cn, tmp, &rs_list, rs_list) { - struct us_conntrack *u; + struct cache_object *obj; - u = cache_get_conntrack(STATE_SYNC(internal), cn); + obj = cache_data_get_object(STATE_SYNC(internal), cn); if (before(cn->seq, from)) continue; else if (after(cn->seq, to)) @@ -473,7 +469,7 @@ out: return ret; } -static void ftfw_send(struct nethdr *net, struct us_conntrack *u) +static void ftfw_send(struct nethdr *net, struct cache_object *obj) { struct cache_ftfw *cn; @@ -482,7 +478,7 @@ static void ftfw_send(struct nethdr *net, struct us_conntrack *u) case NET_T_STATE_UPD: case NET_T_STATE_DEL: cn = (struct cache_ftfw *) - cache_get_extra(STATE_SYNC(internal), u); + cache_get_extra(STATE_SYNC(internal), obj); if (!list_empty(&cn->rs_list)) { list_del_init(&cn->rs_list); @@ -538,10 +534,10 @@ static int tx_queue_xmit(void *data1, const void *data2) return 0; } -static int tx_list_xmit(struct list_head *i, struct us_conntrack *u, int type) +static int tx_list_xmit(struct list_head *i, struct cache_object *obj, int type) { int ret; - struct nethdr *net = BUILD_NETMSG(u->ct, type); + struct nethdr *net = BUILD_NETMSG(obj->ct, type); dp("tx_list sq: %u fl:%u len:%u\n", ntohl(net->seq), net->flags, ntohs(net->len)); @@ -550,7 +546,7 @@ static int tx_list_xmit(struct list_head *i, struct us_conntrack *u, int type) tx_list_len--; ret = mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); - ftfw_send(net, u); + ftfw_send(net, obj); return ret; } @@ -564,13 +560,13 @@ static void ftfw_run(void) /* send conntracks in the tx_list */ list_for_each_entry_safe(cn, tmp, &tx_list, tx_list) { - struct us_conntrack *u; + struct cache_object *obj; - u = cache_get_conntrack(STATE_SYNC(internal), cn); - if (alarm_pending(&u->alarm)) - tx_list_xmit(&cn->tx_list, u, NET_T_STATE_DEL); + obj = cache_data_get_object(STATE_SYNC(internal), cn); + if (alarm_pending(&obj->alarm)) + tx_list_xmit(&cn->tx_list, obj, NET_T_STATE_DEL); else - tx_list_xmit(&cn->tx_list, u, NET_T_STATE_UPD); + tx_list_xmit(&cn->tx_list, obj, NET_T_STATE_UPD); } /* reset alive alarm */ diff --git a/src/sync-mode.c b/src/sync-mode.c index ad2e2ff..368984f 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -22,7 +22,6 @@ #include "log.h" #include "cache.h" #include "conntrackd.h" -#include "us-conntrack.h" #include "network.h" #include "fds.h" #include "event.h" @@ -38,7 +37,8 @@ static void do_mcast_handler_step(struct nethdr *net, size_t remain) { char __ct[nfct_maxsize()]; struct nf_conntrack *ct = (struct nf_conntrack *)(void*) __ct; - struct us_conntrack *u; + struct cache_object *obj; + int id; if (net->version != CONNTRACKD_PROTOCOL_VERSION) { STATE_SYNC(error).msg_rcv_malformed++; @@ -75,33 +75,32 @@ static void do_mcast_handler_step(struct nethdr *net, size_t remain) switch(net->type) { case NET_T_STATE_NEW: -retry: - if ((u = cache_add(STATE_SYNC(external), ct))) { - debug_ct(u->ct, "external new"); - } else { - /* - * One certain connection A arrives to the cache but - * another existing connection B in the cache has - * the same configuration, therefore B clashes with A. - */ - if (errno == EEXIST) { - cache_del(STATE_SYNC(external), ct); - goto retry; + obj = cache_find(STATE_SYNC(external), ct, &id); + if (obj == NULL) { +retry: + obj = cache_object_new(STATE_SYNC(external), ct); + if (obj == NULL) + return; + + if (cache_add(STATE_SYNC(external), obj, id) == -1) { + cache_object_free(obj); + return; } - debug_ct(ct, "can't add"); + } else { + cache_del(STATE_SYNC(external), obj); + cache_object_free(obj); + goto retry; } break; case NET_T_STATE_UPD: - if ((u = cache_update_force(STATE_SYNC(external), ct))) { - debug_ct(u->ct, "external update"); - } else - debug_ct(ct, "can't update"); + cache_update_force(STATE_SYNC(external), ct); break; case NET_T_STATE_DEL: - if (cache_del(STATE_SYNC(external), ct)) - debug_ct(ct, "external destroy"); - else - debug_ct(ct, "can't destroy"); + obj = cache_find(STATE_SYNC(external), ct, &id); + if (obj) { + cache_del(STATE_SYNC(external), obj); + cache_object_free(obj); + } break; default: STATE_SYNC(error).msg_rcv_malformed++; @@ -441,14 +440,14 @@ static void dump_sync(struct nf_conntrack *ct) debug_ct(ct, "resync"); } -static void mcast_send_sync(struct us_conntrack *u, int query) +static void mcast_send_sync(struct cache_object *obj, int query) { struct nethdr *net; - net = BUILD_NETMSG(u->ct, query); + net = BUILD_NETMSG(obj->ct, query); if (STATE_SYNC(sync)->send) - STATE_SYNC(sync)->send(net, u); + STATE_SYNC(sync)->send(net, obj); mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); } @@ -457,13 +456,13 @@ static int purge_step(void *data1, void *data2) { int ret; struct nfct_handle *h = STATE(dump); - struct us_conntrack *u = data2; + struct cache_object *obj = data2; - ret = nfct_query(h, NFCT_Q_GET, u->ct); + ret = nfct_query(h, NFCT_Q_GET, obj->ct); if (ret == -1 && errno == ENOENT) { - debug_ct(u->ct, "overrun purge resync"); - mcast_send_sync(u, NET_T_STATE_DEL); - __cache_del_timer(STATE_SYNC(internal), u, CONFIG(del_timeout)); + debug_ct(obj->ct, "overrun purge resync"); + mcast_send_sync(obj, NET_T_STATE_DEL); + cache_del_timer(STATE_SYNC(internal), obj, CONFIG(del_timeout)); } return 0; @@ -480,7 +479,7 @@ static int overrun_sync(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data) { - struct us_conntrack *u; + struct cache_object *obj; if (ct_filter_conntrack(ct, 1)) return NFCT_CB_CONTINUE; @@ -492,11 +491,9 @@ static int overrun_sync(enum nf_conntrack_msg_type type, nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); nfct_attr_unset(ct, ATTR_USE); - if (!cache_test(STATE_SYNC(internal), ct)) { - if ((u = cache_update_force(STATE_SYNC(internal), ct))) { - debug_ct(u->ct, "overrun resync"); - mcast_send_sync(u, NET_T_STATE_UPD); - } + if ((obj = cache_update_force(STATE_SYNC(internal), ct))) { + debug_ct(obj->ct, "overrun resync"); + mcast_send_sync(obj, NET_T_STATE_UPD); } return NFCT_CB_CONTINUE; @@ -504,50 +501,59 @@ static int overrun_sync(enum nf_conntrack_msg_type type, static void event_new_sync(struct nf_conntrack *ct) { - struct us_conntrack *u; + struct cache_object *obj; + int id; /* required by linux kernel <= 2.6.20 */ nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES); nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS); nfct_attr_unset(ct, ATTR_REPL_COUNTER_BYTES); nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); + + obj = cache_find(STATE_SYNC(internal), ct, &id); + if (obj == NULL) { retry: - if ((u = cache_add(STATE_SYNC(internal), ct))) { - mcast_send_sync(u, NET_T_STATE_NEW); - debug_ct(u->ct, "internal new"); - } else { - if (errno == EEXIST) { - cache_del(STATE_SYNC(internal), ct); - goto retry; + obj = cache_object_new(STATE_SYNC(internal), ct); + if (obj == NULL) + return; + if (cache_add(STATE_SYNC(internal), obj, id) == -1) { + cache_object_free(obj); + return; } + mcast_send_sync(obj, NET_T_STATE_NEW); + debug_ct(obj->ct, "internal new"); + } else { + cache_del(STATE_SYNC(internal), obj); + cache_object_free(obj); debug_ct(ct, "can't add"); + goto retry; } } static void event_update_sync(struct nf_conntrack *ct) { - struct us_conntrack *u; + struct cache_object *obj; - if ((u = cache_update_force(STATE_SYNC(internal), ct)) == NULL) { + if ((obj = cache_update_force(STATE_SYNC(internal), ct)) == NULL) { debug_ct(ct, "can't update"); return; } - debug_ct(u->ct, "internal update"); - mcast_send_sync(u, NET_T_STATE_UPD); + debug_ct(obj->ct, "internal update"); + mcast_send_sync(obj, NET_T_STATE_UPD); } static int event_destroy_sync(struct nf_conntrack *ct) { - struct us_conntrack *u; + struct cache_object *obj; + int id; - u = cache_find(STATE_SYNC(internal), ct); - if (u == NULL) { + obj = cache_find(STATE_SYNC(internal), ct, &id); + if (obj == NULL) { debug_ct(ct, "can't destroy"); return 0; } - - mcast_send_sync(u, NET_T_STATE_DEL); - __cache_del_timer(STATE_SYNC(internal), u, CONFIG(del_timeout)); + mcast_send_sync(obj, NET_T_STATE_DEL); + cache_del_timer(STATE_SYNC(internal), obj, CONFIG(del_timeout)); debug_ct(ct, "internal destroy"); return 1; } diff --git a/src/sync-notrack.c b/src/sync-notrack.c index 700e272..2d3783e 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -18,7 +18,6 @@ #include "conntrackd.h" #include "sync.h" -#include "us-conntrack.h" #include "queue.h" #include "debug.h" #include "network.h" @@ -36,13 +35,13 @@ struct cache_notrack { struct list_head tx_list; }; -static void cache_notrack_add(struct us_conntrack *u, void *data) +static void cache_notrack_add(struct cache_object *obj, void *data) { struct cache_notrack *cn = data; INIT_LIST_HEAD(&cn->tx_list); } -static void cache_notrack_del(struct us_conntrack *u, void *data) +static void cache_notrack_del(struct cache_object *obj, void *data) { struct cache_notrack *cn = data; @@ -89,8 +88,8 @@ static void notrack_kill(void) static int do_cache_to_tx(void *data1, void *data2) { - struct us_conntrack *u = data2; - struct cache_notrack *cn = cache_get_extra(STATE_SYNC(internal), u); + struct cache_object *obj = data2; + struct cache_notrack *cn = cache_get_extra(STATE_SYNC(internal), obj); if (!list_empty(&cn->tx_list)) return 0; @@ -164,10 +163,10 @@ static int tx_queue_xmit(void *data1, const void *data2) return 0; } -static int tx_list_xmit(struct list_head *i, struct us_conntrack *u, int type) +static int tx_list_xmit(struct list_head *i, struct cache_object *obj, int type) { int ret; - struct nethdr *net = BUILD_NETMSG(u->ct, type); + struct nethdr *net = BUILD_NETMSG(obj->ct, type); list_del_init(i); tx_list_len--; @@ -186,10 +185,10 @@ static void notrack_run(void) /* send conntracks in the tx_list */ list_for_each_entry_safe(cn, tmp, &tx_list, tx_list) { - struct us_conntrack *u; + struct cache_object *obj; - u = cache_get_conntrack(STATE_SYNC(internal), cn); - tx_list_xmit(&cn->tx_list, u, NET_T_STATE_UPD); + obj = cache_data_get_object(STATE_SYNC(internal), cn); + tx_list_xmit(&cn->tx_list, obj, NET_T_STATE_UPD); } } -- cgit v1.2.3 From 8dce3504fde7da933dc6e7ecfeb99b4b45125f32 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 15 Jan 2009 23:19:58 +0100 Subject: cache: add status field to store the object status This patch adds the status field to the cache object. This avoids the (ab)use of the alarm to check if an entry is active or dead. This is the first step to possibly move the alarm to the cache_extra memory space of the ftfw (which is the only use by now). Signed-off-by: Pablo Neira Ayuso --- include/cache.h | 8 ++++++++ include/network.h | 1 + src/cache.c | 10 +++++++--- src/cache_iterators.c | 2 +- src/network.c | 13 +++++++++++++ 5 files changed, 30 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/include/cache.h b/include/cache.h index dcd6bcd..fd8e05f 100644 --- a/include/cache.h +++ b/include/cache.h @@ -23,11 +23,19 @@ enum { }; #define CACHE_MAX_FEATURE __CACHE_MAX_FEATURE +enum { + C_OBJ_NONE = 0, /* not in the cache */ + C_OBJ_NEW, /* just added to the cache */ + C_OBJ_ALIVE, /* in the cache, alive */ + C_OBJ_DEAD /* still in the cache, but dead */ +}; + struct cache; struct cache_object { struct hashtable_node hashnode; struct nf_conntrack *ct; struct cache *cache; + int status; struct alarm_block alarm; char data[0]; }; diff --git a/include/network.h b/include/network.h index 619ce3e..f02d920 100644 --- a/include/network.h +++ b/include/network.h @@ -30,6 +30,7 @@ int nethdr_size(int len); void nethdr_set(struct nethdr *net, int type); void nethdr_set_ack(struct nethdr *net); void nethdr_set_ctl(struct nethdr *net); +int object_status_to_network_type(int status); #define NETHDR_DATA(x) \ (struct netattr *)(((char *)x) + NETHDR_SIZ) diff --git a/src/cache.c b/src/cache.c index 621a3f4..c46498b 100644 --- a/src/cache.c +++ b/src/cache.c @@ -196,6 +196,7 @@ struct cache_object *cache_object_new(struct cache *c, struct nf_conntrack *ct) return NULL; } memcpy(obj->ct, ct, nfct_sizeof(ct)); + obj->status = C_OBJ_NONE; return obj; } @@ -225,6 +226,7 @@ static int __add(struct cache *c, struct cache_object *obj, int id) c->extra->add(obj, ((char *) obj) + c->extra_offset); c->stats.active++; + obj->status = C_OBJ_NEW; return 0; } @@ -260,6 +262,7 @@ void cache_update(struct cache *c, struct cache_object *obj, int id, c->extra->update(obj, ((char *) obj) + c->extra_offset); c->stats.upd_ok++; + obj->status = C_OBJ_ALIVE; } static void __del(struct cache *c, struct cache_object *obj) @@ -285,7 +288,7 @@ void cache_del(struct cache *c, struct cache_object *obj) * kill an entry was previously deleted via * __cache_del_timer. */ - if (!alarm_pending(&obj->alarm)) { + if (obj->status != C_OBJ_DEAD) { c->stats.del_ok++; c->stats.active--; } @@ -301,7 +304,7 @@ cache_update_force(struct cache *c, struct nf_conntrack *ct) obj = cache_find(c, ct, &id); if (obj) { - if (!alarm_pending(&obj->alarm)) { + if (obj->status != C_OBJ_DEAD) { cache_update(c, obj, id, ct); return obj; } else { @@ -333,7 +336,8 @@ int cache_del_timer(struct cache *c, struct cache_object *obj, int timeout) cache_object_free(obj); return 1; } - if (!alarm_pending(&obj->alarm)) { + if (obj->status != C_OBJ_DEAD) { + obj->status = C_OBJ_DEAD; add_alarm(&obj->alarm, timeout, 0); /* * increase stats even if this entry was not really diff --git a/src/cache_iterators.c b/src/cache_iterators.c index 4773889..ab6a461 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -51,7 +51,7 @@ static int do_dump(void *data1, struct hashtable_node *n) * specific and it breaks conntrackd modularity. Probably * there's a nicer way to do this but until I come up with it... */ - if (CONFIG(flags) & CTD_SYNC_FTFW && alarm_pending(&obj->alarm)) + if (CONFIG(flags) & CTD_SYNC_FTFW && obj->status == C_OBJ_DEAD) return 0; /* do not show cached timeout, this may confuse users */ diff --git a/src/network.c b/src/network.c index 598195f..320cdea 100644 --- a/src/network.c +++ b/src/network.c @@ -177,3 +177,16 @@ int mcast_track_is_seq_set() { return local_seq_set; } + +#include "cache.h" + +static int status2type[] = { + [C_OBJ_NEW] = NET_T_STATE_NEW, + [C_OBJ_ALIVE] = NET_T_STATE_UPD, + [C_OBJ_DEAD] = NET_T_STATE_DEL, +}; + +int object_status_to_network_type(int status) +{ + return status2type[status]; +} -- cgit v1.2.3 From 2cacd3a802510bde43e23cf4c7d39f51a2eaf460 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 15 Jan 2009 23:19:58 +0100 Subject: run: relax resynchronization algorithm when netlink overruns This patch relaxes the current approach when netlink reports overruns. There are two situations that can trigger a resynchronization with the kernel conntrack table: a) Netlink overruns because the receiver buffer is too small: increasing the netlink buffer size and schedule a resync with the kernel table conntrack to resolve the inconsistency. The sysadmin would notice in the logs and will try to set a bigger buffer in the configuration file. b) The system is under heavy workload (CPU is too busy): we should avoid resync with the kernel table since this is an expensive operation. We do our best here and keep replicating as much states as possible. If CPU consumption lowers at some point, the we will try to resync ourselves. This patch reduces the chances to resynchronize with the kernel conntrack table unless that two overruns do not happen in an internal of 30 seconds. Signed-off-by: Pablo Neira Ayuso --- src/run.c | 38 +++++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/run.c b/src/run.c index caf0b38..2e373ce 100644 --- a/src/run.c +++ b/src/run.c @@ -207,7 +207,7 @@ void local_handler(int fd, void *data) static void do_overrun_alarm(struct alarm_block *a, void *data) { nl_overrun_request_resync(STATE(overrun)); - add_alarm(&STATE(overrun_alarm), 2, 0); + STATE(stats).nl_kernel_table_resync++; } static int event_handler(enum nf_conntrack_msg_type type, @@ -378,6 +378,9 @@ init(void) return 0; } +/* interval of 30s. for between two overrun */ +#define OVRUN_INT 30 + static void __run(struct timeval *next_alarm) { int ret; @@ -406,15 +409,33 @@ static void __run(struct timeval *next_alarm) if (ret == -1) { switch(errno) { case ENOBUFS: - /* - * It seems that ctnetlink can't back off, - * it's likely that we're losing events. - * Solution: duplicate the socket buffer - * size and resync with master conntrack table. + /* We have hit ENOBUFS, it's likely that we are + * losing events. Two possible situations may + * trigger this error: + * + * 1) The netlink receiver buffer is too small: + * increasing the netlink buffer size should + * be enough. However, some event messages + * got lost. We have to resync ourselves + * with the kernel table conntrack table to + * resolve the inconsistency. + * + * 2) The receiver is too slow to process the + * netlink messages so that the queue gets + * full quickly. This generally happens + * if the system is under heavy workload + * (busy CPU). In this case, increasing the + * size of the netlink receiver buffer + * would not help anymore since we would + * be delaying the overrun. Moreover, we + * should avoid resynchronizations. We + * should do our best here and keep + * replicating as much states as possible. + * If workload lowers at some point, + * we resync ourselves. */ nl_resize_socket_buffer(STATE(event)); - nl_overrun_request_resync(STATE(overrun)); - add_alarm(&STATE(overrun_alarm), 2, 0); + add_alarm(&STATE(overrun_alarm), OVRUN_INT, 0); STATE(stats).nl_catch_event_failed++; STATE(stats).nl_overrun++; break; @@ -435,7 +456,6 @@ static void __run(struct timeval *next_alarm) } if (FD_ISSET(nfct_fd(STATE(overrun)), &readfds)) { - del_alarm(&STATE(overrun_alarm)); nfct_catch(STATE(overrun)); if (STATE(mode)->purge) STATE(mode)->purge(); -- cgit v1.2.3 From e2af183ea7e5ea35a1582f40a01a7c49e83b31be Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 15 Jan 2009 23:19:58 +0100 Subject: sync: unify tx_list and tx_queue into one single tx_queue This patch unifies the tx_list and the tx_queue to have only one transmission queue. Since the tx_list hold state objects and tx_queue control messages, I have introduced a queue node type that can be used to differenciate the kind of information that the node stores: object or control message. This patch also reworks the existing queue class to include a file descriptor that can be used to know if there are new data added to the queue (see QUEUE_F_EVFD flag). In this change, I have also modified the current evfd to make the file descriptor to make read operations non-blocking. Moreover, it keeps a counter that is used to know how many messages are inserted in the queue. Signed-off-by: Pablo Neira Ayuso --- include/conntrackd.h | 1 - include/queue.h | 51 +++++-- include/sync.h | 6 +- src/event.c | 20 +-- src/queue.c | 124 +++++++++-------- src/sync-ftfw.c | 367 ++++++++++++++++++++++++--------------------------- src/sync-mode.c | 20 +-- src/sync-notrack.c | 114 ++++++++-------- 8 files changed, 360 insertions(+), 343 deletions(-) (limited to 'src') diff --git a/include/conntrackd.h b/include/conntrackd.h index 67397b8..8cb520d 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -150,7 +150,6 @@ struct ct_sync_state { struct mcast_sock *mcast_server; /* multicast socket: incoming */ struct mcast_sock *mcast_client; /* multicast socket: outgoing */ - struct evfd *evfd; /* event fd */ struct sync_mode *sync; /* sync mode */ diff --git a/include/queue.h b/include/queue.h index 5a9cf39..ef56323 100644 --- a/include/queue.h +++ b/include/queue.h @@ -1,28 +1,53 @@ #ifndef _QUEUE_H_ #define _QUEUE_H_ +#include #include "linux_list.h" -struct queue { - size_t max_size; - size_t cur_size; - unsigned int num_elems; - struct list_head head; +struct queue_node { + struct list_head head; + uint32_t type; + struct queue *owner; + size_t size; }; -struct queue_node { - struct list_head head; - size_t size; - char data[0]; +enum { + Q_ELEM_OBJ = 0, + Q_ELEM_CTL = 1 +}; + +void queue_node_init(struct queue_node *n, int type); +void *queue_node_data(struct queue_node *n); + +struct queue_object { + struct queue_node qnode; + char data[0]; }; -struct queue *queue_create(size_t max_size); +struct queue_object *queue_object_new(int type, size_t size); +void queue_object_free(struct queue_object *obj); + +struct evfd; + +struct queue { + unsigned int max_elems; + unsigned int num_elems; + uint32_t flags; + struct list_head head; + struct evfd *evfd; +}; + +#define QUEUE_F_EVFD (1U << 0) + +struct queue *queue_create(int max_objects, unsigned int flags); void queue_destroy(struct queue *b); unsigned int queue_len(const struct queue *b); -int queue_add(struct queue *b, const void *data, size_t size); -void queue_del(struct queue *b, void *data); +int queue_add(struct queue *b, struct queue_node *n); +int queue_del(struct queue_node *n); +int queue_in(struct queue *b, struct queue_node *n); void queue_iterate(struct queue *b, const void *data, - int (*iterate)(void *data1, const void *data2)); + int (*iterate)(struct queue_node *n, const void *data2)); +int queue_get_eventfd(struct queue *b); #endif diff --git a/include/sync.h b/include/sync.h index 60c9fae..9a9540c 100644 --- a/include/sync.h +++ b/include/sync.h @@ -1,8 +1,11 @@ #ifndef _SYNC_HOOKS_H_ #define _SYNC_HOOKS_H_ +#include + struct nethdr; struct cache_object; +struct fds; struct sync_mode { int internal_cache_flags; @@ -15,7 +18,8 @@ struct sync_mode { int (*local)(int fd, int type, void *data); int (*recv)(const struct nethdr *net); void (*send)(struct nethdr *net, struct cache_object *obj); - void (*run)(void); + void (*run)(fd_set *readfds); + int (*register_fds)(struct fds *fds); }; extern struct sync_mode sync_alarm; diff --git a/src/event.c b/src/event.c index ed78835..d1dfe72 100644 --- a/src/event.c +++ b/src/event.c @@ -17,6 +17,8 @@ */ #include #include +#include +#include #include "event.h" @@ -37,6 +39,7 @@ struct evfd *create_evfd(void) free(e); return NULL; } + fcntl(e->fds[0], F_SETFL, O_NONBLOCK); return e; } @@ -55,19 +58,20 @@ int get_read_evfd(struct evfd *evfd) int write_evfd(struct evfd *evfd) { - int data = 0; + int data = 0, ret = 0; - if (evfd->read) - return 0; + if (evfd->read == 0) + ret = write(evfd->fds[1], &data, sizeof(data)); + evfd->read++; - evfd->read = 1; - return write(evfd->fds[1], &data, sizeof(data)); + return ret; } int read_evfd(struct evfd *evfd) { - int data; + int data, ret = 0; - evfd->read = 0; - return read(evfd->fds[0], &data, sizeof(data)); + if (--evfd->read == 0) + ret = read(evfd->fds[0], &data, sizeof(data)); + return ret; } diff --git a/src/queue.c b/src/queue.c index cdd70ae..cffcc93 100644 --- a/src/queue.c +++ b/src/queue.c @@ -1,5 +1,5 @@ /* - * (C) 2006-2008 by Pablo Neira Ayuso + * (C) 2006-2009 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 @@ -17,110 +17,122 @@ */ #include "queue.h" +#include "event.h" #include #include #include -struct queue *queue_create(size_t max_size) +struct queue *queue_create(int max_objects, unsigned int flags) { struct queue *b; - b = malloc(sizeof(struct queue)); + b = calloc(sizeof(struct queue), 1); if (b == NULL) return NULL; - memset(b, 0, sizeof(struct queue)); - b->max_size = max_size; + b->max_elems = max_objects; INIT_LIST_HEAD(&b->head); + b->flags = flags; + + if (flags & QUEUE_F_EVFD) { + b->evfd = create_evfd(); + if (b->evfd == NULL) { + free(b); + return NULL; + } + } return b; } void queue_destroy(struct queue *b) { - struct list_head *i, *tmp; - struct queue_node *node; - - /* XXX: set cur_size and num_elems */ - list_for_each_safe(i, tmp, &b->head) { - node = (struct queue_node *) i; - list_del(i); - free(node); - } + if (b->flags & QUEUE_F_EVFD) + destroy_evfd(b->evfd); free(b); } -static struct queue_node *queue_node_create(const void *data, size_t size) +void queue_node_init(struct queue_node *n, int type) { - struct queue_node *n; + INIT_LIST_HEAD(&n->head); + n->type = type; +} - n = malloc(sizeof(struct queue_node) + size); - if (n == NULL) +void *queue_node_data(struct queue_node *n) +{ + return ((char *)n) + sizeof(struct queue_node); +} + +struct queue_object *queue_object_new(int type, size_t size) +{ + struct queue_object *obj; + + obj = calloc(sizeof(struct queue_object) + size, 1); + if (obj == NULL) return NULL; - n->size = size; - memcpy(n->data, data, size); + obj->qnode.size = size; + queue_node_init(&obj->qnode, type); - return n; + return obj; } -int queue_add(struct queue *b, const void *data, size_t size) +void queue_object_free(struct queue_object *obj) { - int ret = 0; - struct queue_node *n; - - /* does it fit this queue? */ - if (size > b->max_size) { - errno = ENOSPC; - ret = -1; - goto err; - } + free(obj); +} -retry: - /* queue is full: kill the oldest entry */ - if (b->cur_size + size > b->max_size) { - n = (struct queue_node *) b->head.prev; - list_del(b->head.prev); - b->cur_size -= n->size; - free(n); - goto retry; - } +int queue_add(struct queue *b, struct queue_node *n) +{ + if (!list_empty(&n->head)) + return 0; - n = queue_node_create(data, size); - if (n == NULL) { - ret = -1; - goto err; + if (b->num_elems >= b->max_elems) { + errno = ENOSPC; + return -1; } - + n->owner = b; list_add_tail(&n->head, &b->head); - b->cur_size += size; b->num_elems++; + if (b->evfd) + write_evfd(b->evfd); + return 1; +} -err: - return ret; +int queue_del(struct queue_node *n) +{ + if (list_empty(&n->head)) + return 0; + + list_del_init(&n->head); + n->owner->num_elems--; + if (n->owner->evfd) + read_evfd(n->owner->evfd); + n->owner = NULL; + return 1; } -void queue_del(struct queue *b, void *data) +int queue_in(struct queue *b, struct queue_node *n) { - struct queue_node *n = container_of(data, struct queue_node, data); + return b == n->owner; +} - list_del(&n->head); - b->cur_size -= n->size; - b->num_elems--; - free(n); +int queue_get_eventfd(struct queue *b) +{ + return get_read_evfd(b->evfd); } void queue_iterate(struct queue *b, const void *data, - int (*iterate)(void *data1, const void *data2)) + int (*iterate)(struct queue_node *n, const void *data2)) { struct list_head *i, *tmp; struct queue_node *n; list_for_each_safe(i, tmp, &b->head) { n = (struct queue_node *) i; - if (iterate(n->data, data)) + if (iterate(n, data)) break; } } diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index bddc18c..bb53849 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -24,7 +24,7 @@ #include "alarm.h" #include "log.h" #include "cache.h" -#include "event.h" +#include "fds.h" #include @@ -34,12 +34,8 @@ #define dp(...) #endif -static LIST_HEAD(rs_list); -static LIST_HEAD(tx_list); -static unsigned int rs_list_len; -static unsigned int tx_list_len; -static struct queue *rs_queue; -static struct queue *tx_queue; +struct queue *tx_queue; +struct queue *rs_queue; static uint32_t exp_seq; static uint32_t window; static uint32_t ack_from; @@ -58,8 +54,7 @@ static int say_hello_back; #define ALIVE_INT 1 struct cache_ftfw { - struct list_head rs_list; - struct list_head tx_list; + struct queue_node qnode; uint32_t seq; }; @@ -67,24 +62,13 @@ static void cache_ftfw_add(struct cache_object *obj, void *data) { struct cache_ftfw *cn = data; /* These nodes are not inserted in the list */ - INIT_LIST_HEAD(&cn->rs_list); - INIT_LIST_HEAD(&cn->tx_list); + queue_node_init(&cn->qnode, Q_ELEM_OBJ); } static void cache_ftfw_del(struct cache_object *obj, void *data) { struct cache_ftfw *cn = data; - - /* this node is already out of the list */ - if (!list_empty(&cn->rs_list)) { - /* no need for list_del_init since the entry is destroyed */ - list_del(&cn->rs_list); - rs_list_len--; - } - if (!list_empty(&cn->tx_list)) { - list_del(&cn->tx_list); - tx_list_len--; - } + queue_del(&cn->qnode); } static struct cache_extra cache_ftfw_extra = { @@ -95,54 +79,64 @@ static struct cache_extra cache_ftfw_extra = { static void tx_queue_add_ctlmsg(uint32_t flags, uint32_t from, uint32_t to) { - struct nethdr_ack ack = { - .type = NET_T_CTL, - .flags = flags, - .from = from, - .to = to, - }; + struct queue_object *qobj; + struct nethdr_ack *ack; + + qobj = queue_object_new(Q_ELEM_CTL, sizeof(struct nethdr_ack)); + if (qobj == NULL) + return; + + ack = (struct nethdr_ack *)qobj->data; + ack->type = NET_T_CTL; + ack->flags = flags; + ack->from = from; + ack->to = to; switch(hello_state) { case HELLO_INIT: hello_state = HELLO_SAY; /* fall through */ case HELLO_SAY: - ack.flags |= NET_F_HELLO; + ack->flags |= NET_F_HELLO; break; } if (say_hello_back) { - ack.flags |= NET_F_HELLO_BACK; + ack->flags |= NET_F_HELLO_BACK; say_hello_back = 0; } - queue_add(tx_queue, &ack, NETHDR_ACK_SIZ); - write_evfd(STATE_SYNC(evfd)); + queue_add(tx_queue, &qobj->qnode); } static void tx_queue_add_ctlmsg2(uint32_t flags) { - struct nethdr ctl = { - .type = NET_T_CTL, - .flags = flags, - }; + struct queue_object *qobj; + struct nethdr *ctl; + + qobj = queue_object_new(Q_ELEM_CTL, sizeof(struct nethdr_ack)); + if (qobj == NULL) + return; + + ctl = (struct nethdr *)qobj->data; + ctl->type = NET_T_CTL; + ctl->flags = flags; switch(hello_state) { case HELLO_INIT: hello_state = HELLO_SAY; /* fall through */ case HELLO_SAY: - ctl.flags |= NET_F_HELLO; + ctl->flags |= NET_F_HELLO; break; } if (say_hello_back) { - ctl.flags |= NET_F_HELLO_BACK; + ctl->flags |= NET_F_HELLO_BACK; say_hello_back = 0; } - queue_add(tx_queue, &ctl, NETHDR_SIZ); - write_evfd(STATE_SYNC(evfd)); + queue_add(tx_queue, &qobj->qnode); } /* this function is called from the alarm framework */ @@ -156,17 +150,18 @@ static void do_alive_alarm(struct alarm_block *a, void *data) ack_from_set = 0; } else tx_queue_add_ctlmsg2(NET_F_ALIVE); + + add_alarm(&alive_alarm, ALIVE_INT, 0); } static int ftfw_init(void) { - tx_queue = queue_create(CONFIG(resend_queue_size)); + tx_queue = queue_create(INT_MAX, QUEUE_F_EVFD); if (tx_queue == NULL) { dlog(LOG_ERR, "cannot create tx queue"); return -1; } - - rs_queue = queue_create(CONFIG(resend_queue_size)); + rs_queue = queue_create(INT_MAX, 0); if (rs_queue == NULL) { dlog(LOG_ERR, "cannot create rs queue"); return -1; @@ -192,45 +187,47 @@ static int do_cache_to_tx(void *data1, void *data2) struct cache_object *obj = data2; struct cache_ftfw *cn = cache_get_extra(STATE_SYNC(internal), obj); - /* repeated request for resync? */ - if (!list_empty(&cn->tx_list)) - return 0; + if (queue_in(rs_queue, &cn->qnode)) + queue_del(&cn->qnode); - /* add to tx list */ - list_add_tail(&cn->tx_list, &tx_list); - tx_list_len++; - write_evfd(STATE_SYNC(evfd)); + queue_add(tx_queue, &cn->qnode); return 0; } -static int debug_rs_queue_dump_step(void *data1, const void *data2) +static int rs_queue_dump(struct queue_node *n, const void *data2) { - struct nethdr_ack *net = data1; const int *fd = data2; char buf[512]; int size; - size = sprintf(buf, "seq:%u flags:%u\n", net->seq, net->flags); + switch(n->type) { + case Q_ELEM_CTL: { + struct nethdr *net = queue_node_data(n); + size = sprintf(buf, "control -> seq:%u flags:%u\n", + net->seq, net->flags); + break; + } + case Q_ELEM_OBJ: { + struct cache_ftfw *cn = (struct cache_ftfw *) n; + size = sprintf(buf, "object -> seq:%u\n", cn->seq); + break; + } + default: + return 0; + } send(*fd, buf, size, 0); return 0; } static void debug_rs_dump(int fd) { - struct cache_ftfw *cn, *tmp; char buf[512]; int size; - size = sprintf(buf, "resent list (len=%u):\n", rs_list_len); - send(fd, buf, size, 0); - list_for_each_entry_safe(cn, tmp, &rs_list, rs_list) { - size = sprintf(buf, "seq:%u\n", cn->seq); - send(fd, buf, size, 0); - } - size = sprintf(buf, "\nresent queue (len=%u):\n", queue_len(rs_queue)); + size = sprintf(buf, "resent queue (len=%u):\n", queue_len(rs_queue)); send(fd, buf, size, 0); - queue_iterate(rs_queue, &fd, debug_rs_queue_dump_step); + queue_iterate(rs_queue, &fd, rs_queue_dump); } static int ftfw_local(int fd, int type, void *data) @@ -257,87 +254,84 @@ static int ftfw_local(int fd, int type, void *data) return ret; } -static int rs_queue_to_tx(void *data1, const void *data2) +static int rs_queue_to_tx(struct queue_node *n, const void *data) { - struct nethdr_ack *net = data1; - const struct nethdr_ack *nack = data2; - - if (before(net->seq, nack->from)) - return 0; /* continue */ - else if (after(net->seq, nack->to)) - return 1; /* break */ - - dp("rs_queue_to_tx sq: %u fl:%u len:%u\n", - net->seq, net->flags, net->len); - queue_add(tx_queue, net, net->len); - write_evfd(STATE_SYNC(evfd)); - queue_del(rs_queue, net); - return 0; -} + const struct nethdr_ack *nack = data; -static int rs_queue_empty(void *data1, const void *data2) -{ - struct nethdr *net = data1; - const struct nethdr_ack *h = data2; + switch(n->type) { + case Q_ELEM_CTL: { + struct nethdr_ack *net = queue_node_data(n); - if (h == NULL) { - dp("inconditional remove from queue (seq=%u)\n", net->seq); - queue_del(rs_queue, data1); - return 0; + if (before(net->seq, nack->from)) + return 0; /* continue */ + else if (after(net->seq, nack->to)) + return 1; /* break */ + + dp("rs_queue_to_tx sq: %u fl:%u len:%u\n", + net->seq, net->flags, net->len); + + queue_del(n); + queue_add(tx_queue, n); + break; } + case Q_ELEM_OBJ: { + struct cache_ftfw *cn; - if (before(net->seq, h->from)) - return 0; /* continue */ - else if (after(net->seq, h->to)) - return 1; /* break */ + cn = (struct cache_ftfw *) n; + if (before(cn->seq, nack->from)) + return 0; + else if (after(cn->seq, nack->to)) + return 1; - dp("remove from queue (seq=%u)\n", net->seq); - queue_del(rs_queue, data1); + dp("resending nack'ed (oldseq=%u)\n", cn->seq); + + queue_del(n); + queue_add(tx_queue, n); + break; + } + } return 0; } -static void rs_list_to_tx(struct cache *c, unsigned int from, unsigned int to) +static int rs_queue_empty(struct queue_node *n, const void *data) { - struct cache_ftfw *cn, *tmp; + const struct nethdr_ack *h = data; - list_for_each_entry_safe(cn, tmp, &rs_list, rs_list) { - struct cache_object *obj;; - - obj = cache_data_get_object(STATE_SYNC(internal), cn); - if (before(cn->seq, from)) - continue; - else if (after(cn->seq, to)) - break; + if (h == NULL) { + dp("inconditional remove from queue (seq=%u)\n", net->seq); + queue_del(n); + return 0; + } - dp("resending nack'ed (oldseq=%u)\n", cn->seq); - list_del_init(&cn->rs_list); - rs_list_len--; - /* we received a request for resync before this nack? */ - if (list_empty(&cn->tx_list)) { - list_add_tail(&cn->tx_list, &tx_list); - tx_list_len++; - } - write_evfd(STATE_SYNC(evfd)); - } -} + switch(n->type) { + case Q_ELEM_CTL: { + struct nethdr_ack *net = queue_node_data(n); -static void rs_list_empty(struct cache *c, unsigned int from, unsigned int to) -{ - struct cache_ftfw *cn, *tmp; + if (before(net->seq, h->from)) + return 0; /* continue */ + else if (after(net->seq, h->to)) + return 1; /* break */ - list_for_each_entry_safe(cn, tmp, &rs_list, rs_list) { - struct cache_object *obj; + dp("remove from queue (seq=%u)\n", net->seq); + queue_del(n); + queue_object_free((struct queue_object *)n); + break; + } + case Q_ELEM_OBJ: { + struct cache_ftfw *cn; - obj = cache_data_get_object(STATE_SYNC(internal), cn); - if (before(cn->seq, from)) - continue; - else if (after(cn->seq, to)) - break; + cn = (struct cache_ftfw *) n; + if (before(cn->seq, h->from)) + return 0; + else if (after(cn->seq, h->to)) + return 1; dp("queue: deleting from queue (seq=%u)\n", cn->seq); - list_del_init(&cn->rs_list); - rs_list_len--; + queue_del(n); + break; } + } + return 0; } static int digest_msg(const struct nethdr *net) @@ -351,7 +345,6 @@ static int digest_msg(const struct nethdr *net) if (before(h->to, h->from)) return MSG_BAD; - rs_list_empty(STATE_SYNC(internal), h->from, h->to); queue_iterate(rs_queue, h, rs_queue_empty); return MSG_CTL; @@ -361,7 +354,6 @@ static int digest_msg(const struct nethdr *net) if (before(nack->to, nack->from)) return MSG_BAD; - rs_list_to_tx(STATE_SYNC(internal), nack->from, nack->to); queue_iterate(rs_queue, nack, rs_queue_to_tx); return MSG_CTL; @@ -409,7 +401,6 @@ static int ftfw_recv(const struct nethdr *net) * know anything about that data, we are unreliable until * the helloing finishes */ queue_iterate(rs_queue, NULL, rs_queue_empty); - rs_list_empty(STATE_SYNC(internal), 0, ~0U); goto bypass; } @@ -480,10 +471,8 @@ static void ftfw_send(struct nethdr *net, struct cache_object *obj) cn = (struct cache_ftfw *) cache_get_extra(STATE_SYNC(internal), obj); - if (!list_empty(&cn->rs_list)) { - list_del_init(&cn->rs_list); - rs_list_len--; - } + if (queue_in(rs_queue, &cn->qnode)) + queue_del(&cn->qnode); switch(hello_state) { case HELLO_INIT: @@ -500,82 +489,77 @@ static void ftfw_send(struct nethdr *net, struct cache_object *obj) } cn->seq = ntohl(net->seq); - list_add_tail(&cn->rs_list, &rs_list); - rs_list_len++; + queue_add(rs_queue, &cn->qnode); break; } } -static int tx_queue_xmit(void *data1, const void *data2) +static int tx_queue_xmit(struct queue_node *n, const void *data) { - struct nethdr *net = data1; - - if (IS_ACK(net) || IS_NACK(net) || IS_RESYNC(net)) { - nethdr_set_ack(net); - } else if (IS_ALIVE(net)) { - nethdr_set_ctl(net); - } else { - STATE_SYNC(error).msg_snd_malformed++; - return 0; - } - HDR_HOST2NETWORK(net); - - dp("tx_queue sq: %u fl:%u len:%u\n", - ntohl(net->seq), net->flags, ntohs(net->len)); - - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); - HDR_NETWORK2HOST(net); + switch(n->type) { + case Q_ELEM_CTL: { + struct nethdr *net = queue_node_data(n); + + if (IS_ACK(net) || IS_NACK(net) || IS_RESYNC(net)) { + nethdr_set_ack(net); + } else if (IS_ALIVE(net)) { + nethdr_set_ctl(net); + } else { + STATE_SYNC(error).msg_snd_malformed++; + return 0; + } + HDR_HOST2NETWORK(net); - if (IS_ACK(net) || IS_NACK(net) || IS_RESYNC(net)) - queue_add(rs_queue, net, net->len); + dp("tx_queue sq: %u fl:%u len:%u\n", + ntohl(net->seq), net->flags, ntohs(net->len)); - queue_del(tx_queue, net); + mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); + HDR_NETWORK2HOST(net); - return 0; -} - -static int tx_list_xmit(struct list_head *i, struct cache_object *obj, int type) -{ - int ret; - struct nethdr *net = BUILD_NETMSG(obj->ct, type); + queue_del(n); + if (IS_ACK(net) || IS_NACK(net) || IS_RESYNC(net)) + queue_add(rs_queue, n); + else + queue_object_free((struct queue_object *)n); + break; + } + case Q_ELEM_OBJ: { + struct cache_ftfw *cn; + struct cache_object *obj; + int type; + struct nethdr *net; - dp("tx_list sq: %u fl:%u len:%u\n", - ntohl(net->seq), net->flags, ntohs(net->len)); + cn = (struct cache_ftfw *)n; + obj = cache_data_get_object(STATE_SYNC(internal), cn); + type = object_status_to_network_type(obj->status); + net = BUILD_NETMSG(obj->ct, type); - list_del_init(i); - tx_list_len--; + dp("tx_list sq: %u fl:%u len:%u\n", + ntohl(net->seq), net->flags, ntohs(net->len)); - ret = mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); - ftfw_send(net, obj); + queue_del(n); + mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); + ftfw_send(net, obj); + break; + } + } - return ret; + return 0; } -static void ftfw_run(void) +static void ftfw_run(fd_set *readfds) { - struct cache_ftfw *cn, *tmp; - - /* send messages in the tx_queue */ - queue_iterate(tx_queue, NULL, tx_queue_xmit); - - /* send conntracks in the tx_list */ - list_for_each_entry_safe(cn, tmp, &tx_list, tx_list) { - struct cache_object *obj; - - obj = cache_data_get_object(STATE_SYNC(internal), cn); - if (alarm_pending(&obj->alarm)) - tx_list_xmit(&cn->tx_list, obj, NET_T_STATE_DEL); - else - tx_list_xmit(&cn->tx_list, obj, NET_T_STATE_UPD); + if (FD_ISSET(queue_get_eventfd(tx_queue), readfds)) { + queue_iterate(tx_queue, NULL, tx_queue_xmit); + add_alarm(&alive_alarm, 1, 0); + dp("tx_queue_len:%u rs_queue_len:%u\n", + queue_len(tx_queue), queue_len(rs_queue)); } +} - /* reset alive alarm */ - add_alarm(&alive_alarm, 1, 0); - - dp("tx_list_len:%u tx_queue_len:%u " - "rs_list_len: %u rs_queue_len:%u\n", - tx_list_len, queue_len(tx_queue), - rs_list_len, queue_len(rs_queue)); +static int ftfw_register_fds(struct fds *fds) +{ + return register_fd(queue_get_eventfd(tx_queue), fds); } struct sync_mode sync_ftfw = { @@ -588,4 +572,5 @@ struct sync_mode sync_ftfw = { .recv = ftfw_recv, .send = ftfw_send, .run = ftfw_run, + .register_fds = ftfw_register_fds, }; diff --git a/src/sync-mode.c b/src/sync-mode.c index 368984f..711f71b 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -242,12 +242,6 @@ static int init_sync(void) return -1; } - STATE_SYNC(evfd) = create_evfd(); - if (STATE_SYNC(evfd) == NULL) { - dlog(LOG_ERR, "cannot open evfd"); - return -1; - } - /* initialization of multicast sequence generation */ STATE_SYNC(last_seq_sent) = time(NULL); @@ -259,7 +253,10 @@ static int register_fds_sync(struct fds *fds) if (register_fd(STATE_SYNC(mcast_server->fd), fds) == -1) return -1; - return register_fd(get_read_evfd(STATE_SYNC(evfd)), fds); + if (STATE_SYNC(sync)->register_fds) + return STATE_SYNC(sync)->register_fds(fds); + + return 0; } static void run_sync(fd_set *readfds) @@ -268,11 +265,8 @@ static void run_sync(fd_set *readfds) if (FD_ISSET(STATE_SYNC(mcast_server->fd), readfds)) mcast_handler(); - if (FD_ISSET(get_read_evfd(STATE_SYNC(evfd)), readfds) && - STATE_SYNC(sync)->run) { - read_evfd(STATE_SYNC(evfd)); - STATE_SYNC(sync)->run(); - } + if (STATE_SYNC(sync)->run) + STATE_SYNC(sync)->run(readfds); /* flush pending messages */ mcast_buffered_pending_netmsg(STATE_SYNC(mcast_client)); @@ -286,8 +280,6 @@ static void kill_sync(void) mcast_server_destroy(STATE_SYNC(mcast_server)); mcast_client_destroy(STATE_SYNC(mcast_client)); - destroy_evfd(STATE_SYNC(evfd)); - mcast_buffered_destroy(); if (STATE_SYNC(sync)->kill) diff --git a/src/sync-notrack.c b/src/sync-notrack.c index 2d3783e..40cc199 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -23,32 +23,26 @@ #include "network.h" #include "log.h" #include "cache.h" -#include "event.h" +#include "fds.h" #include -static LIST_HEAD(tx_list); -static unsigned int tx_list_len; static struct queue *tx_queue; struct cache_notrack { - struct list_head tx_list; + struct queue_node qnode; }; static void cache_notrack_add(struct cache_object *obj, void *data) { struct cache_notrack *cn = data; - INIT_LIST_HEAD(&cn->tx_list); + queue_node_init(&cn->qnode, Q_ELEM_OBJ); } static void cache_notrack_del(struct cache_object *obj, void *data) { struct cache_notrack *cn = data; - - if (!list_empty(&cn->tx_list)) { - list_del(&cn->tx_list); - tx_list_len--; - } + queue_del(&cn->qnode); } static struct cache_extra cache_notrack_extra = { @@ -59,20 +53,25 @@ static struct cache_extra cache_notrack_extra = { static void tx_queue_add_ctlmsg(uint32_t flags, uint32_t from, uint32_t to) { - struct nethdr_ack ack = { - .type = NET_T_CTL, - .flags = flags, - .from = from, - .to = to, - }; - - queue_add(tx_queue, &ack, NETHDR_ACK_SIZ); - write_evfd(STATE_SYNC(evfd)); + struct queue_object *qobj; + struct nethdr_ack *ack; + + qobj = queue_object_new(Q_ELEM_CTL, sizeof(struct nethdr_ack)); + if (qobj == NULL) + return; + + ack = (struct nethdr_ack *)qobj->data; + ack->type = NET_T_CTL; + ack->flags = flags; + ack->from = from; + ack->to = to; + + queue_add(tx_queue, &qobj->qnode); } static int notrack_init(void) { - tx_queue = queue_create(~0U); + tx_queue = queue_create(INT_MAX, QUEUE_F_EVFD); if (tx_queue == NULL) { dlog(LOG_ERR, "cannot create tx queue"); return -1; @@ -90,16 +89,7 @@ static int do_cache_to_tx(void *data1, void *data2) { struct cache_object *obj = data2; struct cache_notrack *cn = cache_get_extra(STATE_SYNC(internal), obj); - - if (!list_empty(&cn->tx_list)) - return 0; - - /* add to tx list */ - list_add_tail(&cn->tx_list, &tx_list); - tx_list_len++; - - write_evfd(STATE_SYNC(evfd)); - + queue_add(tx_queue, &cn->qnode); return 0; } @@ -152,44 +142,49 @@ static int notrack_recv(const struct nethdr *net) return ret; } -static int tx_queue_xmit(void *data1, const void *data2) +static int tx_queue_xmit(struct queue_node *n, const void *data2) { - struct nethdr *net = data1; - nethdr_set_ack(net); - HDR_HOST2NETWORK(net); - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); - queue_del(tx_queue, net); + switch (n->type) { + case Q_ELEM_CTL: { + struct nethdr *net = queue_node_data(n); + if (IS_RESYNC(net)) + nethdr_set_ack(net); + else + nethdr_set_ctl(net); + HDR_HOST2NETWORK(net); + mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); + queue_del(n); + queue_object_free((struct queue_object *)n); + break; + } + case Q_ELEM_OBJ: { + struct cache_ftfw *cn; + struct cache_object *obj; + int type; + struct nethdr *net; + + cn = (struct cache_ftfw *)n; + obj = cache_data_get_object(STATE_SYNC(internal), cn); + type = object_status_to_network_type(obj->status);; + net = BUILD_NETMSG(obj->ct, type); + mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); + queue_del(n); + break; + } + } return 0; } -static int tx_list_xmit(struct list_head *i, struct cache_object *obj, int type) +static void notrack_run(fd_set *readfds) { - int ret; - struct nethdr *net = BUILD_NETMSG(obj->ct, type); - - list_del_init(i); - tx_list_len--; - - ret = mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); - - return ret; + if (FD_ISSET(queue_get_eventfd(tx_queue), readfds)) + queue_iterate(tx_queue, NULL, tx_queue_xmit); } -static void notrack_run(void) +static int notrack_register_fds(struct fds *fds) { - struct cache_notrack *cn, *tmp; - - /* send messages in the tx_queue */ - queue_iterate(tx_queue, NULL, tx_queue_xmit); - - /* send conntracks in the tx_list */ - list_for_each_entry_safe(cn, tmp, &tx_list, tx_list) { - struct cache_object *obj; - - obj = cache_data_get_object(STATE_SYNC(internal), cn); - tx_list_xmit(&cn->tx_list, obj, NET_T_STATE_UPD); - } + return register_fd(queue_get_eventfd(tx_queue), fds); } struct sync_mode sync_notrack = { @@ -201,4 +196,5 @@ struct sync_mode sync_notrack = { .local = notrack_local, .recv = notrack_recv, .run = notrack_run, + .register_fds = notrack_register_fds, }; -- cgit v1.2.3 From 4ec9fc2bcceb4e609c43af1a2ecf8d1d87b55d5c Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 17 Jan 2009 17:54:15 +0100 Subject: ftfw: move helloing to ftfw_xmit() This patch moves the helloing logic into ftfw_xmit. Still, the helloing is kept in ftfw_send as we still have two possible paths for messages. This will be removed in the next patches to make all message go over a single txqueue. Signed-off-by: Pablo Neira Ayuso --- src/sync-ftfw.c | 65 +++++++++++++++++++-------------------------------------- 1 file changed, 22 insertions(+), 43 deletions(-) (limited to 'src') diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index bb53849..565a4bc 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -77,6 +77,22 @@ static struct cache_extra cache_ftfw_extra = { .destroy = cache_ftfw_del }; +static void nethdr_set_hello(struct nethdr *net) +{ + switch(hello_state) { + case HELLO_INIT: + hello_state = HELLO_SAY; + /* fall through */ + case HELLO_SAY: + net->flags |= NET_F_HELLO; + break; + } + if (say_hello_back) { + net->flags |= NET_F_HELLO_BACK; + say_hello_back = 0; + } +} + static void tx_queue_add_ctlmsg(uint32_t flags, uint32_t from, uint32_t to) { struct queue_object *qobj; @@ -92,20 +108,6 @@ static void tx_queue_add_ctlmsg(uint32_t flags, uint32_t from, uint32_t to) ack->from = from; ack->to = to; - switch(hello_state) { - case HELLO_INIT: - hello_state = HELLO_SAY; - /* fall through */ - case HELLO_SAY: - ack->flags |= NET_F_HELLO; - break; - } - - if (say_hello_back) { - ack->flags |= NET_F_HELLO_BACK; - say_hello_back = 0; - } - queue_add(tx_queue, &qobj->qnode); } @@ -122,20 +124,6 @@ static void tx_queue_add_ctlmsg2(uint32_t flags) ctl->type = NET_T_CTL; ctl->flags = flags; - switch(hello_state) { - case HELLO_INIT: - hello_state = HELLO_SAY; - /* fall through */ - case HELLO_SAY: - ctl->flags |= NET_F_HELLO; - break; - } - - if (say_hello_back) { - ctl->flags |= NET_F_HELLO_BACK; - say_hello_back = 0; - } - queue_add(tx_queue, &qobj->qnode); } @@ -474,19 +462,7 @@ static void ftfw_send(struct nethdr *net, struct cache_object *obj) if (queue_in(rs_queue, &cn->qnode)) queue_del(&cn->qnode); - switch(hello_state) { - case HELLO_INIT: - hello_state = HELLO_SAY; - /* fall through */ - case HELLO_SAY: - net->flags |= NET_F_HELLO; - break; - } - - if (say_hello_back) { - net->flags |= NET_F_HELLO_BACK; - say_hello_back = 0; - } + nethdr_set_hello(net); cn->seq = ntohl(net->seq); queue_add(rs_queue, &cn->qnode); @@ -496,10 +472,14 @@ static void ftfw_send(struct nethdr *net, struct cache_object *obj) static int tx_queue_xmit(struct queue_node *n, const void *data) { + queue_del(n); + switch(n->type) { case Q_ELEM_CTL: { struct nethdr *net = queue_node_data(n); + nethdr_set_hello(net); + if (IS_ACK(net) || IS_NACK(net) || IS_RESYNC(net)) { nethdr_set_ack(net); } else if (IS_ALIVE(net)) { @@ -516,7 +496,6 @@ static int tx_queue_xmit(struct queue_node *n, const void *data) mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); HDR_NETWORK2HOST(net); - queue_del(n); if (IS_ACK(net) || IS_NACK(net) || IS_RESYNC(net)) queue_add(rs_queue, n); else @@ -533,11 +512,11 @@ static int tx_queue_xmit(struct queue_node *n, const void *data) obj = cache_data_get_object(STATE_SYNC(internal), cn); type = object_status_to_network_type(obj->status); net = BUILD_NETMSG(obj->ct, type); + nethdr_set_hello(net); dp("tx_list sq: %u fl:%u len:%u\n", ntohl(net->seq), net->flags, ntohs(net->len)); - queue_del(n); mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); ftfw_send(net, obj); break; -- cgit v1.2.3 From 786f37040cdcb64b24eb0b437307ed5e208f717f Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 17 Jan 2009 17:54:57 +0100 Subject: sync: add generic tx_queue for all synchronization modes This patch adds a generic tx queue for all synchronization modes. Signed-off-by: Pablo Neira Ayuso --- include/conntrackd.h | 1 + include/sync.h | 3 +-- src/sync-ftfw.c | 37 +++++++++++-------------------------- src/sync-mode.c | 16 ++++++++++++---- src/sync-notrack.c | 37 +++++-------------------------------- 5 files changed, 30 insertions(+), 64 deletions(-) (limited to 'src') diff --git a/include/conntrackd.h b/include/conntrackd.h index 8cb520d..3637e2c 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -150,6 +150,7 @@ struct ct_sync_state { struct mcast_sock *mcast_server; /* multicast socket: incoming */ struct mcast_sock *mcast_client; /* multicast socket: outgoing */ + struct queue *tx_queue; struct sync_mode *sync; /* sync mode */ diff --git a/include/sync.h b/include/sync.h index 9a9540c..bced1cc 100644 --- a/include/sync.h +++ b/include/sync.h @@ -18,8 +18,7 @@ struct sync_mode { int (*local)(int fd, int type, void *data); int (*recv)(const struct nethdr *net); void (*send)(struct nethdr *net, struct cache_object *obj); - void (*run)(fd_set *readfds); - int (*register_fds)(struct fds *fds); + void (*xmit)(void); }; extern struct sync_mode sync_alarm; diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 565a4bc..d544a7b 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -34,7 +34,6 @@ #define dp(...) #endif -struct queue *tx_queue; struct queue *rs_queue; static uint32_t exp_seq; static uint32_t window; @@ -108,7 +107,7 @@ static void tx_queue_add_ctlmsg(uint32_t flags, uint32_t from, uint32_t to) ack->from = from; ack->to = to; - queue_add(tx_queue, &qobj->qnode); + queue_add(STATE_SYNC(tx_queue), &qobj->qnode); } static void tx_queue_add_ctlmsg2(uint32_t flags) @@ -124,7 +123,7 @@ static void tx_queue_add_ctlmsg2(uint32_t flags) ctl->type = NET_T_CTL; ctl->flags = flags; - queue_add(tx_queue, &qobj->qnode); + queue_add(STATE_SYNC(tx_queue), &qobj->qnode); } /* this function is called from the alarm framework */ @@ -144,11 +143,6 @@ static void do_alive_alarm(struct alarm_block *a, void *data) static int ftfw_init(void) { - tx_queue = queue_create(INT_MAX, QUEUE_F_EVFD); - if (tx_queue == NULL) { - dlog(LOG_ERR, "cannot create tx queue"); - return -1; - } rs_queue = queue_create(INT_MAX, 0); if (rs_queue == NULL) { dlog(LOG_ERR, "cannot create rs queue"); @@ -167,7 +161,6 @@ static int ftfw_init(void) static void ftfw_kill(void) { queue_destroy(rs_queue); - queue_destroy(tx_queue); } static int do_cache_to_tx(void *data1, void *data2) @@ -178,7 +171,7 @@ static int do_cache_to_tx(void *data1, void *data2) if (queue_in(rs_queue, &cn->qnode)) queue_del(&cn->qnode); - queue_add(tx_queue, &cn->qnode); + queue_add(STATE_SYNC(tx_queue), &cn->qnode); return 0; } @@ -259,7 +252,7 @@ static int rs_queue_to_tx(struct queue_node *n, const void *data) net->seq, net->flags, net->len); queue_del(n); - queue_add(tx_queue, n); + queue_add(STATE_SYNC(tx_queue), n); break; } case Q_ELEM_OBJ: { @@ -274,7 +267,7 @@ static int rs_queue_to_tx(struct queue_node *n, const void *data) dp("resending nack'ed (oldseq=%u)\n", cn->seq); queue_del(n); - queue_add(tx_queue, n); + queue_add(STATE_SYNC(tx_queue), n); break; } } @@ -526,19 +519,12 @@ static int tx_queue_xmit(struct queue_node *n, const void *data) return 0; } -static void ftfw_run(fd_set *readfds) +static void ftfw_xmit(void) { - if (FD_ISSET(queue_get_eventfd(tx_queue), readfds)) { - queue_iterate(tx_queue, NULL, tx_queue_xmit); - add_alarm(&alive_alarm, 1, 0); - dp("tx_queue_len:%u rs_queue_len:%u\n", - queue_len(tx_queue), queue_len(rs_queue)); - } -} - -static int ftfw_register_fds(struct fds *fds) -{ - return register_fd(queue_get_eventfd(tx_queue), fds); + queue_iterate(STATE_SYNC(tx_queue), NULL, tx_queue_xmit); + add_alarm(&alive_alarm, ALIVE_INT, 0); + dp("tx_queue_len:%u rs_queue_len:%u\n", + queue_len(tx_queue), queue_len(rs_queue)); } struct sync_mode sync_ftfw = { @@ -550,6 +536,5 @@ struct sync_mode sync_ftfw = { .local = ftfw_local, .recv = ftfw_recv, .send = ftfw_send, - .run = ftfw_run, - .register_fds = ftfw_register_fds, + .xmit = ftfw_xmit, }; diff --git a/src/sync-mode.c b/src/sync-mode.c index 711f71b..5ae9062 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -26,6 +26,7 @@ #include "fds.h" #include "event.h" #include "debug.h" +#include "queue.h" #include #include @@ -242,6 +243,12 @@ static int init_sync(void) return -1; } + STATE_SYNC(tx_queue) = queue_create(INT_MAX, QUEUE_F_EVFD); + if (STATE_SYNC(tx_queue) == NULL) { + dlog(LOG_ERR, "cannot create tx queue"); + return -1; + } + /* initialization of multicast sequence generation */ STATE_SYNC(last_seq_sent) = time(NULL); @@ -253,8 +260,8 @@ static int register_fds_sync(struct fds *fds) if (register_fd(STATE_SYNC(mcast_server->fd), fds) == -1) return -1; - if (STATE_SYNC(sync)->register_fds) - return STATE_SYNC(sync)->register_fds(fds); + if (register_fd(queue_get_eventfd(STATE_SYNC(tx_queue)), fds) == -1) + return -1; return 0; } @@ -265,8 +272,8 @@ static void run_sync(fd_set *readfds) if (FD_ISSET(STATE_SYNC(mcast_server->fd), readfds)) mcast_handler(); - if (STATE_SYNC(sync)->run) - STATE_SYNC(sync)->run(readfds); + if (FD_ISSET(queue_get_eventfd(STATE_SYNC(tx_queue)), readfds)) + STATE_SYNC(sync)->xmit(); /* flush pending messages */ mcast_buffered_pending_netmsg(STATE_SYNC(mcast_client)); @@ -281,6 +288,7 @@ static void kill_sync(void) mcast_client_destroy(STATE_SYNC(mcast_client)); mcast_buffered_destroy(); + queue_destroy(STATE_SYNC(tx_queue)); if (STATE_SYNC(sync)->kill) STATE_SYNC(sync)->kill(); diff --git a/src/sync-notrack.c b/src/sync-notrack.c index 40cc199..4ded298 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -27,8 +27,6 @@ #include -static struct queue *tx_queue; - struct cache_notrack { struct queue_node qnode; }; @@ -66,30 +64,14 @@ static void tx_queue_add_ctlmsg(uint32_t flags, uint32_t from, uint32_t to) ack->from = from; ack->to = to; - queue_add(tx_queue, &qobj->qnode); -} - -static int notrack_init(void) -{ - tx_queue = queue_create(INT_MAX, QUEUE_F_EVFD); - if (tx_queue == NULL) { - dlog(LOG_ERR, "cannot create tx queue"); - return -1; - } - - return 0; -} - -static void notrack_kill(void) -{ - queue_destroy(tx_queue); + queue_add(STATE_SYNC(tx_queue), &qobj->qnode); } static int do_cache_to_tx(void *data1, void *data2) { struct cache_object *obj = data2; struct cache_notrack *cn = cache_get_extra(STATE_SYNC(internal), obj); - queue_add(tx_queue, &cn->qnode); + queue_add(STATE_SYNC(tx_queue), &cn->qnode); return 0; } @@ -176,25 +158,16 @@ static int tx_queue_xmit(struct queue_node *n, const void *data2) return 0; } -static void notrack_run(fd_set *readfds) -{ - if (FD_ISSET(queue_get_eventfd(tx_queue), readfds)) - queue_iterate(tx_queue, NULL, tx_queue_xmit); -} - -static int notrack_register_fds(struct fds *fds) +static void notrack_xmit(void) { - return register_fd(queue_get_eventfd(tx_queue), fds); + queue_iterate(STATE_SYNC(tx_queue), NULL, tx_queue_xmit); } struct sync_mode sync_notrack = { .internal_cache_flags = LIFETIME, .external_cache_flags = LIFETIME, .internal_cache_extra = &cache_notrack_extra, - .init = notrack_init, - .kill = notrack_kill, .local = notrack_local, .recv = notrack_recv, - .run = notrack_run, - .register_fds = notrack_register_fds, + .xmit = notrack_xmit, }; -- cgit v1.2.3 From b1d00262f999a597fa24af3298195db9cf52b790 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 17 Jan 2009 18:03:50 +0100 Subject: sync: enqueue state updates to tx_queue With this patch, all the states updates are enqueued in the tx_queue. Thus, there's a single output path. This patch adds a simple refcounting mechanism to note when an object is sitting in the txqueue. This patch also removes the alarm that is required by the ftfw approach. Signed-off-by: Pablo Neira Ayuso --- include/cache.h | 7 ++--- include/sync.h | 2 +- src/cache.c | 59 ++++++++++++++++++------------------------ src/sync-alarm.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++-------- src/sync-ftfw.c | 70 +++++++++++++++++++++++++------------------------- src/sync-mode.c | 23 ++++++++--------- src/sync-notrack.c | 12 ++++++++- 7 files changed, 152 insertions(+), 96 deletions(-) (limited to 'src') diff --git a/include/cache.h b/include/cache.h index fd8e05f..03b6822 100644 --- a/include/cache.h +++ b/include/cache.h @@ -4,7 +4,6 @@ #include #include #include "hash.h" -#include "alarm.h" /* cache features */ enum { @@ -36,7 +35,7 @@ struct cache_object { struct nf_conntrack *ct; struct cache *cache; int status; - struct alarm_block alarm; + int refcnt; char data[0]; }; @@ -106,12 +105,14 @@ void cache_destroy(struct cache *e); struct cache_object *cache_object_new(struct cache *c, struct nf_conntrack *ct); void cache_object_free(struct cache_object *obj); +void cache_object_get(struct cache_object *obj); +int cache_object_put(struct cache_object *obj); +void cache_object_set_status(struct cache_object *obj, int status); int cache_add(struct cache *c, struct cache_object *obj, int id); void cache_update(struct cache *c, struct cache_object *obj, int id, struct nf_conntrack *ct); struct cache_object *cache_update_force(struct cache *c, struct nf_conntrack *ct); void cache_del(struct cache *c, struct cache_object *obj); -int cache_del_timer(struct cache *c, struct cache_object *obj, int timeout); struct cache_object *cache_find(struct cache *c, struct nf_conntrack *ct, int *pos); void cache_stats(const struct cache *c, int fd); void cache_stats_extended(const struct cache *c, int fd); diff --git a/include/sync.h b/include/sync.h index bced1cc..51f8f5b 100644 --- a/include/sync.h +++ b/include/sync.h @@ -17,7 +17,7 @@ struct sync_mode { void (*kill)(void); int (*local)(int fd, int type, void *data); int (*recv)(const struct nethdr *net); - void (*send)(struct nethdr *net, struct cache_object *obj); + void (*enqueue)(struct cache_object *obj, int type); void (*xmit)(void); }; diff --git a/src/cache.c b/src/cache.c index c46498b..1e08a33 100644 --- a/src/cache.c +++ b/src/cache.c @@ -174,8 +174,6 @@ void cache_destroy(struct cache *c) free(c); } -static void __del_timeout(struct alarm_block *a, void *data); - struct cache_object *cache_object_new(struct cache *c, struct nf_conntrack *ct) { struct cache_object *obj; @@ -187,7 +185,6 @@ struct cache_object *cache_object_new(struct cache *c, struct nf_conntrack *ct) return NULL; } obj->cache = c; - init_alarm(&obj->alarm, obj, __del_timeout); if ((obj->ct = nfct_new()) == NULL) { free(obj); @@ -207,6 +204,30 @@ void cache_object_free(struct cache_object *obj) free(obj); } +int cache_object_put(struct cache_object *obj) +{ + if (--obj->refcnt == 0) { + cache_del(obj->cache, obj); + cache_object_free(obj); + return 1; + } + return 0; +} + +void cache_object_get(struct cache_object *obj) +{ + obj->refcnt++; +} + +void cache_object_set_status(struct cache_object *obj, int status) +{ + if (status == C_OBJ_DEAD) { + obj->cache->stats.del_ok++; + obj->cache->stats.active--; + } + obj->status = status; +} + static int __add(struct cache *c, struct cache_object *obj, int id) { int ret; @@ -227,6 +248,7 @@ static int __add(struct cache *c, struct cache_object *obj, int id) c->stats.active++; obj->status = C_OBJ_NEW; + obj->refcnt++; return 0; } @@ -292,7 +314,6 @@ void cache_del(struct cache *c, struct cache_object *obj) c->stats.del_ok++; c->stats.active--; } - del_alarm(&obj->alarm); __del(c, obj); } @@ -322,36 +343,6 @@ cache_update_force(struct cache *c, struct nf_conntrack *ct) return obj; } -static void __del_timeout(struct alarm_block *a, void *data) -{ - struct cache_object *obj = (struct cache_object *) data; - __del(obj->cache, obj); - cache_object_free(obj); -} - -int cache_del_timer(struct cache *c, struct cache_object *obj, int timeout) -{ - if (timeout <= 0) { - cache_del(c, obj); - cache_object_free(obj); - return 1; - } - if (obj->status != C_OBJ_DEAD) { - obj->status = C_OBJ_DEAD; - add_alarm(&obj->alarm, timeout, 0); - /* - * increase stats even if this entry was not really - * removed yet. We do not want to make people think - * that the replication protocol does not work - * properly. - */ - c->stats.del_ok++; - c->stats.active--; - return 1; - } - return 0; -} - struct cache_object * cache_find(struct cache *c, struct nf_conntrack *ct, int *id) { diff --git a/src/sync-alarm.c b/src/sync-alarm.c index 34937fe..a2f17ac 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -21,14 +21,21 @@ #include "network.h" #include "alarm.h" #include "cache.h" +#include "queue.h" #include "debug.h" #include #include +struct cache_alarm { + struct queue_node qnode; + struct alarm_block alarm; +}; + +static void alarm_enqueue(struct cache_object *obj, int query); + static void refresher(struct alarm_block *a, void *data) { - struct nethdr *net; struct cache_object *obj = data; debug_ct(obj->ct, "persistence update"); @@ -37,36 +44,37 @@ static void refresher(struct alarm_block *a, void *data) random() % CONFIG(refresh) + 1, ((random() % 5 + 1) * 200000) - 1); - net = BUILD_NETMSG(obj->ct, NET_T_STATE_UPD); - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); + alarm_enqueue(obj, NET_T_STATE_UPD); } static void cache_alarm_add(struct cache_object *obj, void *data) { - struct alarm_block *a = data; + struct cache_alarm *ca = data; - init_alarm(a, obj, refresher); - add_alarm(a, + queue_node_init(&ca->qnode, Q_ELEM_OBJ); + init_alarm(&ca->alarm, obj, refresher); + add_alarm(&ca->alarm, random() % CONFIG(refresh) + 1, ((random() % 5 + 1) * 200000) - 1); } static void cache_alarm_update(struct cache_object *obj, void *data) { - struct alarm_block *a = data; - add_alarm(a, + struct cache_alarm *ca = data; + add_alarm(&ca->alarm, random() % CONFIG(refresh) + 1, ((random() % 5 + 1) * 200000) - 1); } static void cache_alarm_destroy(struct cache_object *obj, void *data) { - struct alarm_block *a = data; - del_alarm(a); + struct cache_alarm *ca = data; + queue_del(&ca->qnode); + del_alarm(&ca->alarm); } static struct cache_extra cache_alarm_extra = { - .size = sizeof(struct alarm_block), + .size = sizeof(struct cache_alarm), .add = cache_alarm_add, .update = cache_alarm_update, .destroy = cache_alarm_destroy @@ -102,9 +110,54 @@ static int alarm_recv(const struct nethdr *net) return 0; } +static void alarm_enqueue(struct cache_object *obj, int query) +{ + struct cache_alarm *ca = cache_get_extra(STATE_SYNC(internal), obj); + if (queue_add(STATE_SYNC(tx_queue), &ca->qnode)) + cache_object_get(obj); +} + +static int tx_queue_xmit(struct queue_node *n, const void *data) +{ + struct nethdr *net; + + queue_del(n); + + switch(n->type) { + case Q_ELEM_CTL: + net = queue_node_data(n); + nethdr_set_ctl(net); + HDR_HOST2NETWORK(net); + mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); + queue_object_free((struct queue_object *)n); + break; + case Q_ELEM_OBJ: { + struct cache_alarm *ca; + struct cache_object *obj; + int type; + + ca = (struct cache_alarm *)n; + obj = cache_data_get_object(STATE_SYNC(internal), ca); + type = object_status_to_network_type(obj->status); + net = BUILD_NETMSG(obj->ct, type); + mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); + cache_object_put(obj); + break; + } + } + return 0; +} + +static void alarm_xmit(void) +{ + queue_iterate(STATE_SYNC(tx_queue), NULL, tx_queue_xmit); +} + struct sync_mode sync_alarm = { .internal_cache_flags = LIFETIME, .external_cache_flags = TIMER | LIFETIME, .internal_cache_extra = &cache_alarm_extra, .recv = alarm_recv, + .enqueue = alarm_enqueue, + .xmit = alarm_xmit, }; diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index d544a7b..a287ecd 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -168,11 +168,13 @@ static int do_cache_to_tx(void *data1, void *data2) struct cache_object *obj = data2; struct cache_ftfw *cn = cache_get_extra(STATE_SYNC(internal), obj); - if (queue_in(rs_queue, &cn->qnode)) + if (queue_in(rs_queue, &cn->qnode)) { queue_del(&cn->qnode); - - queue_add(STATE_SYNC(tx_queue), &cn->qnode); - + queue_add(STATE_SYNC(tx_queue), &cn->qnode); + } else { + if (queue_add(STATE_SYNC(tx_queue), &cn->qnode)) + cache_object_get(obj); + } return 0; } @@ -278,16 +280,15 @@ static int rs_queue_empty(struct queue_node *n, const void *data) { const struct nethdr_ack *h = data; - if (h == NULL) { - dp("inconditional remove from queue (seq=%u)\n", net->seq); - queue_del(n); - return 0; - } - switch(n->type) { case Q_ELEM_CTL: { struct nethdr_ack *net = queue_node_data(n); + if (h == NULL) { + queue_del(n); + queue_object_free((struct queue_object *)n); + return 0; + } if (before(net->seq, h->from)) return 0; /* continue */ else if (after(net->seq, h->to)) @@ -300,8 +301,15 @@ static int rs_queue_empty(struct queue_node *n, const void *data) } case Q_ELEM_OBJ: { struct cache_ftfw *cn; + struct cache_object *obj; cn = (struct cache_ftfw *) n; + if (h == NULL) { + queue_del(n); + obj = cache_data_get_object(STATE_SYNC(internal), cn); + cache_object_put(obj); + return 0; + } if (before(cn->seq, h->from)) return 0; else if (after(cn->seq, h->to)) @@ -309,6 +317,8 @@ static int rs_queue_empty(struct queue_node *n, const void *data) dp("queue: deleting from queue (seq=%u)\n", cn->seq); queue_del(n); + obj = cache_data_get_object(STATE_SYNC(internal), cn); + cache_object_put(obj); break; } } @@ -441,28 +451,6 @@ out: return ret; } -static void ftfw_send(struct nethdr *net, struct cache_object *obj) -{ - struct cache_ftfw *cn; - - switch(net->type) { - case NET_T_STATE_NEW: - case NET_T_STATE_UPD: - case NET_T_STATE_DEL: - cn = (struct cache_ftfw *) - cache_get_extra(STATE_SYNC(internal), obj); - - if (queue_in(rs_queue, &cn->qnode)) - queue_del(&cn->qnode); - - nethdr_set_hello(net); - - cn->seq = ntohl(net->seq); - queue_add(rs_queue, &cn->qnode); - break; - } -} - static int tx_queue_xmit(struct queue_node *n, const void *data) { queue_del(n); @@ -511,7 +499,9 @@ static int tx_queue_xmit(struct queue_node *n, const void *data) ntohl(net->seq), net->flags, ntohs(net->len)); mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); - ftfw_send(net, obj); + cn->seq = ntohl(net->seq); + queue_add(rs_queue, &cn->qnode); + /* we release the object once we get the acknowlegment */ break; } } @@ -527,6 +517,18 @@ static void ftfw_xmit(void) queue_len(tx_queue), queue_len(rs_queue)); } +static void ftfw_enqueue(struct cache_object *obj, int type) +{ + struct cache_ftfw *cn = cache_get_extra(STATE_SYNC(internal), obj); + if (queue_in(rs_queue, &cn->qnode)) { + queue_del(&cn->qnode); + queue_add(STATE_SYNC(tx_queue), &cn->qnode); + } else { + if (queue_add(STATE_SYNC(tx_queue), &cn->qnode)) + cache_object_get(obj); + } +} + struct sync_mode sync_ftfw = { .internal_cache_flags = LIFETIME, .external_cache_flags = LIFETIME, @@ -535,6 +537,6 @@ struct sync_mode sync_ftfw = { .kill = ftfw_kill, .local = ftfw_local, .recv = ftfw_recv, - .send = ftfw_send, + .enqueue = ftfw_enqueue, .xmit = ftfw_xmit, }; diff --git a/src/sync-mode.c b/src/sync-mode.c index 5ae9062..00e2f7b 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -442,14 +442,7 @@ static void dump_sync(struct nf_conntrack *ct) static void mcast_send_sync(struct cache_object *obj, int query) { - struct nethdr *net; - - net = BUILD_NETMSG(obj->ct, query); - - if (STATE_SYNC(sync)->send) - STATE_SYNC(sync)->send(net, obj); - - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); + STATE_SYNC(sync)->enqueue(obj, query); } static int purge_step(void *data1, void *data2) @@ -461,8 +454,11 @@ static int purge_step(void *data1, void *data2) ret = nfct_query(h, NFCT_Q_GET, obj->ct); if (ret == -1 && errno == ENOENT) { debug_ct(obj->ct, "overrun purge resync"); - mcast_send_sync(obj, NET_T_STATE_DEL); - cache_del_timer(STATE_SYNC(internal), obj, CONFIG(del_timeout)); + if (obj->status != C_OBJ_DEAD) { + cache_object_set_status(obj, C_OBJ_DEAD); + mcast_send_sync(obj, NET_T_STATE_DEL); + cache_object_put(obj); + } } return 0; @@ -552,8 +548,11 @@ static int event_destroy_sync(struct nf_conntrack *ct) debug_ct(ct, "can't destroy"); return 0; } - mcast_send_sync(obj, NET_T_STATE_DEL); - cache_del_timer(STATE_SYNC(internal), obj, CONFIG(del_timeout)); + if (obj->status != C_OBJ_DEAD) { + cache_object_set_status(obj, C_OBJ_DEAD); + mcast_send_sync(obj, NET_T_STATE_DEL); + cache_object_put(obj); + } debug_ct(ct, "internal destroy"); return 1; } diff --git a/src/sync-notrack.c b/src/sync-notrack.c index 4ded298..3b547ee 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -71,7 +71,8 @@ static int do_cache_to_tx(void *data1, void *data2) { struct cache_object *obj = data2; struct cache_notrack *cn = cache_get_extra(STATE_SYNC(internal), obj); - queue_add(STATE_SYNC(tx_queue), &cn->qnode); + if (queue_add(STATE_SYNC(tx_queue), &cn->qnode)) + cache_object_get(obj); return 0; } @@ -152,6 +153,7 @@ static int tx_queue_xmit(struct queue_node *n, const void *data2) mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); queue_del(n); + cache_object_put(obj); break; } } @@ -163,11 +165,19 @@ static void notrack_xmit(void) queue_iterate(STATE_SYNC(tx_queue), NULL, tx_queue_xmit); } +static void notrack_enqueue(struct cache_object *obj, int query) +{ + struct cache_notrack *cn = cache_get_extra(STATE_SYNC(internal), obj); + if (queue_add(STATE_SYNC(tx_queue), &cn->qnode)) + cache_object_get(obj); +} + struct sync_mode sync_notrack = { .internal_cache_flags = LIFETIME, .external_cache_flags = LIFETIME, .internal_cache_extra = &cache_notrack_extra, .local = notrack_local, .recv = notrack_recv, + .enqueue = notrack_enqueue, .xmit = notrack_xmit, }; -- cgit v1.2.3 From d581381870486687586dea4ebf4b7065ae408cd0 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 17 Jan 2009 18:03:52 +0100 Subject: network: do not re-set the message type in nethdr_set* functions The network headers already contain the message type set. It is not necessary to set it up again. Signed-off-by: Pablo Neira Ayuso --- src/network.c | 10 +++++----- src/sync-ftfw.c | 5 +---- 2 files changed, 6 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/network.c b/src/network.c index 320cdea..7a106b1 100644 --- a/src/network.c +++ b/src/network.c @@ -39,31 +39,31 @@ int nethdr_size(int len) return NETHDR_SIZ + len; } -static inline void __nethdr_set(struct nethdr *net, int len, int type) +static inline void __nethdr_set(struct nethdr *net, int len) { if (!seq_set) { seq_set = 1; cur_seq = time(NULL); } net->version = CONNTRACKD_PROTOCOL_VERSION; - net->type = type; net->len = len; net->seq = cur_seq++; } void nethdr_set(struct nethdr *net, int type) { - __nethdr_set(net, NETHDR_SIZ, type); + __nethdr_set(net, NETHDR_SIZ); + net->type = type; } void nethdr_set_ack(struct nethdr *net) { - __nethdr_set(net, NETHDR_ACK_SIZ, NET_T_CTL); + __nethdr_set(net, NETHDR_ACK_SIZ); } void nethdr_set_ctl(struct nethdr *net) { - __nethdr_set(net, NETHDR_SIZ, NET_T_CTL); + __nethdr_set(net, NETHDR_SIZ); } static size_t tx_buflenmax; diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index a287ecd..0d49756 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -463,11 +463,8 @@ static int tx_queue_xmit(struct queue_node *n, const void *data) if (IS_ACK(net) || IS_NACK(net) || IS_RESYNC(net)) { nethdr_set_ack(net); - } else if (IS_ALIVE(net)) { - nethdr_set_ctl(net); } else { - STATE_SYNC(error).msg_snd_malformed++; - return 0; + nethdr_set_ctl(net); } HDR_HOST2NETWORK(net); -- cgit v1.2.3 From 7ae054f8aae252ee9c57e26327675e466fc1d15d Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 17 Jan 2009 18:03:52 +0100 Subject: src: support for redundant dedicated links This patch adds support for redundant dedicated links. You can add a pool of dedicated links that can be used if the current active fails. Signed-off-by: Pablo Neira Ayuso --- doc/sync/alarm/conntrackd.conf | 19 ++++ doc/sync/ftfw/conntrackd.conf | 19 ++++ doc/sync/notrack/conntrackd.conf | 19 ++++ include/conntrackd.h | 10 +- include/mcast.h | 28 ++++- include/netlink.h | 1 + include/network.h | 6 +- src/main.c | 6 +- src/mcast.c | 231 ++++++++++++++++++++++++++++++++++++--- src/netlink.c | 16 +++ src/network.c | 9 +- src/read_config_lex.l | 1 + src/read_config_yy.y | 105 ++++++++++++------ src/sync-mode.c | 109 ++++++++++++++---- 14 files changed, 495 insertions(+), 84 deletions(-) (limited to 'src') diff --git a/doc/sync/alarm/conntrackd.conf b/doc/sync/alarm/conntrackd.conf index f16f439..528ff8f 100644 --- a/doc/sync/alarm/conntrackd.conf +++ b/doc/sync/alarm/conntrackd.conf @@ -104,6 +104,25 @@ Sync { # Checksum on } + # + # You can specify more than one dedicated link. Thus, if one dedicated + # link fails, conntrackd can fail-over to another. Note that adding + # more than one dedicated link does not mean that state-updates will + # be sent to all of them. There is only one active dedicated link at + # a given moment. The `Default' keyword indicates that this interface + # will be selected as the initial dedicated link. You can have + # up to 4 redundant dedicated links. Note: Use different multicast + # groups for every redundant link. + # + # Multicast Default { + # IPv4_address 225.0.0.51 + # Group 3781 + # IPv4_interface 192.168.100.101 + # Interface eth3 + # # McastSndSocketBuffer 1249280 + # # McastRcvSocketBuffer 1249280 + # Checksum on + # } } # diff --git a/doc/sync/ftfw/conntrackd.conf b/doc/sync/ftfw/conntrackd.conf index d85fc28..2e60f2c 100644 --- a/doc/sync/ftfw/conntrackd.conf +++ b/doc/sync/ftfw/conntrackd.conf @@ -112,6 +112,25 @@ Sync { # Checksum on } + # + # You can specify more than one dedicated link. Thus, if one dedicated + # link fails, conntrackd can fail-over to another. Note that adding + # more than one dedicated link does not mean that state-updates will + # be sent to all of them. There is only one active dedicated link at + # a given moment. The `Default' keyword indicates that this interface + # will be selected as the initial dedicated link. You can have + # up to 4 redundant dedicated links. Note: Use different multicast + # groups for every redundant link. + # + # Multicast Default { + # IPv4_address 225.0.0.51 + # Group 3781 + # IPv4_interface 192.168.100.101 + # Interface eth3 + # # McastSndSocketBuffer 1249280 + # # McastRcvSocketBuffer 1249280 + # Checksum on + # } } # diff --git a/doc/sync/notrack/conntrackd.conf b/doc/sync/notrack/conntrackd.conf index 4d03234..7f8c8a3 100644 --- a/doc/sync/notrack/conntrackd.conf +++ b/doc/sync/notrack/conntrackd.conf @@ -94,6 +94,25 @@ Sync { # Checksum on } + # + # You can specify more than one dedicated link. Thus, if one dedicated + # link fails, conntrackd can fail-over to another. Note that adding + # more than one dedicated link does not mean that state-updates will + # be sent to all of them. There is only one active dedicated link at + # a given moment. The `Default' keyword indicates that this interface + # will be selected as the initial dedicated link. You can have + # up to 4 redundant dedicated links. Note: Use different multicast + # groups for every redundant link. + # + # Multicast Default { + # IPv4_address 225.0.0.51 + # Group 3781 + # IPv4_interface 192.168.100.101 + # Interface eth3 + # # McastSndSocketBuffer 1249280 + # # McastRcvSocketBuffer 1249280 + # Checksum on + # } } # diff --git a/include/conntrackd.h b/include/conntrackd.h index 3637e2c..ab5d825 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -29,6 +29,7 @@ #define STATS_NETWORK 28 /* extended network stats */ #define STATS_CACHE 29 /* extended cache stats */ #define STATS_RUNTIME 30 /* extended runtime stats */ +#define STATS_MULTICAST 31 /* multicast network stats */ #define DEFAULT_CONFIGFILE "/etc/conntrackd/conntrackd.conf" #define DEFAULT_LOCKFILE "/var/lock/conntrackd.lock" @@ -66,7 +67,9 @@ struct ct_conf { int syslog_facility; char lockfile[FILENAME_MAXLEN]; int hashsize; /* hashtable size */ - struct mcast_conf mcast; /* multicast settings */ + int mcast_links; + int mcast_default_link; + struct mcast_conf mcast[MCAST_LINKS_MAX]; struct local_conf local; /* unix socket facilities */ int limit; int refresh; @@ -148,8 +151,9 @@ struct ct_sync_state { struct cache *internal; /* internal events cache (netlink) */ struct cache *external; /* external events cache (mcast) */ - struct mcast_sock *mcast_server; /* multicast socket: incoming */ - struct mcast_sock *mcast_client; /* multicast socket: outgoing */ + struct mcast_sock_multi *mcast_server; /* multicast incoming */ + struct mcast_sock_multi *mcast_client; /* multicast outgoing */ + struct nlif_handle *mcast_iface; struct queue *tx_queue; struct sync_mode *sync; /* sync mode */ diff --git a/include/mcast.h b/include/mcast.h index 7c4b1d6..623f390 100644 --- a/include/mcast.h +++ b/include/mcast.h @@ -19,6 +19,7 @@ struct mcast_conf { unsigned int interface_index6; } ifa; int mtu; + int interface_idx; int sndbuf; int rcvbuf; char iface[IFNAMSIZ]; @@ -37,19 +38,42 @@ struct mcast_sock { struct sockaddr_in6 ipv6; } addr; socklen_t sockaddr_len; + int interface_idx; struct mcast_stats stats; }; +#define MCAST_LINKS_MAX 4 + +struct mcast_sock_multi { + int num_links; + int max_mtu; + struct mcast_sock *current_link; + struct mcast_sock *multi[MCAST_LINKS_MAX]; +}; + struct mcast_sock *mcast_server_create(struct mcast_conf *conf); void mcast_server_destroy(struct mcast_sock *m); +struct mcast_sock_multi *mcast_server_create_multi(struct mcast_conf *conf, int conf_len); +void mcast_server_destroy_multi(struct mcast_sock_multi *m); struct mcast_sock *mcast_client_create(struct mcast_conf *conf); void mcast_client_destroy(struct mcast_sock *m); +struct mcast_sock_multi *mcast_client_create_multi(struct mcast_conf *conf, int conf_len); +void mcast_client_destroy_multi(struct mcast_sock_multi*m); ssize_t mcast_send(struct mcast_sock *m, void *data, int size); ssize_t mcast_recv(struct mcast_sock *m, void *data, int size); -struct mcast_stats *mcast_get_stats(struct mcast_sock *m); -void mcast_dump_stats(int fd, struct mcast_sock *s, struct mcast_sock *r); +int mcast_get_fd(struct mcast_sock *m); +int mcast_get_ifidx(struct mcast_sock_multi *m, int i); +int mcast_get_current_ifidx(struct mcast_sock_multi *m); + +struct mcast_sock *mcast_get_current_link(struct mcast_sock_multi *m); +void mcast_set_current_link(struct mcast_sock_multi *m, int i); + +void mcast_dump_stats(int fd, const struct mcast_sock_multi *s, const struct mcast_sock_multi *r); + +struct nlif_handle; +void mcast_dump_stats_extended(int fd, const struct mcast_sock_multi *s, const struct mcast_sock_multi *r, const struct nlif_handle *h); #endif diff --git a/include/netlink.h b/include/netlink.h index 5feb3e9..4bc5ee4 100644 --- a/include/netlink.h +++ b/include/netlink.h @@ -10,6 +10,7 @@ struct nfct_handle *nl_init_event_handler(void); struct nfct_handle *nl_init_dump_handler(void); struct nfct_handle *nl_init_request_handler(void); struct nfct_handle *nl_init_overrun_handler(void); +struct nlif_handle *nl_init_interface_handler(void); int nl_overrun_request_resync(struct nfct_handle *h); void nl_resize_socket_buffer(struct nfct_handle *h); diff --git a/include/network.h b/include/network.h index f02d920..740e762 100644 --- a/include/network.h +++ b/include/network.h @@ -76,7 +76,7 @@ enum { __hdr; \ }) -struct mcast_sock; +struct mcast_sock_multi; enum { SEQ_UNKNOWN, @@ -94,8 +94,8 @@ struct mcast_conf; int mcast_buffered_init(int mtu); void mcast_buffered_destroy(void); -int mcast_buffered_send_netmsg(struct mcast_sock *m, const struct nethdr *net); -ssize_t mcast_buffered_pending_netmsg(struct mcast_sock *m); +int mcast_buffered_send_netmsg(struct mcast_sock_multi *m, const struct nethdr *net); +ssize_t mcast_buffered_pending_netmsg(struct mcast_sock_multi *m); #define IS_DATA(x) (x->type <= NET_T_STATE_MAX && \ (x->flags & ~(NET_F_HELLO | NET_F_HELLO_BACK)) == 0) diff --git a/src/main.c b/src/main.c index 929b5c9..061a73e 100644 --- a/src/main.c +++ b/src/main.c @@ -43,7 +43,7 @@ static const char usage_client_commands[] = " -i, display content of the internal cache\n" " -e, display the content of the external cache\n" " -k, kill conntrack daemon\n" - " -s [|network|cache|runtime], dump statistics\n" + " -s [|network|cache|runtime|multicast], dump statistics\n" " -R, resync with kernel conntrack table\n" " -n, request resync with other node (only FT-FW and NOTRACK modes)\n" " -x, dump cache in XML format (requires -i or -e)\n" @@ -169,6 +169,10 @@ int main(int argc, char *argv[]) strlen(argv[i+1])) == 0) { action = STATS_RUNTIME; i++; + } else if (strncmp(argv[i+1], "multicast", + strlen(argv[i+1])) == 0) { + action = STATS_MULTICAST; + i++; } else { fprintf(stderr, "ERROR: unknown " "parameter `%s' for " diff --git a/src/mcast.c b/src/mcast.c index 2bb8743..70205d8 100644 --- a/src/mcast.c +++ b/src/mcast.c @@ -1,5 +1,5 @@ /* - * (C) 2006 by Pablo Neira Ayuso + * (C) 2006-2009 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 @@ -45,6 +45,8 @@ struct mcast_sock *mcast_server_create(struct mcast_conf *conf) return NULL; memset(m, 0, sizeof(struct mcast_sock)); + m->interface_idx = conf->interface_idx; + switch(conf->ipproto) { case AF_INET: mreq.ipv4.imr_multiaddr.s_addr = conf->in.inet_addr.s_addr; @@ -147,12 +149,52 @@ struct mcast_sock *mcast_server_create(struct mcast_conf *conf) return m; } +struct mcast_sock_multi * +mcast_server_create_multi(struct mcast_conf *conf, int conf_len) +{ + struct mcast_sock_multi *m; + int i, j; + + if (conf_len <= 0 || conf_len > MCAST_LINKS_MAX) + return NULL; + + m = calloc(sizeof(struct mcast_sock_multi), 1); + if (m == NULL) + return NULL; + + m->max_mtu = INT_MAX; + for (i=0; imulti[i] = mcast_server_create(&conf[i]); + if (m->multi[i] == NULL) { + for (j=0; jmulti[j]); + } + free(m); + return NULL; + } + if (m->max_mtu > conf[i].mtu) + m->max_mtu = conf[i].mtu; + } + m->num_links = conf_len; + + return m; +} + void mcast_server_destroy(struct mcast_sock *m) { close(m->fd); free(m); } +void mcast_server_destroy_multi(struct mcast_sock_multi *m) +{ + int i; + + for (i=0; inum_links; i++) + mcast_server_destroy(m->multi[i]); + free(m); +} + static int __mcast_client_create_ipv4(struct mcast_sock *m, struct mcast_conf *conf) { @@ -222,6 +264,8 @@ struct mcast_sock *mcast_client_create(struct mcast_conf *conf) return NULL; memset(m, 0, sizeof(struct mcast_sock)); + m->interface_idx = conf->interface_idx; + if ((m->fd = socket(conf->ipproto, SOCK_DGRAM, 0)) == -1) { debug("mcast_sock_client_create:socket"); free(m); @@ -275,12 +319,52 @@ struct mcast_sock *mcast_client_create(struct mcast_conf *conf) return m; } +struct mcast_sock_multi * +mcast_client_create_multi(struct mcast_conf *conf, int conf_len) +{ + struct mcast_sock_multi *m; + int i, j; + + if (conf_len <= 0 || conf_len > MCAST_LINKS_MAX) + return NULL; + + m = calloc(sizeof(struct mcast_sock_multi), 1); + if (m == NULL) + return NULL; + + m->max_mtu = INT_MAX; + for (i=0; imulti[i] = mcast_client_create(&conf[i]); + if (m->multi[i] == NULL) { + for (j=0; jmulti[j]); + } + free(m); + return NULL; + } + if (m->max_mtu > conf[i].mtu) + m->max_mtu = conf[i].mtu; + } + m->num_links = conf_len; + + return m; +} + void mcast_client_destroy(struct mcast_sock *m) { close(m->fd); free(m); } +void mcast_client_destroy_multi(struct mcast_sock_multi *m) +{ + int i; + + for (i=0; inum_links; i++) + mcast_client_destroy(m->multi[i]); + free(m); +} + ssize_t mcast_send(struct mcast_sock *m, void *data, int size) { ssize_t ret; @@ -326,29 +410,140 @@ ssize_t mcast_recv(struct mcast_sock *m, void *data, int size) return ret; } -struct mcast_stats *mcast_get_stats(struct mcast_sock *m) +void mcast_set_current_link(struct mcast_sock_multi *m, int i) +{ + m->current_link = m->multi[i]; +} + +struct mcast_sock *mcast_get_current_link(struct mcast_sock_multi *m) +{ + return m->current_link; +} + +int mcast_get_fd(struct mcast_sock *m) +{ + return m->fd; +} + +int mcast_get_current_ifidx(struct mcast_sock_multi *m) { - return &m->stats; + return m->current_link->interface_idx; } -void mcast_dump_stats(int fd, struct mcast_sock *s, struct mcast_sock *r) +int mcast_get_ifidx(struct mcast_sock_multi *m, int i) { - char buf[512]; + return m->multi[i]->interface_idx; +} + +static int +mcast_snprintf_stats(char *buf, size_t buflen, char *ifname, + struct mcast_stats *s, struct mcast_stats *r) +{ + size_t size; + + size = snprintf(buf, buflen, "multicast traffic (active device=%s):\n" + "%20llu Bytes sent " + "%20llu Bytes recv\n" + "%20llu Pckts sent " + "%20llu Pckts recv\n" + "%20llu Error send " + "%20llu Error recv\n\n", + ifname, + (unsigned long long)s->bytes, + (unsigned long long)r->bytes, + (unsigned long long)s->messages, + (unsigned long long)r->messages, + (unsigned long long)s->error, + (unsigned long long)r->error); + return size; +} + +static int +mcast_snprintf_stats2(char *buf, size_t buflen, const char *ifname, + const char *status, int active, + struct mcast_stats *s, struct mcast_stats *r) +{ + size_t size; + + size = snprintf(buf, buflen, + "multicast traffic device=%s status=%s role=%s:\n" + "%20llu Bytes sent " + "%20llu Bytes recv\n" + "%20llu Pckts sent " + "%20llu Pckts recv\n" + "%20llu Error send " + "%20llu Error recv\n\n", + ifname, status, active ? "ACTIVE" : "BACKUP", + (unsigned long long)s->bytes, + (unsigned long long)r->bytes, + (unsigned long long)s->messages, + (unsigned long long)r->messages, + (unsigned long long)s->error, + (unsigned long long)r->error); + return size; +} + +void +mcast_dump_stats(int fd, + const struct mcast_sock_multi *s, + const struct mcast_sock_multi *r) +{ + int i; + struct mcast_stats snd = { 0, 0, 0}; + struct mcast_stats rcv = { 0, 0, 0}; + char ifname[IFNAMSIZ], buf[512]; int size; - size = sprintf(buf, "multicast traffic:\n" - "%20llu Bytes sent " - "%20llu Bytes recv\n" - "%20llu Pckts sent " - "%20llu Pckts recv\n" - "%20llu Error send " - "%20llu Error recv\n\n", - (unsigned long long)s->stats.bytes, - (unsigned long long)r->stats.bytes, - (unsigned long long)s->stats.messages, - (unsigned long long)r->stats.messages, - (unsigned long long)s->stats.error, - (unsigned long long)r->stats.error); + /* it is the same for the receiver, no need to do it twice */ + if_indextoname(s->current_link->interface_idx, ifname); + + for (i=0; inum_links && inum_links; i++) { + snd.bytes += s->multi[i]->stats.bytes; + snd.messages += s->multi[i]->stats.messages; + snd.error += s->multi[i]->stats.error; + rcv.bytes += r->multi[i]->stats.bytes; + rcv.messages += r->multi[i]->stats.messages; + rcv.error += r->multi[i]->stats.error; + } + size = mcast_snprintf_stats(buf, sizeof(buf), ifname, &snd, &rcv); + send(fd, buf, size, 0); +} +void +mcast_dump_stats_extended(int fd, + const struct mcast_sock_multi *s, + const struct mcast_sock_multi *r, + const struct nlif_handle *h) +{ + int i; + char buf[4096]; + int size = 0; + + for (i=0; inum_links && inum_links; i++) { + int idx = s->multi[i]->interface_idx, active; + unsigned int flags; + char ifname[IFNAMSIZ]; + const char *status; + + if_indextoname(idx, ifname); + nlif_get_ifflags(h, idx, &flags); + active = (s->multi[i] == s->current_link); + /* + * IFF_UP shows administrative status + * IFF_RUNNING shows carrier status + */ + if (flags & IFF_UP) { + if (!(flags & IFF_RUNNING)) + status = "NO-CARRIER"; + else + status = "RUNNING"; + } else { + status = "DOWN"; + } + size += mcast_snprintf_stats2(buf+size, sizeof(buf), + ifname, status, active, + &s->multi[i]->stats, + &r->multi[i]->stats); + } send(fd, buf, size, 0); } diff --git a/src/netlink.c b/src/netlink.c index 92fbf00..2266201 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -114,6 +114,22 @@ struct nfct_handle *nl_init_request_handler(void) return h; } +struct nlif_handle *nl_init_interface_handler(void) +{ + struct nlif_handle *h; + h = nlif_open(); + if (h == NULL) + return NULL; + + if (nlif_query(h) == -1) { + free(h); + return NULL; + } + fcntl(nlif_fd(h), F_SETFL, O_NONBLOCK); + + return h; +} + static int warned = 0; void nl_resize_socket_buffer(struct nfct_handle *h) diff --git a/src/network.c b/src/network.c index 7a106b1..f71aef0 100644 --- a/src/network.c +++ b/src/network.c @@ -95,7 +95,8 @@ void mcast_buffered_destroy(void) } /* return 0 if it is not sent, otherwise return 1 */ -int mcast_buffered_send_netmsg(struct mcast_sock *m, const struct nethdr *net) +int +mcast_buffered_send_netmsg(struct mcast_sock_multi *m, const struct nethdr *net) { int ret = 0, len = ntohs(net->len); @@ -104,7 +105,7 @@ retry: memcpy(tx_buf + tx_buflen, net, len); tx_buflen += len; } else { - mcast_send(m, tx_buf, tx_buflen); + mcast_send(mcast_get_current_link(m), tx_buf, tx_buflen); ret = 1; tx_buflen = 0; goto retry; @@ -113,14 +114,14 @@ retry: return ret; } -ssize_t mcast_buffered_pending_netmsg(struct mcast_sock *m) +ssize_t mcast_buffered_pending_netmsg(struct mcast_sock_multi *m) { ssize_t ret; if (tx_buflen == 0) return 0; - ret = mcast_send(m, tx_buf, tx_buflen); + ret = mcast_send(mcast_get_current_link(m), tx_buf, tx_buflen); tx_buflen = 0; return ret; diff --git a/src/read_config_lex.l b/src/read_config_lex.l index f8b0ba1..e9e5d43 100644 --- a/src/read_config_lex.l +++ b/src/read_config_lex.l @@ -118,6 +118,7 @@ notrack [N|n][O|o][T|t][R|r][A|a][C|c][K|k] "Userspace" { return T_USERSPACE; } "Kernelspace" { return T_KERNELSPACE; } "EventIterationLimit" { return T_EVENT_ITER_LIMIT; } +"Default" { return T_DEFAULT; } {is_on} { return T_ON; } {is_off} { return T_OFF; } diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 274bfc3..de6cef3 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -38,6 +38,7 @@ struct ct_conf conf; static void __kernel_filter_start(void); static void __kernel_filter_add_state(int value); +static void __max_mcast_dedicated_links_reached(void); %} %union { @@ -59,7 +60,7 @@ static void __kernel_filter_add_state(int value); %token T_SYSLOG T_WRITE_THROUGH T_STAT_BUFFER_SIZE T_DESTROY_TIMEOUT %token T_MCAST_RCVBUFF T_MCAST_SNDBUFF T_NOTRACK %token T_FILTER T_ADDRESS T_PROTOCOL T_STATE T_ACCEPT T_IGNORE -%token T_FROM T_USERSPACE T_KERNELSPACE T_EVENT_ITER_LIMIT +%token T_FROM T_USERSPACE T_KERNELSPACE T_EVENT_ITER_LIMIT T_DEFAULT %token T_IP T_PATH_VAL %token T_NUMBER @@ -174,14 +175,22 @@ checksum: T_CHECKSUM T_ON { fprintf(stderr, "WARNING: The use of `Checksum' outside the " "`Multicast' clause is ambiguous.\n"); - conf.mcast.checksum = 0; + /* + * XXX: The use of Checksum outside of the Multicast clause is broken + * if we have more than one dedicated links. + */ + conf.mcast[0].checksum = 0; }; checksum: T_CHECKSUM T_OFF { fprintf(stderr, "WARNING: The use of `Checksum' outside the " "`Multicast' clause is ambiguous.\n"); - conf.mcast.checksum = 1; + /* + * XXX: The use of Checksum outside of the Multicast clause is broken + * if we have more than one dedicated links. + */ + conf.mcast[0].checksum = 1; }; ignore_traffic : T_IGNORE_TRAFFIC '{' ignore_traffic_options '}' @@ -243,32 +252,45 @@ ignore_traffic_option : T_IPV6_ADDR T_IP }; -multicast_line : T_MULTICAST '{' multicast_options '}'; +multicast_line : T_MULTICAST '{' multicast_options '}' +{ + conf.mcast_links++; +}; + +multicast_line : T_MULTICAST T_DEFAULT '{' multicast_options '}' +{ + conf.mcast_default_link = conf.mcast_links; + conf.mcast_links++; +}; multicast_options : | multicast_options multicast_option; multicast_option : T_IPV4_ADDR T_IP { - if (!inet_aton($2, &conf.mcast.in)) { + __max_mcast_dedicated_links_reached(); + + if (!inet_aton($2, &conf.mcast[conf.mcast_links].in)) { fprintf(stderr, "%s is not a valid IPv4 address\n", $2); break; } - if (conf.mcast.ipproto == AF_INET6) { + if (conf.mcast[conf.mcast_links].ipproto == AF_INET6) { fprintf(stderr, "Your multicast address is IPv4 but " "is binded to an IPv6 interface? Surely " "this is not what you want\n"); break; } - conf.mcast.ipproto = AF_INET; + conf.mcast[conf.mcast_links].ipproto = AF_INET; }; multicast_option : T_IPV6_ADDR T_IP { + __max_mcast_dedicated_links_reached(); + #ifdef HAVE_INET_PTON_IPV6 - if (inet_pton(AF_INET6, $2, &conf.mcast.in) <= 0) { + if (inet_pton(AF_INET6, $2, &conf.mcast[conf.mcast_links].in) <= 0) { fprintf(stderr, "%s is not a valid IPv6 address\n", $2); break; } @@ -277,16 +299,17 @@ multicast_option : T_IPV6_ADDR T_IP break; #endif - if (conf.mcast.ipproto == AF_INET) { + if (conf.mcast[conf.mcast_links].ipproto == AF_INET) { fprintf(stderr, "Your multicast address is IPv6 but " "is binded to an IPv4 interface? Surely " "this is not what you want\n"); break; } - conf.mcast.ipproto = AF_INET6; + conf.mcast[conf.mcast_links].ipproto = AF_INET6; - if (conf.mcast.iface[0] && !conf.mcast.ifa.interface_index6) { + if (conf.mcast[conf.mcast_links].iface[0] && + !conf.mcast[conf.mcast_links].ifa.interface_index6) { unsigned int idx; idx = if_nametoindex($2); @@ -295,26 +318,28 @@ multicast_option : T_IPV6_ADDR T_IP break; } - conf.mcast.ifa.interface_index6 = idx; - conf.mcast.ipproto = AF_INET6; + conf.mcast[conf.mcast_links].ifa.interface_index6 = idx; + conf.mcast[conf.mcast_links].ipproto = AF_INET6; } }; multicast_option : T_IPV4_IFACE T_IP { - if (!inet_aton($2, &conf.mcast.ifa)) { + __max_mcast_dedicated_links_reached(); + + if (!inet_aton($2, &conf.mcast[conf.mcast_links].ifa)) { fprintf(stderr, "%s is not a valid IPv4 address\n", $2); break; } - if (conf.mcast.ipproto == AF_INET6) { + if (conf.mcast[conf.mcast_links].ipproto == AF_INET6) { fprintf(stderr, "Your multicast interface is IPv4 but " "is binded to an IPv6 interface? Surely " "this is not what you want\n"); break; } - conf.mcast.ipproto = AF_INET; + conf.mcast[conf.mcast_links].ipproto = AF_INET; }; multicast_option : T_IPV6_IFACE T_IP @@ -324,19 +349,22 @@ multicast_option : T_IPV6_IFACE T_IP multicast_option : T_IFACE T_STRING { - strncpy(conf.mcast.iface, $2, IFNAMSIZ); + unsigned int idx; - if (conf.mcast.ipproto == AF_INET6) { - unsigned int idx; + __max_mcast_dedicated_links_reached(); - idx = if_nametoindex($2); - if (!idx) { - fprintf(stderr, "%s is an invalid interface.\n", $2); - break; - } + strncpy(conf.mcast[conf.mcast_links].iface, $2, IFNAMSIZ); + + idx = if_nametoindex($2); + if (!idx) { + fprintf(stderr, "%s is an invalid interface.\n", $2); + break; + } + conf.mcast[conf.mcast_links].interface_idx = idx; - conf.mcast.ifa.interface_index6 = idx; - conf.mcast.ipproto = AF_INET6; + if (conf.mcast[conf.mcast_links].ipproto == AF_INET6) { + conf.mcast[conf.mcast_links].ifa.interface_index6 = idx; + conf.mcast[conf.mcast_links].ipproto = AF_INET6; } }; @@ -348,27 +376,32 @@ multicast_option : T_BACKLOG T_NUMBER multicast_option : T_GROUP T_NUMBER { - conf.mcast.port = $2; + __max_mcast_dedicated_links_reached(); + conf.mcast[conf.mcast_links].port = $2; }; multicast_option: T_MCAST_SNDBUFF T_NUMBER { - conf.mcast.sndbuf = $2; + __max_mcast_dedicated_links_reached(); + conf.mcast[conf.mcast_links].sndbuf = $2; }; multicast_option: T_MCAST_RCVBUFF T_NUMBER { - conf.mcast.rcvbuf = $2; + __max_mcast_dedicated_links_reached(); + conf.mcast[conf.mcast_links].rcvbuf = $2; }; multicast_option: T_CHECKSUM T_ON { - conf.mcast.checksum = 0; + __max_mcast_dedicated_links_reached(); + conf.mcast[conf.mcast_links].checksum = 0; }; multicast_option: T_CHECKSUM T_OFF { - conf.mcast.checksum = 1; + __max_mcast_dedicated_links_reached(); + conf.mcast[conf.mcast_links].checksum = 1; }; hashsize : T_HASHSIZE T_NUMBER @@ -1050,6 +1083,16 @@ static void __kernel_filter_add_state(int value) &filter_proto); } +static void __max_mcast_dedicated_links_reached(void) +{ + if (conf.mcast_links >= MCAST_LINKS_MAX) { + fprintf(stderr, "ERROR: too many dedicated links in " + "the configuration file (Maximum: %d).\n", + MCAST_LINKS_MAX); + exit(EXIT_FAILURE); + } +} + int init_config(char *filename) { diff --git a/src/sync-mode.c b/src/sync-mode.c index 00e2f7b..0dbd12d 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -33,8 +33,10 @@ #include #include #include +#include -static void do_mcast_handler_step(struct nethdr *net, size_t remain) +static void +do_mcast_handler_step(int if_idx, struct nethdr *net, size_t remain) { char __ct[nfct_maxsize()]; struct nf_conntrack *ct = (struct nf_conntrack *)(void*) __ct; @@ -47,6 +49,9 @@ static void do_mcast_handler_step(struct nethdr *net, size_t remain) return; } + if (if_idx != mcast_get_current_ifidx(STATE_SYNC(mcast_client))) + mcast_set_current_link(STATE_SYNC(mcast_client), if_idx); + switch (STATE_SYNC(sync)->recv(net)) { case MSG_DATA: break; @@ -111,13 +116,13 @@ retry: } /* handler for multicast messages received */ -static void mcast_handler(void) +static void mcast_handler(struct mcast_sock *m, int if_idx) { ssize_t numbytes; ssize_t remain; char __net[65536], *ptr = __net; /* XXX: maximum MTU for IPv4 */ - numbytes = mcast_recv(STATE_SYNC(mcast_server), __net, sizeof(__net)); + numbytes = mcast_recv(m, __net, sizeof(__net)); if (numbytes <= 0) return; @@ -160,12 +165,46 @@ static void mcast_handler(void) HDR_NETWORK2HOST(net); - do_mcast_handler_step(net, remain); + do_mcast_handler_step(if_idx, net, remain); ptr += net->len; remain -= net->len; } } +/* select a new interface candidate in a round robin basis */ +static void mcast_iface_candidate(void) +{ + int i, idx; + unsigned int flags; + char buf[IFNAMSIZ]; + + for (i=0; inum_links; i++) { + idx = mcast_get_ifidx(STATE_SYNC(mcast_client), i); + if (idx == mcast_get_current_ifidx(STATE_SYNC(mcast_client))) + continue; + nlif_get_ifflags(STATE_SYNC(mcast_iface), idx, &flags); + if (flags & (IFF_RUNNING | IFF_UP)) { + mcast_set_current_link(STATE_SYNC(mcast_client), i); + dlog(LOG_NOTICE, "device `%s' becomes multicast " + "dedicated link", + if_indextoname(idx, buf)); + return; + } + } + dlog(LOG_ERR, "no dedicated links available!"); +} + +static void mcast_iface_handler(void) +{ + int idx = mcast_get_current_ifidx(STATE_SYNC(mcast_client)); + unsigned int flags; + + nlif_catch(STATE_SYNC(mcast_iface)); + nlif_get_ifflags(STATE_SYNC(mcast_iface), idx, &flags); + if (!(flags & IFF_RUNNING) || !(flags & IFF_UP)) + mcast_iface_candidate(); +} + static int init_sync(void) { state.sync = malloc(sizeof(struct ct_sync_state)); @@ -216,30 +255,35 @@ static int init_sync(void) } /* multicast server to receive events from the wire */ - STATE_SYNC(mcast_server) = mcast_server_create(&CONFIG(mcast)); + STATE_SYNC(mcast_server) = + mcast_server_create_multi(CONFIG(mcast), CONFIG(mcast_links)); if (STATE_SYNC(mcast_server) == NULL) { dlog(LOG_ERR, "can't open multicast server!"); return -1; } - dlog(LOG_NOTICE, "multicast server socket receiver queue " - "has been set to %d bytes", CONFIG(mcast).rcvbuf); - /* multicast client to send events on the wire */ - STATE_SYNC(mcast_client) = mcast_client_create(&CONFIG(mcast)); + STATE_SYNC(mcast_client) = + mcast_client_create_multi(CONFIG(mcast), CONFIG(mcast_links)); if (STATE_SYNC(mcast_client) == NULL) { dlog(LOG_ERR, "can't open client multicast socket"); - mcast_server_destroy(STATE_SYNC(mcast_server)); + mcast_server_destroy_multi(STATE_SYNC(mcast_server)); return -1; } + /* we only use one link to send events, but all to receive them */ + mcast_set_current_link(STATE_SYNC(mcast_client), + CONFIG(mcast_default_link)); - dlog(LOG_NOTICE, "multicast client socket sender queue " - "has been set to %d bytes", CONFIG(mcast).sndbuf); - - if (mcast_buffered_init(CONFIG(mcast).mtu) == -1) { + if (mcast_buffered_init(STATE_SYNC(mcast_client)->max_mtu) == -1) { dlog(LOG_ERR, "can't init tx buffer!"); - mcast_server_destroy(STATE_SYNC(mcast_server)); - mcast_client_destroy(STATE_SYNC(mcast_client)); + mcast_server_destroy_multi(STATE_SYNC(mcast_server)); + mcast_client_destroy_multi(STATE_SYNC(mcast_client)); + return -1; + } + + STATE_SYNC(mcast_iface) = nl_init_interface_handler(); + if (!STATE_SYNC(mcast_iface)) { + dlog(LOG_ERR, "can't open interface watcher"); return -1; } @@ -257,7 +301,14 @@ static int init_sync(void) static int register_fds_sync(struct fds *fds) { - if (register_fd(STATE_SYNC(mcast_server->fd), fds) == -1) + int i; + + for (i=0; inum_links; i++) { + int fd = mcast_get_fd(STATE_SYNC(mcast_server)->multi[i]); + if (register_fd(fd, fds) == -1) + return -1; + } + if (register_fd(nlif_fd(STATE_SYNC(mcast_iface)), fds) == -1) return -1; if (register_fd(queue_get_eventfd(STATE_SYNC(tx_queue)), fds) == -1) @@ -268,13 +319,20 @@ static int register_fds_sync(struct fds *fds) static void run_sync(fd_set *readfds) { - /* multicast packet has been received */ - if (FD_ISSET(STATE_SYNC(mcast_server->fd), readfds)) - mcast_handler(); + int i; + + for (i=0; inum_links; i++) { + int fd = mcast_get_fd(STATE_SYNC(mcast_server)->multi[i]); + if (FD_ISSET(fd, readfds)) + mcast_handler(STATE_SYNC(mcast_server)->multi[i], i); + } if (FD_ISSET(queue_get_eventfd(STATE_SYNC(tx_queue)), readfds)) STATE_SYNC(sync)->xmit(); + if (FD_ISSET(nlif_fd(STATE_SYNC(mcast_iface)), readfds)) + mcast_iface_handler(); + /* flush pending messages */ mcast_buffered_pending_netmsg(STATE_SYNC(mcast_client)); } @@ -284,8 +342,10 @@ static void kill_sync(void) cache_destroy(STATE_SYNC(internal)); cache_destroy(STATE_SYNC(external)); - mcast_server_destroy(STATE_SYNC(mcast_server)); - mcast_client_destroy(STATE_SYNC(mcast_client)); + mcast_server_destroy_multi(STATE_SYNC(mcast_server)); + mcast_client_destroy_multi(STATE_SYNC(mcast_client)); + + nlif_close(STATE_SYNC(mcast_iface)); mcast_buffered_destroy(); queue_destroy(STATE_SYNC(tx_queue)); @@ -418,6 +478,11 @@ static int local_handler_sync(int fd, int type, void *data) cache_stats_extended(STATE_SYNC(internal), fd); cache_stats_extended(STATE_SYNC(external), fd); break; + case STATS_MULTICAST: + mcast_dump_stats_extended(fd, STATE_SYNC(mcast_client), + STATE_SYNC(mcast_server), + STATE_SYNC(mcast_iface)); + break; default: if (STATE_SYNC(sync)->local) ret = STATE_SYNC(sync)->local(fd, type, data); -- cgit v1.2.3 From c54c8c9287fc87177daf9b51933f92c7e6402904 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 17 Jan 2009 18:03:52 +0100 Subject: src: rename overrun handler to resync handler This patch is a cleanup. The overrun handler is actually a way to resynchronize against the conntrack kernel table. The name overrun was used because it was initially its purpose. The new naming shows its genericity. Signed-off-by: Pablo Neira Ayuso --- include/conntrackd.h | 10 +++++----- include/netlink.h | 4 ++-- src/netlink.c | 4 ++-- src/run.c | 22 +++++++++++----------- src/stats-mode.c | 12 ++++++------ src/sync-mode.c | 12 ++++++------ 6 files changed, 32 insertions(+), 32 deletions(-) (limited to 'src') diff --git a/include/conntrackd.h b/include/conntrackd.h index ab5d825..d5b61c6 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -111,8 +111,8 @@ struct ct_general_state { struct nfct_handle *dump; /* dump handler */ struct nfct_handle *request; /* request handler */ - struct nfct_handle *overrun; /* overrun handler */ - struct alarm_block overrun_alarm; + struct nfct_handle *resync; /* resync handler */ + struct alarm_block resync_alarm; struct fds *fds; @@ -204,9 +204,9 @@ struct ct_mode { int (*local)(int fd, int type, void *data); void (*kill)(void); void (*dump)(struct nf_conntrack *ct); - int (*overrun)(enum nf_conntrack_msg_type type, - struct nf_conntrack *ct, - void *data); + int (*resync)(enum nf_conntrack_msg_type type, + struct nf_conntrack *ct, + void *data); int (*purge)(void); void (*event_new)(struct nf_conntrack *ct); void (*event_upd)(struct nf_conntrack *ct); diff --git a/include/netlink.h b/include/netlink.h index 4bc5ee4..a8eb919 100644 --- a/include/netlink.h +++ b/include/netlink.h @@ -9,10 +9,10 @@ struct nfct_handle; struct nfct_handle *nl_init_event_handler(void); struct nfct_handle *nl_init_dump_handler(void); struct nfct_handle *nl_init_request_handler(void); -struct nfct_handle *nl_init_overrun_handler(void); +struct nfct_handle *nl_init_resync_handler(void); struct nlif_handle *nl_init_interface_handler(void); -int nl_overrun_request_resync(struct nfct_handle *h); +int nl_send_resync(struct nfct_handle *h); void nl_resize_socket_buffer(struct nfct_handle *h); int nl_dump_conntrack_table(struct nfct_handle *h); int nl_flush_conntrack_table(struct nfct_handle *h); diff --git a/src/netlink.c b/src/netlink.c index 2266201..15a30f6 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -90,7 +90,7 @@ struct nfct_handle *nl_init_dump_handler(void) return h; } -struct nfct_handle *nl_init_overrun_handler(void) +struct nfct_handle *nl_init_resync_handler(void) { struct nfct_handle *h; @@ -172,7 +172,7 @@ int nl_flush_conntrack_table(struct nfct_handle *h) return nfct_query(h, NFCT_Q_FLUSH, &CONFIG(family)); } -int nl_overrun_request_resync(struct nfct_handle *h) +int nl_send_resync(struct nfct_handle *h) { int family = CONFIG(family); return nfct_send(h, NFCT_Q_DUMP, &family); diff --git a/src/run.c b/src/run.c index 2e373ce..b436113 100644 --- a/src/run.c +++ b/src/run.c @@ -204,9 +204,9 @@ void local_handler(int fd, void *data) STATE(stats).local_unknown_request++; } -static void do_overrun_alarm(struct alarm_block *a, void *data) +static void do_resync_alarm(struct alarm_block *a, void *data) { - nl_overrun_request_resync(STATE(overrun)); + nl_send_resync(STATE(resync)); STATE(stats).nl_kernel_table_resync++; } @@ -313,16 +313,16 @@ init(void) return -1; } - STATE(overrun) = nl_init_overrun_handler(); - if (STATE(overrun)== NULL) { + STATE(resync) = nl_init_resync_handler(); + if (STATE(resync)== NULL) { dlog(LOG_ERR, "can't open netlink handler: %s", strerror(errno)); dlog(LOG_ERR, "no ctnetlink kernel support?"); return -1; } - nfct_callback_register(STATE(overrun), + nfct_callback_register(STATE(resync), NFCT_T_ALL, - STATE(mode)->overrun, + STATE(mode)->resync, NULL); /* no callback, it does not do anything with the output */ @@ -334,7 +334,7 @@ init(void) return -1; } - init_alarm(&STATE(overrun_alarm), NULL, do_overrun_alarm); + init_alarm(&STATE(resync_alarm), NULL, do_resync_alarm); STATE(fds) = create_fds(); if (STATE(fds) == NULL) { @@ -344,7 +344,7 @@ init(void) register_fd(STATE(local).fd, STATE(fds)); register_fd(nfct_fd(STATE(event)), STATE(fds)); - register_fd(nfct_fd(STATE(overrun)), STATE(fds)); + register_fd(nfct_fd(STATE(resync)), STATE(fds)); if (STATE(mode)->register_fds && STATE(mode)->register_fds(STATE(fds)) == -1) { @@ -435,7 +435,7 @@ static void __run(struct timeval *next_alarm) * we resync ourselves. */ nl_resize_socket_buffer(STATE(event)); - add_alarm(&STATE(overrun_alarm), OVRUN_INT, 0); + add_alarm(&STATE(resync_alarm), OVRUN_INT, 0); STATE(stats).nl_catch_event_failed++; STATE(stats).nl_overrun++; break; @@ -455,8 +455,8 @@ static void __run(struct timeval *next_alarm) } } - if (FD_ISSET(nfct_fd(STATE(overrun)), &readfds)) { - nfct_catch(STATE(overrun)); + if (FD_ISSET(nfct_fd(STATE(resync)), &readfds)) { + nfct_catch(STATE(resync)); if (STATE(mode)->purge) STATE(mode)->purge(); } diff --git a/src/stats-mode.c b/src/stats-mode.c index 679a50c..159bbef 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -102,9 +102,9 @@ static void dump_stats(struct nf_conntrack *ct) debug_ct(ct, "resync entry"); } -static int overrun_stats(enum nf_conntrack_msg_type type, - struct nf_conntrack *ct, - void *data) +static int resync_stats(enum nf_conntrack_msg_type type, + struct nf_conntrack *ct, + void *data) { if (ct_filter_conntrack(ct, 1)) return NFCT_CB_CONTINUE; @@ -118,7 +118,7 @@ static int overrun_stats(enum nf_conntrack_msg_type type, nfct_attr_unset(ct, ATTR_USE); if (!cache_update_force(STATE_STATS(cache), ct)) - debug_ct(ct, "overrun stats resync"); + debug_ct(ct, "stats resync"); return NFCT_CB_CONTINUE; } @@ -130,7 +130,7 @@ static int purge_step(void *data1, void *data2) ret = nfct_query(STATE(dump), NFCT_Q_GET, obj->ct); if (ret == -1 && errno == ENOENT) { - debug_ct(obj->ct, "overrun purge stats"); + debug_ct(obj->ct, "purge stats"); cache_del(STATE_STATS(cache), obj); cache_object_free(obj); } @@ -196,7 +196,7 @@ struct ct_mode stats_mode = { .local = local_handler_stats, .kill = kill_stats, .dump = dump_stats, - .overrun = overrun_stats, + .resync = resync_stats, .purge = purge_stats, .event_new = event_new_stats, .event_upd = event_update_stats, diff --git a/src/sync-mode.c b/src/sync-mode.c index 0dbd12d..2e189cb 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -518,7 +518,7 @@ static int purge_step(void *data1, void *data2) ret = nfct_query(h, NFCT_Q_GET, obj->ct); if (ret == -1 && errno == ENOENT) { - debug_ct(obj->ct, "overrun purge resync"); + debug_ct(obj->ct, "purge resync"); if (obj->status != C_OBJ_DEAD) { cache_object_set_status(obj, C_OBJ_DEAD); mcast_send_sync(obj, NET_T_STATE_DEL); @@ -536,9 +536,9 @@ static int purge_sync(void) return 0; } -static int overrun_sync(enum nf_conntrack_msg_type type, - struct nf_conntrack *ct, - void *data) +static int resync_sync(enum nf_conntrack_msg_type type, + struct nf_conntrack *ct, + void *data) { struct cache_object *obj; @@ -553,7 +553,7 @@ static int overrun_sync(enum nf_conntrack_msg_type type, nfct_attr_unset(ct, ATTR_USE); if ((obj = cache_update_force(STATE_SYNC(internal), ct))) { - debug_ct(obj->ct, "overrun resync"); + debug_ct(obj->ct, "resync"); mcast_send_sync(obj, NET_T_STATE_UPD); } @@ -629,7 +629,7 @@ struct ct_mode sync_mode = { .local = local_handler_sync, .kill = kill_sync, .dump = dump_sync, - .overrun = overrun_sync, + .resync = resync_sync, .purge = purge_sync, .event_new = event_new_sync, .event_upd = event_update_sync, -- cgit v1.2.3 From 05194422ee8fa038d99fe77a2e9d776d25623fd2 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 17 Jan 2009 18:03:53 +0100 Subject: src: remove register_fds hooks This patch moves the file descriptor registration after the initialization instead of having a specific hook for this. Signed-off-by: Pablo Neira Ayuso --- include/conntrackd.h | 1 - src/run.c | 25 +++++++++---------------- src/stats-mode.c | 1 - src/sync-mode.c | 31 ++++++++++++------------------- 4 files changed, 21 insertions(+), 37 deletions(-) (limited to 'src') diff --git a/include/conntrackd.h b/include/conntrackd.h index d5b61c6..fbf126a 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -199,7 +199,6 @@ extern struct ct_general_state st; struct ct_mode { int (*init)(void); - int (*register_fds)(struct fds *fds); void (*run)(fd_set *readfds); int (*local)(int fd, int type, void *data); void (*kill)(void); diff --git a/src/run.c b/src/run.c index b436113..a6dfe15 100644 --- a/src/run.c +++ b/src/run.c @@ -278,6 +278,12 @@ init(void) STATE(mode) = &stats_mode; } + STATE(fds) = create_fds(); + if (STATE(fds) == NULL) { + dlog(LOG_ERR, "can't create file descriptor pool"); + return -1; + } + /* Initialization */ if (STATE(mode)->init() == -1) { dlog(LOG_ERR, "initialization failed"); @@ -289,6 +295,7 @@ init(void) dlog(LOG_ERR, "can't open unix socket!"); return -1; } + register_fd(STATE(local).fd, STATE(fds)); STATE(event) = nl_init_event_handler(); if (STATE(event) == NULL) { @@ -298,6 +305,7 @@ init(void) return -1; } nfct_callback_register(STATE(event), NFCT_T_ALL, event_handler, NULL); + register_fd(nfct_fd(STATE(event)), STATE(fds)); STATE(dump) = nl_init_dump_handler(); if (STATE(dump) == NULL) { @@ -324,6 +332,7 @@ init(void) NFCT_T_ALL, STATE(mode)->resync, NULL); + register_fd(nfct_fd(STATE(resync)), STATE(fds)); /* no callback, it does not do anything with the output */ STATE(request) = nl_init_request_handler(); @@ -336,22 +345,6 @@ init(void) init_alarm(&STATE(resync_alarm), NULL, do_resync_alarm); - STATE(fds) = create_fds(); - if (STATE(fds) == NULL) { - dlog(LOG_ERR, "can't create file descriptor pool"); - return -1; - } - - register_fd(STATE(local).fd, STATE(fds)); - register_fd(nfct_fd(STATE(event)), STATE(fds)); - register_fd(nfct_fd(STATE(resync)), STATE(fds)); - - if (STATE(mode)->register_fds && - STATE(mode)->register_fds(STATE(fds)) == -1) { - dlog(LOG_ERR, "fds registration failed"); - return -1; - } - /* Signals handling */ sigemptyset(&STATE(block)); sigaddset(&STATE(block), SIGTERM); diff --git a/src/stats-mode.c b/src/stats-mode.c index 159bbef..b742c0c 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -191,7 +191,6 @@ static int event_destroy_stats(struct nf_conntrack *ct) struct ct_mode stats_mode = { .init = init_stats, - .register_fds = NULL, .run = NULL, .local = local_handler_stats, .kill = kill_stats, diff --git a/src/sync-mode.c b/src/sync-mode.c index 2e189cb..54d0ebb 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -207,6 +207,8 @@ static void mcast_iface_handler(void) static int init_sync(void) { + int i; + state.sync = malloc(sizeof(struct ct_sync_state)); if (!state.sync) { dlog(LOG_ERR, "can't allocate memory for sync"); @@ -261,6 +263,11 @@ static int init_sync(void) dlog(LOG_ERR, "can't open multicast server!"); return -1; } + for (i=0; inum_links; i++) { + int fd = mcast_get_fd(STATE_SYNC(mcast_server)->multi[i]); + if (register_fd(fd, STATE(fds)) == -1) + return -1; + } /* multicast client to send events on the wire */ STATE_SYNC(mcast_client) = @@ -286,12 +293,17 @@ static int init_sync(void) dlog(LOG_ERR, "can't open interface watcher"); return -1; } + if (register_fd(nlif_fd(STATE_SYNC(mcast_iface)), STATE(fds)) == -1) + return -1; STATE_SYNC(tx_queue) = queue_create(INT_MAX, QUEUE_F_EVFD); if (STATE_SYNC(tx_queue) == NULL) { dlog(LOG_ERR, "cannot create tx queue"); return -1; } + if (register_fd(queue_get_eventfd(STATE_SYNC(tx_queue)), + STATE(fds)) == -1) + return -1; /* initialization of multicast sequence generation */ STATE_SYNC(last_seq_sent) = time(NULL); @@ -299,24 +311,6 @@ static int init_sync(void) return 0; } -static int register_fds_sync(struct fds *fds) -{ - int i; - - for (i=0; inum_links; i++) { - int fd = mcast_get_fd(STATE_SYNC(mcast_server)->multi[i]); - if (register_fd(fd, fds) == -1) - return -1; - } - if (register_fd(nlif_fd(STATE_SYNC(mcast_iface)), fds) == -1) - return -1; - - if (register_fd(queue_get_eventfd(STATE_SYNC(tx_queue)), fds) == -1) - return -1; - - return 0; -} - static void run_sync(fd_set *readfds) { int i; @@ -624,7 +618,6 @@ static int event_destroy_sync(struct nf_conntrack *ct) struct ct_mode sync_mode = { .init = init_sync, - .register_fds = register_fds_sync, .run = run_sync, .local = local_handler_sync, .kill = kill_sync, -- cgit v1.2.3 From 746f7031f4d1e3bccdd6db3c53835d8b85b73c90 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 17 Jan 2009 18:03:53 +0100 Subject: src: add state polling support (oppossed to current event-driven) This patch adds the clause PollSecs that changes the normal behaviour of conntrackd. With PollSecs set to > 0, conntrackd polls every N seconds the entries. This is the opposed behaviour of an event-driven behaviour but may be useful for those that have really strong limitations in terms of CPU consumption and want to perform a relaxed replication. Signed-off-by: Pablo Neira Ayuso --- doc/stats/conntrackd.conf | 12 ++++++++++++ doc/sync/alarm/conntrackd.conf | 12 ++++++++++++ doc/sync/ftfw/conntrackd.conf | 12 ++++++++++++ doc/sync/notrack/conntrackd.conf | 12 ++++++++++++ include/conntrackd.h | 2 ++ src/read_config_lex.l | 1 + src/read_config_yy.y | 13 ++++++++++++- src/run.c | 41 ++++++++++++++++++++++++++++------------ 8 files changed, 92 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/doc/stats/conntrackd.conf b/doc/stats/conntrackd.conf index 1fc21af..889d387 100644 --- a/doc/stats/conntrackd.conf +++ b/doc/stats/conntrackd.conf @@ -91,6 +91,18 @@ Stats { # LogFile on + # + # By default, the daemon receives state updates following an + # event-driven model. You can modify this behaviour by switching to + # polling mode with the PollSecs clause. This clause tells conntrackd + # to dump the states in the kernel every N seconds. With regards to + # synchronization mode, the polling mode can only guarantee that + # long-lifetime states are recovered. The main advantage of this method + # is the reduction in the state replication at the cost of reducing the + # chances of recovering connections. + # + # PollSecs 15 + # # Enable connection logging via Syslog. Default is off. # Syslog: on, off or a facility name (daemon (default) or local0..7) diff --git a/doc/sync/alarm/conntrackd.conf b/doc/sync/alarm/conntrackd.conf index 528ff8f..3479a83 100644 --- a/doc/sync/alarm/conntrackd.conf +++ b/doc/sync/alarm/conntrackd.conf @@ -183,6 +183,18 @@ General { # SocketBufferSizeMaxGrowth 8388608 + # + # By default, the daemon receives state updates following an + # event-driven model. You can modify this behaviour by switching to + # polling mode with the PollSecs clause. This clause tells conntrackd + # to dump the states in the kernel every N seconds. With regards to + # synchronization mode, the polling mode can only guarantee that + # long-lifetime states are recovered. The main advantage of this method + # is the reduction in the state replication at the cost of reducing the + # chances of recovering connections. + # + # PollSecs 15 + # # The daemon prioritizes the handling of state-change events coming # from the core. With this clause, you can set the maximum number of diff --git a/doc/sync/ftfw/conntrackd.conf b/doc/sync/ftfw/conntrackd.conf index 2e60f2c..77ef76c 100644 --- a/doc/sync/ftfw/conntrackd.conf +++ b/doc/sync/ftfw/conntrackd.conf @@ -191,6 +191,18 @@ General { # SocketBufferSizeMaxGrowth 8388608 + # + # By default, the daemon receives state updates following an + # event-driven model. You can modify this behaviour by switching to + # polling mode with the PollSecs clause. This clause tells conntrackd + # to dump the states in the kernel every N seconds. With regards to + # synchronization mode, the polling mode can only guarantee that + # long-lifetime states are recovered. The main advantage of this method + # is the reduction in the state replication at the cost of reducing the + # chances of recovering connections. + # + # PollSecs 15 + # # The daemon prioritizes the handling of state-change events coming # from the core. With this clause, you can set the maximum number of diff --git a/doc/sync/notrack/conntrackd.conf b/doc/sync/notrack/conntrackd.conf index 7f8c8a3..5abf589 100644 --- a/doc/sync/notrack/conntrackd.conf +++ b/doc/sync/notrack/conntrackd.conf @@ -173,6 +173,18 @@ General { # SocketBufferSizeMaxGrowth 8388608 + # + # By default, the daemon receives state updates following an + # event-driven model. You can modify this behaviour by switching to + # polling mode with the PollSecs clause. This clause tells conntrackd + # to dump the states in the kernel every N seconds. With regards to + # synchronization mode, the polling mode can only guarantee that + # long-lifetime states are recovered. The main advantage of this method + # is the reduction in the state replication at the cost of reducing the + # chances of recovering connections. + # + # PollSecs 15 + # # The daemon prioritizes the handling of state-change events coming # from the core. With this clause, you can set the maximum number of diff --git a/include/conntrackd.h b/include/conntrackd.h index fbf126a..acf907c 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -48,6 +48,7 @@ #define CTD_SYNC_FTFW (1UL << 2) #define CTD_SYNC_ALARM (1UL << 3) #define CTD_SYNC_NOTRACK (1UL << 4) +#define CTD_POLL (1UL << 5) /* FILENAME_MAX is 4096 on my system, perhaps too much? */ #ifndef FILENAME_MAXLEN @@ -85,6 +86,7 @@ struct ct_conf { int family; /* protocol family */ unsigned int resend_queue_size; /* FTFW protocol */ unsigned int window_size; + int poll_kernel_secs; int cache_write_through; int filter_from_kernelspace; int event_iterations_limit; diff --git a/src/read_config_lex.l b/src/read_config_lex.l index e9e5d43..4953974 100644 --- a/src/read_config_lex.l +++ b/src/read_config_lex.l @@ -119,6 +119,7 @@ notrack [N|n][O|o][T|t][R|r][A|a][C|c][K|k] "Kernelspace" { return T_KERNELSPACE; } "EventIterationLimit" { return T_EVENT_ITER_LIMIT; } "Default" { return T_DEFAULT; } +"PollSecs" { return T_POLL_SECS; } {is_on} { return T_ON; } {is_off} { return T_OFF; } diff --git a/src/read_config_yy.y b/src/read_config_yy.y index de6cef3..ce604d9 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -58,7 +58,7 @@ static void __max_mcast_dedicated_links_reached(void); %token T_ESTABLISHED T_SYN_SENT T_SYN_RECV T_FIN_WAIT %token T_CLOSE_WAIT T_LAST_ACK T_TIME_WAIT T_CLOSE T_LISTEN %token T_SYSLOG T_WRITE_THROUGH T_STAT_BUFFER_SIZE T_DESTROY_TIMEOUT -%token T_MCAST_RCVBUFF T_MCAST_SNDBUFF T_NOTRACK +%token T_MCAST_RCVBUFF T_MCAST_SNDBUFF T_NOTRACK T_POLL_SECS %token T_FILTER T_ADDRESS T_PROTOCOL T_STATE T_ACCEPT T_IGNORE %token T_FROM T_USERSPACE T_KERNELSPACE T_EVENT_ITER_LIMIT T_DEFAULT @@ -715,6 +715,7 @@ general_line: hashsize | netlink_buffer_size_max_grown | family | event_iterations_limit + | poll_secs | filter ; @@ -741,6 +742,16 @@ event_iterations_limit : T_EVENT_ITER_LIMIT T_NUMBER CONFIG(event_iterations_limit) = $2; }; +poll_secs: T_POLL_SECS T_NUMBER +{ + conf.flags |= CTD_POLL; + conf.poll_kernel_secs = $2; + if (conf.poll_kernel_secs == 0) { + fprintf(stderr, "ERROR: `PollSecs' clause must be > 0\n"); + exit(EXIT_FAILURE); + } +}; + filter : T_FILTER '{' filter_list '}' { CONFIG(filter_from_kernelspace) = 0; diff --git a/src/run.c b/src/run.c index a6dfe15..a483ab3 100644 --- a/src/run.c +++ b/src/run.c @@ -39,7 +39,8 @@ void killer(int foo) /* no signals while handling signals */ sigprocmask(SIG_BLOCK, &STATE(block), NULL); - nfct_close(STATE(event)); + if (!(CONFIG(flags) & CTD_POLL)) + nfct_close(STATE(event)); nfct_close(STATE(request)); if (STATE(us_filter)) @@ -204,12 +205,18 @@ void local_handler(int fd, void *data) STATE(stats).local_unknown_request++; } -static void do_resync_alarm(struct alarm_block *a, void *data) +static void do_overrun_resync_alarm(struct alarm_block *a, void *data) { nl_send_resync(STATE(resync)); STATE(stats).nl_kernel_table_resync++; } +static void do_poll_resync_alarm(struct alarm_block *a, void *data) +{ + nl_send_resync(STATE(resync)); + add_alarm(&STATE(resync_alarm), CONFIG(poll_kernel_secs), 0); +} + static int event_handler(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data) @@ -297,15 +304,18 @@ init(void) } register_fd(STATE(local).fd, STATE(fds)); - STATE(event) = nl_init_event_handler(); - if (STATE(event) == NULL) { - dlog(LOG_ERR, "can't open netlink handler: %s", - strerror(errno)); - dlog(LOG_ERR, "no ctnetlink kernel support?"); - return -1; + if (!(CONFIG(flags) & CTD_POLL)) { + STATE(event) = nl_init_event_handler(); + if (STATE(event) == NULL) { + dlog(LOG_ERR, "can't open netlink handler: %s", + strerror(errno)); + dlog(LOG_ERR, "no ctnetlink kernel support?"); + return -1; + } + nfct_callback_register(STATE(event), NFCT_T_ALL, + event_handler, NULL); + register_fd(nfct_fd(STATE(event)), STATE(fds)); } - nfct_callback_register(STATE(event), NFCT_T_ALL, event_handler, NULL); - register_fd(nfct_fd(STATE(event)), STATE(fds)); STATE(dump) = nl_init_dump_handler(); if (STATE(dump) == NULL) { @@ -343,7 +353,13 @@ init(void) return -1; } - init_alarm(&STATE(resync_alarm), NULL, do_resync_alarm); + if (CONFIG(flags) & CTD_POLL) { + init_alarm(&STATE(resync_alarm), NULL, do_poll_resync_alarm); + add_alarm(&STATE(resync_alarm), CONFIG(poll_kernel_secs), 0); + dlog(LOG_NOTICE, "running in polling mode"); + } else { + init_alarm(&STATE(resync_alarm), NULL, do_overrun_resync_alarm); + } /* Signals handling */ sigemptyset(&STATE(block)); @@ -397,7 +413,8 @@ static void __run(struct timeval *next_alarm) do_local_server_step(&STATE(local), NULL, local_handler); /* conntrack event has happened */ - if (FD_ISSET(nfct_fd(STATE(event)), &readfds)) { + if (!(CONFIG(flags) & CTD_POLL) && + FD_ISSET(nfct_fd(STATE(event)), &readfds)) { ret = nfct_catch(STATE(event)); if (ret == -1) { switch(errno) { -- cgit v1.2.3 From 7f5a53998abfc9b199b713244fe8baf0a7c2b2fe Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 17 Jan 2009 18:03:53 +0100 Subject: cache: add objects statistics This patch adds the object counter to `conntrackd -s cache'. This is useful to detect object leaks in runtime. This patch also changes the layout of the output to fit the display in less than 24 lines (assuming 24x80 terminal). Signed-off-by: Pablo Neira Ayuso --- include/cache.h | 2 ++ src/cache.c | 18 +++++++++--------- 2 files changed, 11 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/include/cache.h b/include/cache.h index 03b6822..697a64b 100644 --- a/include/cache.h +++ b/include/cache.h @@ -87,6 +87,8 @@ struct cache { uint32_t commit_fail; uint32_t flush; + + uint32_t objects; } stats; }; diff --git a/src/cache.c b/src/cache.c index 1e08a33..a5f37dd 100644 --- a/src/cache.c +++ b/src/cache.c @@ -194,12 +194,14 @@ struct cache_object *cache_object_new(struct cache *c, struct nf_conntrack *ct) } memcpy(obj->ct, ct, nfct_sizeof(ct)); obj->status = C_OBJ_NONE; + c->stats.objects++; return obj; } void cache_object_free(struct cache_object *obj) { + obj->cache->stats.objects--; nfct_destroy(obj->ct); free(obj); } @@ -387,18 +389,16 @@ void cache_stats_extended(const struct cache *c, int fd) int size; size = snprintf(buf, sizeof(buf), - "cache:%s\tactive/total entries:\t%12u/%12u\n" - "\tcreation OK:\t\t\t%12u\n" - "\tcreation failed:\t\t%12u\n" + "cache:%s\tactive objects:\t\t%12u\n" + "\tactive/total entries:\t\t%12u/%12u\n" + "\tcreation OK/failed:\t\t%12u/%12u\n" "\t\tno memory available:\t%12u\n" "\t\tno space left in cache:\t%12u\n" - "\tupdate OK:\t\t\t%12u\n" - "\tupdate failed:\t\t\t%12u\n" + "\tupdate OK/failed:\t\t%12u/%12u\n" "\t\tentry not found:\t%12u\n" - "\tdeletion created:\t\t%12u\n" - "\tdeletion failed:\t\t%12u\n" - "\t\tentry not found:\t%12u\n", - c->name, + "\tdeletion created/failed:\t%12u/%12u\n" + "\t\tentry not found:\t%12u\n\n", + c->name, c->stats.objects, c->stats.active, hashtable_counter(c->h), c->stats.add_ok, c->stats.add_fail, -- cgit v1.2.3 From a63f5181807803ffdd879edca9fd4d73c4be35f3 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 17 Jan 2009 18:24:57 +0100 Subject: ftfw: add ResendQueueSize and deprecate ResendBufferSize clauses This patch adds ResendQueueSize, which sets the number of objects that can be stored in the resend queue waiting to be confirmed. The ResendBufferSize clause has been deprecated. Signed-off-by: Pablo Neira Ayuso --- doc/sync/ftfw/conntrackd.conf | 15 ++++++++------- include/queue.h | 1 + src/queue.c | 7 +++++++ src/read_config_lex.l | 1 + src/read_config_yy.y | 13 ++++++++++--- src/sync-ftfw.c | 44 ++++++++++++++++++++++++++++++++++++++----- 6 files changed, 66 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/doc/sync/ftfw/conntrackd.conf b/doc/sync/ftfw/conntrackd.conf index 77ef76c..4fd86d7 100644 --- a/doc/sync/ftfw/conntrackd.conf +++ b/doc/sync/ftfw/conntrackd.conf @@ -4,14 +4,15 @@ Sync { Mode FTFW { # - # Size of the buffer that hold control messages for - # possible resends (in bytes). Under message omission, - # this size determines the length of the history window - # of control message. Control messages are 16 bytes long, - # so that we keep a history of 262144/16 = 16384 control - # messages. + # Size of the resend queue (in objects). This is the maximum + # number of objects that can be stored waiting to be confirmed + # via acknoledgment. If you keep this value low, the daemon + # will have less chances to recover state-changes under message + # omission. On the other hand, if you keep this value high, + # the daemon will consume more memory to store dead objects. + # Default is 131072 objects. # - ResendBufferSize 262144 + # ResendQueueSize 131072 # # Entries committed to the connection tracking table diff --git a/include/queue.h b/include/queue.h index ef56323..9213b3d 100644 --- a/include/queue.h +++ b/include/queue.h @@ -44,6 +44,7 @@ void queue_destroy(struct queue *b); unsigned int queue_len(const struct queue *b); int queue_add(struct queue *b, struct queue_node *n); int queue_del(struct queue_node *n); +struct queue_node *queue_del_head(struct queue *b); int queue_in(struct queue *b, struct queue_node *n); void queue_iterate(struct queue *b, const void *data, diff --git a/src/queue.c b/src/queue.c index cffcc93..7b36dc6 100644 --- a/src/queue.c +++ b/src/queue.c @@ -113,6 +113,13 @@ int queue_del(struct queue_node *n) return 1; } +struct queue_node *queue_del_head(struct queue *b) +{ + struct queue_node *n = (struct queue_node *) b->head.next; + queue_del(n); + return n; +} + int queue_in(struct queue *b, struct queue_node *n) { return b == n->owner; diff --git a/src/read_config_lex.l b/src/read_config_lex.l index 4953974..9bc4c18 100644 --- a/src/read_config_lex.l +++ b/src/read_config_lex.l @@ -88,6 +88,7 @@ notrack [N|n][O|o][T|t][R|r][A|a][C|c][K|k] "ListenTo" { return T_LISTEN_TO; } "Family" { return T_FAMILY; } "ResendBufferSize" { return T_RESEND_BUFFER_SIZE; } +"ResendQueueSize" { return T_RESEND_QUEUE_SIZE; } "Checksum" { return T_CHECKSUM; } "ACKWindowSize" { return T_WINDOWSIZE; } "Replicate" { return T_REPLICATE; } diff --git a/src/read_config_yy.y b/src/read_config_yy.y index ce604d9..97aa178 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -54,7 +54,7 @@ static void __max_mcast_dedicated_links_reached(void); %token T_GENERAL T_SYNC T_STATS T_RELAX_TRANSITIONS T_BUFFER_SIZE T_DELAY %token T_SYNC_MODE T_LISTEN_TO T_FAMILY T_RESEND_BUFFER_SIZE %token T_ALARM T_FTFW T_CHECKSUM T_WINDOWSIZE T_ON T_OFF -%token T_REPLICATE T_FOR T_IFACE T_PURGE +%token T_REPLICATE T_FOR T_IFACE T_PURGE T_RESEND_QUEUE_SIZE %token T_ESTABLISHED T_SYN_SENT T_SYN_RECV T_FIN_WAIT %token T_CLOSE_WAIT T_LAST_ACK T_TIME_WAIT T_CLOSE T_LISTEN %token T_SYSLOG T_WRITE_THROUGH T_STAT_BUFFER_SIZE T_DESTROY_TIMEOUT @@ -525,6 +525,7 @@ sync_mode_ftfw_list: | sync_mode_ftfw_list sync_mode_ftfw_line; sync_mode_ftfw_line: resend_queue_size + | resend_buffer_size | timeout | purge | window_size @@ -537,7 +538,13 @@ sync_mode_notrack_line: timeout | purge ; -resend_queue_size: T_RESEND_BUFFER_SIZE T_NUMBER +resend_buffer_size: T_RESEND_BUFFER_SIZE T_NUMBER +{ + fprintf(stderr, "WARNING: `ResendBufferSize' is deprecated. " + "Use `ResendQueueSize' instead\n"); +}; + +resend_queue_size: T_RESEND_QUEUE_SIZE T_NUMBER { conf.resend_queue_size = $2; }; @@ -1146,7 +1153,7 @@ init_config(char *filename) CONFIG(refresh) = 60; if (CONFIG(resend_queue_size) == 0) - CONFIG(resend_queue_size) = 262144; + CONFIG(resend_queue_size) = 131072; /* default to a window size of 300 packets */ if (CONFIG(window_size) == 0) diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 0d49756..493c15f 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -27,6 +27,7 @@ #include "fds.h" #include +#include #if 0 #define dp printf @@ -143,7 +144,7 @@ static void do_alive_alarm(struct alarm_block *a, void *data) static int ftfw_init(void) { - rs_queue = queue_create(INT_MAX, 0); + rs_queue = queue_create(CONFIG(resend_queue_size), 0); if (rs_queue == NULL) { dlog(LOG_ERR, "cannot create rs queue"); return -1; @@ -451,6 +452,29 @@ out: return ret; } +static void rs_queue_purge_full(void) +{ + struct queue_node *n; + + n = queue_del_head(rs_queue); + switch(n->type) { + case Q_ELEM_CTL: { + struct queue_object *qobj = (struct queue_object *)n; + queue_object_free(qobj); + break; + } + case Q_ELEM_OBJ: { + struct cache_ftfw *cn; + struct cache_object *obj; + + cn = (struct cache_ftfw *)n; + obj = cache_data_get_object(STATE_SYNC(internal), cn); + cache_object_put(obj); + break; + } + } +} + static int tx_queue_xmit(struct queue_node *n, const void *data) { queue_del(n); @@ -474,9 +498,14 @@ static int tx_queue_xmit(struct queue_node *n, const void *data) mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); HDR_NETWORK2HOST(net); - if (IS_ACK(net) || IS_NACK(net) || IS_RESYNC(net)) - queue_add(rs_queue, n); - else + if (IS_ACK(net) || IS_NACK(net) || IS_RESYNC(net)) { + if (queue_add(rs_queue, n) < 0) { + if (errno == ENOSPC) { + rs_queue_purge_full(); + queue_add(rs_queue, n); + } + } + } else queue_object_free((struct queue_object *)n); break; } @@ -497,7 +526,12 @@ static int tx_queue_xmit(struct queue_node *n, const void *data) mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); cn->seq = ntohl(net->seq); - queue_add(rs_queue, &cn->qnode); + if (queue_add(rs_queue, &cn->qnode) < 0) { + if (errno == ENOSPC) { + rs_queue_purge_full(); + queue_add(rs_queue, &cn->qnode); + } + } /* we release the object once we get the acknowlegment */ break; } -- cgit v1.2.3 From d05f05e21be0cca59ca67ac19ef2b73c467b8250 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 17 Jan 2009 20:33:30 +0100 Subject: src: add `-s queue' and change `-v' behaviour This patch moves the existing `-v' behaviour to `-s queue' where it really belongs. The `-v' option is now left to display the version which is the common use of it. # conntrackd -v Connection tracking userspace daemon v0.9.9. Licensed under GPLv2. (C) 2006-2009 Pablo Neira Ayuso Signed-off-by: Pablo Neira Ayuso --- include/conntrackd.h | 3 ++- src/main.c | 22 +++++++++++++++++----- src/sync-ftfw.c | 8 ++++---- 3 files changed, 23 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/include/conntrackd.h b/include/conntrackd.h index acf907c..eca6b76 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -25,11 +25,12 @@ #define DUMP_INT_XML 24 /* dump internal cache in XML */ #define DUMP_EXT_XML 25 /* dump external cache in XML */ #define RESET_TIMERS 26 /* reset kernel timers */ -#define DEBUG_INFO 27 /* show debug info (if any) */ +#define DEBUG_INFO 27 /* unused */ #define STATS_NETWORK 28 /* extended network stats */ #define STATS_CACHE 29 /* extended cache stats */ #define STATS_RUNTIME 30 /* extended runtime stats */ #define STATS_MULTICAST 31 /* multicast network stats */ +#define STATS_QUEUE 32 /* queue stats */ #define DEFAULT_CONFIGFILE "/etc/conntrackd/conntrackd.conf" #define DEFAULT_LOCKFILE "/var/lock/conntrackd.lock" diff --git a/src/main.c b/src/main.c index 061a73e..c3271fe 100644 --- a/src/main.c +++ b/src/main.c @@ -43,12 +43,12 @@ static const char usage_client_commands[] = " -i, display content of the internal cache\n" " -e, display the content of the external cache\n" " -k, kill conntrack daemon\n" - " -s [|network|cache|runtime|multicast], dump statistics\n" + " -s [|network|cache|runtime|multicast|queue], dump statistics\n" " -R, resync with kernel conntrack table\n" " -n, request resync with other node (only FT-FW and NOTRACK modes)\n" " -x, dump cache in XML format (requires -i or -e)\n" " -t, reset the kernel timeout (see PurgeTimeout clause)\n" - " -v, show internal debugging information (if any)\n"; + " -v, display conntrackd version\n"; static const char usage_options[] = "Options:\n" @@ -64,6 +64,15 @@ show_usage(char *progname) fprintf(stdout, "%s\n", usage_options); } +static void +show_version(void) +{ + fprintf(stdout, "Connection tracking userspace daemon v%s. ", VERSION); + fprintf(stdout, "Licensed under GPLv2.\n"); + fprintf(stdout, "(C) 2006-2009 Pablo Neira Ayuso "); + fprintf(stdout, "\n"); +} + static void set_operation_mode(int *current, int want, char *argv[]) { @@ -173,6 +182,10 @@ int main(int argc, char *argv[]) strlen(argv[i+1])) == 0) { action = STATS_MULTICAST; i++; + } else if (strncmp(argv[i+1], "queue", + strlen(argv[i+1])) == 0) { + action = STATS_QUEUE; + i++; } else { fprintf(stderr, "ERROR: unknown " "parameter `%s' for " @@ -206,9 +219,8 @@ int main(int argc, char *argv[]) } break; case 'v': - set_operation_mode(&type, REQUEST, argv); - action = DEBUG_INFO; - break; + show_version(); + exit(EXIT_SUCCESS); default: show_usage(argv[0]); fprintf(stderr, "Unknown option: %s\n", argv[i]); diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 493c15f..fd6c350 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -204,12 +204,12 @@ static int rs_queue_dump(struct queue_node *n, const void *data2) return 0; } -static void debug_rs_dump(int fd) +static void ftfw_local_queue(int fd) { char buf[512]; int size; - size = sprintf(buf, "resent queue (len=%u):\n", queue_len(rs_queue)); + size = sprintf(buf, "resent queue (len=%u)\n", queue_len(rs_queue)); send(fd, buf, size, 0); queue_iterate(rs_queue, &fd, rs_queue_dump); } @@ -227,8 +227,8 @@ static int ftfw_local(int fd, int type, void *data) dlog(LOG_NOTICE, "sending bulk update"); cache_iterate(STATE_SYNC(internal), NULL, do_cache_to_tx); break; - case DEBUG_INFO: - debug_rs_dump(fd); + case STATS_QUEUE: + ftfw_local_queue(fd); break; default: ret = 0; -- cgit v1.2.3 From 4fb9c22f6e4ec2fadd22c0863137f211d9b392c4 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 17 Jan 2009 20:34:13 +0100 Subject: conntrack: add -C command to display the counter This patch adds the -C command, to display the table counter. In the case of `-C conntrack' the tool reads the proc interface. For expectation, it loops on the table to count the number of entries (as there is not proc interface to display the number of expectations). Signed-off-by: Pablo Neira Ayuso --- conntrack.8 | 3 +++ include/conntrack.h | 8 +++++++- src/conntrack.c | 50 +++++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 55 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/conntrack.8 b/conntrack.8 index 146e2df..94f4e41 100644 --- a/conntrack.8 +++ b/conntrack.8 @@ -72,6 +72,9 @@ Display a real-time event log. .TP .BI "-F, --flush " Flush the whole given table +.TP +.BI "-C, --count " +Show the table counter. .SS PARAMETERS .TP .BI "-z, --zero " diff --git a/include/conntrack.h b/include/conntrack.h index 4787809..87a262d 100644 --- a/include/conntrack.h +++ b/include/conntrack.h @@ -59,8 +59,14 @@ enum action { EXP_EVENT_BIT = 14, EXP_EVENT = (1 << EXP_EVENT_BIT), + + CT_COUNT_BIT = 15, + CT_COUNT = (1 << CT_COUNT_BIT), + + EXP_COUNT_BIT = 16, + EXP_COUNT = (1 << EXP_COUNT_BIT), }; -#define NUMBER_OF_CMD 15 +#define NUMBER_OF_CMD 17 enum options { CT_OPT_ORIG_SRC_BIT = 0, diff --git a/src/conntrack.c b/src/conntrack.c index e8b2c4f..6064fb7 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -54,13 +54,15 @@ #include #include #include +#include +#include #include static const char cmdflags[NUMBER_OF_CMD] -= {'L','I','U','D','G','F','E','V','h','L','I','D','G','F','E'}; += {'L','I','U','D','G','F','E','V','h','L','I','D','G','F','E','C','C'}; static const char cmd_need_param[NUMBER_OF_CMD] -= { 2, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, 0, 2, 2 }; += { 2, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, 0, 2, 2, 2, 2}; static const char *optflags[NUMBER_OF_OPT] = { "src","dst","reply-src","reply-dst","protonum","timeout","status","zero", @@ -138,6 +140,7 @@ static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = /*EXP_GET*/ {1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, /*EXP_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, /*EXP_EVENT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*CT_COUNT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, }; static LIST_HEAD(proto_list); @@ -858,6 +861,14 @@ static int dump_exp_cb(enum nf_conntrack_msg_type type, return NFCT_CB_CONTINUE; } +static int count_exp_cb(enum nf_conntrack_msg_type type, + struct nf_expect *exp, + void *data) +{ + counter++; + return NFCT_CB_CONTINUE; +} + static struct ctproto_handler *h; static const int cmd2type[][2] = { @@ -869,6 +880,7 @@ static const int cmd2type[][2] = { ['E'] = { CT_EVENT, EXP_EVENT }, ['V'] = { CT_VERSION, CT_VERSION }, ['h'] = { CT_HELP, CT_HELP }, + ['C'] = { CT_COUNT, EXP_COUNT }, }; static const int opt2type[] = { @@ -908,7 +920,7 @@ static const int opt2attr[] = { ['i'] = ATTR_ID, }; -static char exit_msg[][64] = { +static char exit_msg[NUMBER_OF_CMD][64] = { [CT_LIST_BIT] = "%d flow entries has been shown.\n", [CT_CREATE_BIT] = "%d flow entries has been created.\n", [CT_UPDATE_BIT] = "%d flow entries has been updated.\n", @@ -955,7 +967,7 @@ int main(int argc, char *argv[]) while ((c = getopt_long(argc, argv, "L::I::U::D::G::E::F::hVs:d:r:q:" "p:t:u:e:a:z[:]:{:}:m:i:f:o:n::" - "g::c:b:", + "g::c:b:C::", opts, NULL)) != -1) { switch(c) { /* commands */ @@ -967,6 +979,7 @@ int main(int argc, char *argv[]) case 'E': case 'V': case 'h': + case 'C': type = check_type(argc, argv); add_command(&command, cmd2type[c][type]); break; @@ -1322,7 +1335,34 @@ int main(int argc, char *argv[]) res = nfexp_catch(cth); nfct_close(cth); break; - + case CT_COUNT: { +#define NF_CONNTRACK_COUNT_PROC "/proc/sys/net/netfilter/nf_conntrack_count" + int fd, count; + char buf[strlen("2147483647")]; /* INT_MAX */ + fd = open(NF_CONNTRACK_COUNT_PROC, O_RDONLY); + if (fd == -1) { + exit_error(OTHER_PROBLEM, "Can't open %s", + NF_CONNTRACK_COUNT_PROC); + } + if (read(fd, buf, sizeof(buf)) == -1) { + exit_error(OTHER_PROBLEM, "Can't read %s", + NF_CONNTRACK_COUNT_PROC); + } + close(fd); + count = atoi(buf); + printf("%d\n", count); + break; + } + case EXP_COUNT: + cth = nfct_open(EXPECT, 0); + if (!cth) + exit_error(OTHER_PROBLEM, "Can't open handler"); + + nfexp_callback_register(cth, NFCT_T_ALL, count_exp_cb, NULL); + res = nfexp_query(cth, NFCT_Q_DUMP, &family); + nfct_close(cth); + printf("%d\n", counter); + break; case CT_VERSION: printf("%s v%s (conntrack-tools)\n", PROGNAME, VERSION); break; -- cgit v1.2.3 From 0cad5cba3e1f7b4295d0f98a1d9df3acdbb6f203 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 21 Jan 2009 13:51:21 +0100 Subject: src: obsolete `DestroyTimeout' clause This patch obsoletes `DestroyTimeout' which has no clients anymore. Signed-off-by: Pablo Neira Ayuso --- include/conntrackd.h | 1 - src/read_config_yy.y | 7 ++----- 2 files changed, 2 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/include/conntrackd.h b/include/conntrackd.h index eca6b76..99b9caa 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -78,7 +78,6 @@ struct ct_conf { int cache_timeout; /* cache entries timeout */ int commit_timeout; /* committed entries timeout */ unsigned int purge_timeout; /* purge kernel entries timeout */ - int del_timeout; unsigned int netlink_buffer_size; unsigned int netlink_buffer_size_max_grown; union inet_address *listen_to; diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 97aa178..d71829f 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -556,7 +556,8 @@ window_size: T_WINDOWSIZE T_NUMBER destroy_timeout: T_DESTROY_TIMEOUT T_NUMBER { - conf.del_timeout = $2; + fprintf(stderr, "WARNING: `DestroyTimeout' is deprecated. " + "Remove it.\n"); }; relax_transitions: T_RELAX_TRANSITIONS @@ -1159,10 +1160,6 @@ init_config(char *filename) if (CONFIG(window_size) == 0) CONFIG(window_size) = 300; - /* double of 120 seconds which is common timeout of a final state */ - if (conf.flags & CTD_SYNC_FTFW && CONFIG(del_timeout) == 0) - CONFIG(del_timeout) = 240; - if (CONFIG(event_iterations_limit) == 0) CONFIG(event_iterations_limit) = 100; -- cgit v1.2.3 From ccb54b5f240d3bb014938057c39b24699ff07bfa Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 21 Jan 2009 14:59:48 +0100 Subject: conntrack: fix use of -u which is optional with -I The option --status can be used with -I. Currently, this behaviour is broken. conntrack v0.9.9 (conntrack-tools): Illegal option `--status' with this command Try `conntrack -h' or 'conntrack --help' for more information. Signed-off-by: Pablo Neira Ayuso --- src/conntrack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index 6064fb7..c746ae8 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -126,7 +126,7 @@ static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = { /* s d r q p t u z e [ ] { } a m i f n g o c b*/ /*CT_LIST*/ {2,2,2,2,2,0,2,2,0,0,0,0,0,0,2,0,2,2,2,2,2,0}, -/*CT_CREATE*/ {2,2,2,2,1,1,0,0,0,0,0,0,0,2,2,0,0,2,2,0,0,0}, +/*CT_CREATE*/ {2,2,2,2,1,1,2,0,0,0,0,0,0,2,2,0,0,2,2,0,0,0}, /*CT_UPDATE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0}, /*CT_DELETE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0}, /*CT_GET*/ {2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,2,0,0,0,2,0,0}, -- cgit v1.2.3 From 61d976838ee0c3eeda295818ff44f44327b0596d Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 25 Jan 2009 13:44:22 +0100 Subject: cache_iterators: start a clean session if commit finds an entry The current commit code updates an entry it still exists in the kernel. With this patch, we delete the entry and create a new one to make sure that we start a clean session. Signed-off-by: Pablo Neira Ayuso --- include/cache.h | 1 - src/cache_iterators.c | 60 +++++++++++---------------------------------------- 2 files changed, 12 insertions(+), 49 deletions(-) (limited to 'src') diff --git a/include/cache.h b/include/cache.h index 697a64b..bb0ca4d 100644 --- a/include/cache.h +++ b/include/cache.h @@ -83,7 +83,6 @@ struct cache { uint32_t upd_fail_enoent; uint32_t commit_ok; - uint32_t commit_exist; uint32_t commit_fail; uint32_t flush; diff --git a/src/cache_iterators.c b/src/cache_iterators.c index ab6a461..379deed 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -111,57 +111,26 @@ __do_commit_step(struct __commit_container *tmp, struct cache_object *obj) */ nfct_set_attr_u32(ct, ATTR_TIMEOUT, CONFIG(commit_timeout)); -try_again: - ret = nl_exist_conntrack(tmp->h, ct); - switch (ret) { - case -1: - dlog(LOG_ERR, "commit-exist: %s", strerror(errno)); - dlog_ct(STATE(log), ct, NFCT_O_PLAIN); - break; - case 0: - if (nl_create_conntrack(tmp->h, ct) == -1) { - if (errno == ENOMEM) { +retry: + if (nl_create_conntrack(tmp->h, ct) == -1) { + if (errno == EEXIST && retry == 1) { + ret = nl_destroy_conntrack(tmp->h, ct); + if (ret == 0 || (ret == -1 && errno == ENOENT)) { if (retry) { retry = 0; - sched_yield(); - goto try_again; + goto retry; } } - dlog(LOG_ERR, "commit-create: %s", strerror(errno)); + dlog(LOG_ERR, "commit-destroy: %s", strerror(errno)); dlog_ct(STATE(log), ct, NFCT_O_PLAIN); tmp->c->stats.commit_fail++; - } else - tmp->c->stats.commit_ok++; - break; - case 1: - tmp->c->stats.commit_exist++; - if (nl_update_conntrack(tmp->h, ct) == -1) { - if (errno == ENOMEM || errno == ETIME) { - if (retry) { - retry = 0; - sched_yield(); - goto try_again; - } - } - /* try harder, delete the entry and retry */ - if (retry) { - ret = nl_destroy_conntrack(tmp->h, ct); - if (ret == 0 || - (ret == -1 && errno == ENOENT)) { - retry = 0; - goto try_again; - } - dlog(LOG_ERR, "commit-rm: %s", strerror(errno)); - dlog_ct(STATE(log), ct, NFCT_O_PLAIN); - tmp->c->stats.commit_fail++; - break; - } - dlog(LOG_ERR, "commit-update: %s", strerror(errno)); + } else { + dlog(LOG_ERR, "commit-create: %s", strerror(errno)); dlog_ct(STATE(log), ct, NFCT_O_PLAIN); tmp->c->stats.commit_fail++; - } else - tmp->c->stats.commit_ok++; - break; + } + } else { + tmp->c->stats.commit_ok++; } } @@ -191,7 +160,6 @@ static int do_commit_master(void *data, struct hashtable_node *n) void cache_commit(struct cache *c) { unsigned int commit_ok = c->stats.commit_ok; - unsigned int commit_exist = c->stats.commit_exist; unsigned int commit_fail = c->stats.commit_fail; struct __commit_container tmp; struct timeval commit_start, commit_stop, res; @@ -213,14 +181,10 @@ void cache_commit(struct cache *c) /* calculate new entries committed */ commit_ok = c->stats.commit_ok - commit_ok; commit_fail = c->stats.commit_fail - commit_fail; - commit_exist = c->stats.commit_exist - commit_exist; /* log results */ dlog(LOG_NOTICE, "Committed %u new entries", commit_ok); - if (commit_exist) - dlog(LOG_NOTICE, "%u entries updated, " - "already exist", commit_exist); if (commit_fail) dlog(LOG_NOTICE, "%u entries can't be " "committed", commit_fail); -- cgit v1.2.3 From e6732c96ffd9baaaa84dab763ff6e600bf6abc95 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 25 Jan 2009 17:51:09 +0100 Subject: cache: remove nl_exist_conntrack() function This function is a synonimous of nl_get_conntrack(), use the get function instead. Signed-off-by: Pablo Neira Ayuso --- include/netlink.h | 1 - src/cache_wt.c | 2 +- src/netlink.c | 15 ++------------- 3 files changed, 3 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/include/netlink.h b/include/netlink.h index a8eb919..d8a4fef 100644 --- a/include/netlink.h +++ b/include/netlink.h @@ -16,7 +16,6 @@ int nl_send_resync(struct nfct_handle *h); void nl_resize_socket_buffer(struct nfct_handle *h); int nl_dump_conntrack_table(struct nfct_handle *h); int nl_flush_conntrack_table(struct nfct_handle *h); -int nl_exist_conntrack(struct nfct_handle *h, const struct nf_conntrack *ct); int nl_get_conntrack(struct nfct_handle *h, const struct nf_conntrack *ct); int nl_create_conntrack(struct nfct_handle *h, const struct nf_conntrack *ct); int nl_update_conntrack(struct nfct_handle *h, const struct nf_conntrack *ct); diff --git a/src/cache_wt.c b/src/cache_wt.c index 84a816f..4b67e8e 100644 --- a/src/cache_wt.c +++ b/src/cache_wt.c @@ -30,7 +30,7 @@ static void add_wt(struct cache_object *obj) char __ct[nfct_maxsize()]; struct nf_conntrack *ct = (struct nf_conntrack *)(void*) __ct; - ret = nl_exist_conntrack(STATE(request), obj->ct); + ret = nl_get_conntrack(STATE(request), obj->ct); switch (ret) { case -1: dlog(LOG_ERR, "cache_wt problem: %s", strerror(errno)); diff --git a/src/netlink.c b/src/netlink.c index 15a30f6..e538aa0 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -178,8 +178,8 @@ int nl_send_resync(struct nfct_handle *h) return nfct_send(h, NFCT_Q_DUMP, &family); } -static int -__nl_get_conntrack(struct nfct_handle *h, const struct nf_conntrack *ct) +/* if the handle has no callback, check for existence, otherwise, update */ +int nl_get_conntrack(struct nfct_handle *h, const struct nf_conntrack *ct) { int ret; char __tmp[nfct_maxsize()]; @@ -197,17 +197,6 @@ __nl_get_conntrack(struct nfct_handle *h, const struct nf_conntrack *ct) return 1; } -int nl_exist_conntrack(struct nfct_handle *h, const struct nf_conntrack *ct) -{ - return __nl_get_conntrack(h, ct); -} - -/* get the conntrack and update the cache */ -int nl_get_conntrack(struct nfct_handle *h, const struct nf_conntrack *ct) -{ - return __nl_get_conntrack(h, ct); -} - int nl_create_conntrack(struct nfct_handle *h, const struct nf_conntrack *orig) { int ret; -- cgit v1.2.3 From 8d689ebb67c511f5c03acdfc2226156d5f87c319 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 25 Jan 2009 17:51:18 +0100 Subject: cache: mangle timeout inside nl_*_conntrack() functions This patch moves the timeout mangling inside nl_*_conntrack(). Signed-off-by: Pablo Neira Ayuso --- include/netlink.h | 4 ++-- src/cache_iterators.c | 12 ++---------- src/cache_wt.c | 6 +++--- src/netlink.c | 14 ++++++++++++-- 4 files changed, 19 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/include/netlink.h b/include/netlink.h index d8a4fef..9d67165 100644 --- a/include/netlink.h +++ b/include/netlink.h @@ -17,8 +17,8 @@ void nl_resize_socket_buffer(struct nfct_handle *h); int nl_dump_conntrack_table(struct nfct_handle *h); int nl_flush_conntrack_table(struct nfct_handle *h); int nl_get_conntrack(struct nfct_handle *h, const struct nf_conntrack *ct); -int nl_create_conntrack(struct nfct_handle *h, const struct nf_conntrack *ct); -int nl_update_conntrack(struct nfct_handle *h, const struct nf_conntrack *ct); +int nl_create_conntrack(struct nfct_handle *h, const struct nf_conntrack *ct, int timeout); +int nl_update_conntrack(struct nfct_handle *h, const struct nf_conntrack *ct, int timeout); int nl_destroy_conntrack(struct nfct_handle *h, const struct nf_conntrack *ct); static inline int ct_is_related(const struct nf_conntrack *ct) diff --git a/src/cache_iterators.c b/src/cache_iterators.c index 379deed..9b54ea1 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -105,14 +105,8 @@ __do_commit_step(struct __commit_container *tmp, struct cache_object *obj) int ret, retry = 1; struct nf_conntrack *ct = obj->ct; - /* - * Set a reduced timeout for candidate-to-be-committed - * conntracks that live in the external cache - */ - nfct_set_attr_u32(ct, ATTR_TIMEOUT, CONFIG(commit_timeout)); - retry: - if (nl_create_conntrack(tmp->h, ct) == -1) { + if (nl_create_conntrack(tmp->h, ct, CONFIG(commit_timeout)) == -1) { if (errno == EEXIST && retry == 1) { ret = nl_destroy_conntrack(tmp->h, ct); if (ret == 0 || (ret == -1 && errno == ENOENT)) { @@ -223,9 +217,7 @@ static int do_reset_timers(void *data1, struct hashtable_node *n) if (current_timeout < CONFIG(purge_timeout)) break; - nfct_set_attr_u32(tmp, ATTR_TIMEOUT, CONFIG(purge_timeout)); - - if (nl_update_conntrack(h, tmp) == -1) { + if (nl_update_conntrack(h, tmp, CONFIG(purge_timeout)) == -1) { if (errno == ETIME || errno == ENOENT) break; dlog(LOG_ERR, "reset-timers-upd: %s", strerror(errno)); diff --git a/src/cache_wt.c b/src/cache_wt.c index 4b67e8e..6f9ccc7 100644 --- a/src/cache_wt.c +++ b/src/cache_wt.c @@ -38,14 +38,14 @@ static void add_wt(struct cache_object *obj) break; case 0: memcpy(ct, obj->ct, nfct_maxsize()); - if (nl_create_conntrack(STATE(dump), ct) == -1) { + if (nl_create_conntrack(STATE(dump), ct, 0) == -1) { dlog(LOG_ERR, "cache_wt create: %s", strerror(errno)); dlog_ct(STATE(log), obj->ct, NFCT_O_PLAIN); } break; case 1: memcpy(ct, obj->ct, nfct_maxsize()); - if (nl_update_conntrack(STATE(dump), ct) == -1) { + if (nl_update_conntrack(STATE(dump), ct, 0) == -1) { dlog(LOG_ERR, "cache_wt crt-upd: %s", strerror(errno)); dlog_ct(STATE(log), obj->ct, NFCT_O_PLAIN); } @@ -60,7 +60,7 @@ static void upd_wt(struct cache_object *obj) memcpy(ct, obj->ct, nfct_maxsize()); - if (nl_update_conntrack(STATE(dump), ct) == -1) { + if (nl_update_conntrack(STATE(dump), ct, 0) == -1) { dlog(LOG_ERR, "cache_wt update:%s", strerror(errno)); dlog_ct(STATE(log), obj->ct, NFCT_O_PLAIN); } diff --git a/src/netlink.c b/src/netlink.c index e538aa0..24d61a0 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -197,7 +197,9 @@ int nl_get_conntrack(struct nfct_handle *h, const struct nf_conntrack *ct) return 1; } -int nl_create_conntrack(struct nfct_handle *h, const struct nf_conntrack *orig) +int nl_create_conntrack(struct nfct_handle *h, + const struct nf_conntrack *orig, + int timeout) { int ret; struct nf_conntrack *ct; @@ -206,6 +208,9 @@ int nl_create_conntrack(struct nfct_handle *h, const struct nf_conntrack *orig) if (ct == NULL) return -1; + if (timeout > 0) + nfct_set_attr_u32(ct, ATTR_TIMEOUT, timeout); + /* we hit error if we try to change the expected bit */ if (nfct_attr_is_set(ct, ATTR_STATUS)) { uint32_t status = nfct_get_attr_u32(ct, ATTR_STATUS); @@ -233,7 +238,9 @@ int nl_create_conntrack(struct nfct_handle *h, const struct nf_conntrack *orig) return ret; } -int nl_update_conntrack(struct nfct_handle *h, const struct nf_conntrack *orig) +int nl_update_conntrack(struct nfct_handle *h, + const struct nf_conntrack *orig, + int timeout) { int ret; struct nf_conntrack *ct; @@ -242,6 +249,9 @@ int nl_update_conntrack(struct nfct_handle *h, const struct nf_conntrack *orig) if (ct == NULL) return -1; + if (timeout > 0) + nfct_set_attr_u32(ct, ATTR_TIMEOUT, timeout); + /* unset NAT info, otherwise we hit error */ nfct_attr_unset(ct, ATTR_SNAT_IPV4); nfct_attr_unset(ct, ATTR_DNAT_IPV4); -- cgit v1.2.3 From b9ee88a0fdb20ed847f05efce1b0abdc8afbabaf Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 25 Jan 2009 17:51:23 +0100 Subject: src: don't clone when calling nl_*_conntrack functions This patch removes the clone conntrack objects created before calling nl_*_conntrack functions since they are not required anymore (the previous patch guarantees that objects passed as parameter are not modified). Signed-off-by: Pablo Neira Ayuso --- src/cache_iterators.c | 19 ++++++------------- src/cache_wt.c | 15 +++------------ 2 files changed, 9 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/cache_iterators.c b/src/cache_iterators.c index 9b54ea1..be69d47 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -194,34 +194,27 @@ static int do_reset_timers(void *data1, struct hashtable_node *n) u_int32_t current_timeout; struct nfct_handle *h = data1; struct cache_object *obj = (struct cache_object *)n; - struct nf_conntrack *ct = obj->ct; - char __tmp[nfct_maxsize()]; - struct nf_conntrack *tmp = (struct nf_conntrack *) (void *)__tmp; - - memset(__tmp, 0, sizeof(__tmp)); - /* use the original tuple to check if it is there */ - nfct_copy(tmp, ct, NFCT_CP_ORIG); - - ret = nl_get_conntrack(h, tmp); + ret = nl_get_conntrack(h, obj->ct); switch (ret) { case -1: /* the kernel table is not in sync with internal cache */ dlog(LOG_ERR, "reset-timers: %s", strerror(errno)); - dlog_ct(STATE(log), ct, NFCT_O_PLAIN); + dlog_ct(STATE(log), obj->ct, NFCT_O_PLAIN); break; case 1: /* use the object that contain the current timer */ - current_timeout = nfct_get_attr_u32(ct, ATTR_TIMEOUT); + current_timeout = nfct_get_attr_u32(obj->ct, ATTR_TIMEOUT); /* already about to die, do not touch it */ if (current_timeout < CONFIG(purge_timeout)) break; - if (nl_update_conntrack(h, tmp, CONFIG(purge_timeout)) == -1) { + ret = nl_update_conntrack(h, obj->ct, CONFIG(purge_timeout)); + if (ret == -1) { if (errno == ETIME || errno == ENOENT) break; dlog(LOG_ERR, "reset-timers-upd: %s", strerror(errno)); - dlog_ct(STATE(log), ct, NFCT_O_PLAIN); + dlog_ct(STATE(log), obj->ct, NFCT_O_PLAIN); } break; } diff --git a/src/cache_wt.c b/src/cache_wt.c index 6f9ccc7..34fe82e 100644 --- a/src/cache_wt.c +++ b/src/cache_wt.c @@ -27,8 +27,6 @@ static void add_wt(struct cache_object *obj) { int ret; - char __ct[nfct_maxsize()]; - struct nf_conntrack *ct = (struct nf_conntrack *)(void*) __ct; ret = nl_get_conntrack(STATE(request), obj->ct); switch (ret) { @@ -37,15 +35,13 @@ static void add_wt(struct cache_object *obj) dlog_ct(STATE(log), obj->ct, NFCT_O_PLAIN); break; case 0: - memcpy(ct, obj->ct, nfct_maxsize()); - if (nl_create_conntrack(STATE(dump), ct, 0) == -1) { + if (nl_create_conntrack(STATE(dump), obj->ct, 0) == -1) { dlog(LOG_ERR, "cache_wt create: %s", strerror(errno)); dlog_ct(STATE(log), obj->ct, NFCT_O_PLAIN); } break; case 1: - memcpy(ct, obj->ct, nfct_maxsize()); - if (nl_update_conntrack(STATE(dump), ct, 0) == -1) { + if (nl_update_conntrack(STATE(dump), obj->ct, 0) == -1) { dlog(LOG_ERR, "cache_wt crt-upd: %s", strerror(errno)); dlog_ct(STATE(log), obj->ct, NFCT_O_PLAIN); } @@ -55,12 +51,7 @@ static void add_wt(struct cache_object *obj) static void upd_wt(struct cache_object *obj) { - char __ct[nfct_maxsize()]; - struct nf_conntrack *ct = (struct nf_conntrack *)(void*) __ct; - - memcpy(ct, obj->ct, nfct_maxsize()); - - if (nl_update_conntrack(STATE(dump), ct, 0) == -1) { + if (nl_update_conntrack(STATE(dump), obj->ct, 0) == -1) { dlog(LOG_ERR, "cache_wt update:%s", strerror(errno)); dlog_ct(STATE(log), obj->ct, NFCT_O_PLAIN); } -- cgit v1.2.3 From eec8fdf57f34fe0d80b884ad0e376ed24c63ffcc Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 25 Jan 2009 17:52:56 +0100 Subject: src: change behaviour of `-t' option With this patch, the `-t' option adds an alarm that will flush the cache after CONFIG(purge_timeout) seconds specified in the config file. This looks much cleaner and more performance that looping on the entire conntrack table to set the new timeout of every single entry. Signed-off-by: Pablo Neira Ayuso --- include/cache.h | 1 - include/conntrackd.h | 2 ++ src/cache_iterators.c | 46 ---------------------------------------------- src/sync-mode.c | 23 ++++++++++++++++++----- 4 files changed, 20 insertions(+), 52 deletions(-) (limited to 'src') diff --git a/include/cache.h b/include/cache.h index bb0ca4d..5e96dd3 100644 --- a/include/cache.h +++ b/include/cache.h @@ -126,6 +126,5 @@ void cache_dump(struct cache *c, int fd, int type); void cache_commit(struct cache *c); void cache_flush(struct cache *c); void cache_bulk(struct cache *c); -void cache_reset_timers(struct cache *c); #endif diff --git a/include/conntrackd.h b/include/conntrackd.h index 99b9caa..3e10a2f 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -158,6 +158,8 @@ struct ct_sync_state { struct nlif_handle *mcast_iface; struct queue *tx_queue; + struct alarm_block reset_cache_alarm; + struct sync_mode *sync; /* sync mode */ /* statistics */ diff --git a/src/cache_iterators.c b/src/cache_iterators.c index be69d47..4bf518a 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -188,52 +188,6 @@ void cache_commit(struct cache *c) res.tv_sec, res.tv_usec); } -static int do_reset_timers(void *data1, struct hashtable_node *n) -{ - int ret; - u_int32_t current_timeout; - struct nfct_handle *h = data1; - struct cache_object *obj = (struct cache_object *)n; - - ret = nl_get_conntrack(h, obj->ct); - switch (ret) { - case -1: - /* the kernel table is not in sync with internal cache */ - dlog(LOG_ERR, "reset-timers: %s", strerror(errno)); - dlog_ct(STATE(log), obj->ct, NFCT_O_PLAIN); - break; - case 1: - /* use the object that contain the current timer */ - current_timeout = nfct_get_attr_u32(obj->ct, ATTR_TIMEOUT); - /* already about to die, do not touch it */ - if (current_timeout < CONFIG(purge_timeout)) - break; - - ret = nl_update_conntrack(h, obj->ct, CONFIG(purge_timeout)); - if (ret == -1) { - if (errno == ETIME || errno == ENOENT) - break; - dlog(LOG_ERR, "reset-timers-upd: %s", strerror(errno)); - dlog_ct(STATE(log), obj->ct, NFCT_O_PLAIN); - } - break; - } - return 0; -} - -void cache_reset_timers(struct cache *c) -{ - struct nfct_handle *h; - - h = nfct_open(CONNTRACK, 0); - if (h == NULL) { - dlog(LOG_ERR, "can't create handler to reset timers"); - return; - } - hashtable_iterate(c->h, h, do_reset_timers); - nfct_close(h); -} - static int do_flush(void *data, struct hashtable_node *n) { struct cache *c = data; diff --git a/src/sync-mode.c b/src/sync-mode.c index 54d0ebb..84a4de0 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -205,6 +205,13 @@ static void mcast_iface_handler(void) mcast_iface_candidate(); } +static void do_reset_cache_alarm(struct alarm_block *a, void *data) +{ + STATE(stats).nl_kernel_table_flush++; + dlog(LOG_NOTICE, "flushing kernel conntrack table (scheduled)"); + nl_flush_conntrack_table(STATE(request)); +} + static int init_sync(void) { int i; @@ -305,6 +312,8 @@ static int init_sync(void) STATE(fds)) == -1) return -1; + init_alarm(&STATE_SYNC(reset_cache_alarm), NULL, do_reset_cache_alarm); + /* initialization of multicast sequence generation */ STATE_SYNC(last_seq_sent) = time(NULL); @@ -432,6 +441,8 @@ static int local_handler_sync(int fd, int type, void *data) } break; case COMMIT: + /* delete the reset alarm if any before committing */ + del_alarm(&STATE_SYNC(reset_cache_alarm)); ret = fork(); if (ret == 0) { dlog(LOG_NOTICE, "committing external cache"); @@ -440,14 +451,16 @@ static int local_handler_sync(int fd, int type, void *data) } break; case RESET_TIMERS: - ret = fork(); - if (ret == 0) { - dlog(LOG_NOTICE, "resetting timers"); - cache_reset_timers(STATE_SYNC(internal)); - exit(EXIT_SUCCESS); + if (!alarm_pending(&STATE_SYNC(reset_cache_alarm))) { + dlog(LOG_NOTICE, "flushing conntrack table in %d secs", + CONFIG(purge_timeout)); + add_alarm(&STATE_SYNC(reset_cache_alarm), + CONFIG(purge_timeout), 0); } break; case FLUSH_CACHE: + /* inmediate flush, remove pending flush scheduled if any */ + del_alarm(&STATE_SYNC(reset_cache_alarm)); dlog(LOG_NOTICE, "flushing caches"); cache_flush(STATE_SYNC(internal)); cache_flush(STATE_SYNC(external)); -- cgit v1.2.3 From 1c9faf8c218bc7ff4617557383e4116f1adb11e5 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 25 Jan 2009 17:53:02 +0100 Subject: cache: move lifetime feature to main cache code The lifetime feature is used by all working modes, it is useful to know how long it has been an entry living in the cache. This patch moves the lifetime feature to the main caching code. Signed-off-by: Pablo Neira Ayuso --- include/cache.h | 6 ++--- src/Makefile.am | 2 +- src/cache.c | 3 ++- src/cache_iterators.c | 6 +++++ src/cache_lifetime.c | 65 --------------------------------------------------- src/stats-mode.c | 4 +--- src/sync-alarm.c | 4 ++-- src/sync-ftfw.c | 4 ++-- src/sync-notrack.c | 4 ++-- 9 files changed, 18 insertions(+), 80 deletions(-) delete mode 100644 src/cache_lifetime.c (limited to 'src') diff --git a/include/cache.h b/include/cache.h index 5e96dd3..1fd3881 100644 --- a/include/cache.h +++ b/include/cache.h @@ -12,10 +12,7 @@ enum { TIMER_FEATURE = 0, TIMER = (1 << TIMER_FEATURE), - LIFETIME_FEATURE = 2, - LIFETIME = (1 << LIFETIME_FEATURE), - - WRITE_THROUGH_FEATURE = 3, + WRITE_THROUGH_FEATURE = 1, WRITE_THROUGH = (1 << WRITE_THROUGH_FEATURE), __CACHE_MAX_FEATURE @@ -36,6 +33,7 @@ struct cache_object { struct cache *cache; int status; int refcnt; + long lifetime; char data[0]; }; diff --git a/src/Makefile.am b/src/Makefile.am index 64ed2b5..8ba09e1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -14,7 +14,7 @@ conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c rbtree.c \ local.c log.c mcast.c netlink.c vector.c \ filter.c fds.c event.c \ cache.c cache_iterators.c \ - cache_lifetime.c cache_timer.c cache_wt.c \ + cache_timer.c cache_wt.c \ sync-mode.c sync-alarm.c sync-ftfw.c sync-notrack.c \ traffic_stats.c stats-mode.c \ network.c cidr.c \ diff --git a/src/cache.c b/src/cache.c index a5f37dd..71825e1 100644 --- a/src/cache.c +++ b/src/cache.c @@ -26,6 +26,7 @@ #include #include #include +#include static uint32_t __hash4(const struct nf_conntrack *ct, const struct hashtable *table) @@ -94,7 +95,6 @@ static int compare(const void *data1, const void *data2) struct cache_feature *cache_feature[CACHE_MAX_FEATURE] = { [TIMER_FEATURE] = &timer_feature, - [LIFETIME_FEATURE] = &lifetime_feature, [WRITE_THROUGH_FEATURE] = &writethrough_feature, }; @@ -249,6 +249,7 @@ static int __add(struct cache *c, struct cache_object *obj, int id) c->extra->add(obj, ((char *) obj) + c->extra_offset); c->stats.active++; + obj->lifetime = time(NULL); obj->status = C_OBJ_NEW; obj->refcnt++; return 0; diff --git a/src/cache_iterators.c b/src/cache_iterators.c index 4bf518a..3a1ec72 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -26,6 +26,7 @@ #include #include #include +#include struct __dump_container { int fd; @@ -75,6 +76,11 @@ static int do_dump(void *data1, struct hashtable_node *n) data += obj->cache->features[i]->size; } } + if (container->type != NFCT_O_XML) { + long tm = time(NULL); + size += sprintf(buf+size, " [active since %lds]", + tm - obj->lifetime); + } size += sprintf(buf+size, "\n"); if (send(container->fd, buf, size, 0) == -1) { if (errno != EPIPE) diff --git a/src/cache_lifetime.c b/src/cache_lifetime.c deleted file mode 100644 index 639d8c1..0000000 --- a/src/cache_lifetime.c +++ /dev/null @@ -1,65 +0,0 @@ -/* - * (C) 2006 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include "cache.h" -#include -#include -#include - -static void lifetime_add(struct cache_object *obj, void *data) -{ - long *lifetime = data; - struct timeval tv; - - gettimeofday(&tv, NULL); - - *lifetime = tv.tv_sec; -} - -static void lifetime_update(struct cache_object *obj, void *data) -{ -} - -static void lifetime_destroy(struct cache_object *obj, void *data) -{ -} - -static int lifetime_dump(struct cache_object *obj, - void *data, - char *buf, - int type) -{ - long *lifetime = data; - struct timeval tv; - - if (type == NFCT_O_XML) - return 0; - - gettimeofday(&tv, NULL); - - return sprintf(buf, " [active since %lds]", tv.tv_sec - *lifetime); -} - -struct cache_feature lifetime_feature = { - .size = sizeof(long), - .add = lifetime_add, - .update = lifetime_update, - .destroy = lifetime_destroy, - .dump = lifetime_dump -}; diff --git a/src/stats-mode.c b/src/stats-mode.c index b742c0c..226a6b8 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -37,9 +37,7 @@ static int init_stats(void) } memset(state.stats, 0, sizeof(struct ct_stats_state)); - STATE_STATS(cache) = cache_create("stats", - LIFETIME, - NULL); + STATE_STATS(cache) = cache_create("stats", NO_FEATURES, NULL); if (!STATE_STATS(cache)) { dlog(LOG_ERR, "can't allocate memory for the " "external cache"); diff --git a/src/sync-alarm.c b/src/sync-alarm.c index a2f17ac..1815447 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -154,8 +154,8 @@ static void alarm_xmit(void) } struct sync_mode sync_alarm = { - .internal_cache_flags = LIFETIME, - .external_cache_flags = TIMER | LIFETIME, + .internal_cache_flags = NO_FEATURES, + .external_cache_flags = TIMER, .internal_cache_extra = &cache_alarm_extra, .recv = alarm_recv, .enqueue = alarm_enqueue, diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index fd6c350..91ce25d 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -561,8 +561,8 @@ static void ftfw_enqueue(struct cache_object *obj, int type) } struct sync_mode sync_ftfw = { - .internal_cache_flags = LIFETIME, - .external_cache_flags = LIFETIME, + .internal_cache_flags = NO_FEATURES, + .external_cache_flags = NO_FEATURES, .internal_cache_extra = &cache_ftfw_extra, .init = ftfw_init, .kill = ftfw_kill, diff --git a/src/sync-notrack.c b/src/sync-notrack.c index 3b547ee..7bd4351 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -173,8 +173,8 @@ static void notrack_enqueue(struct cache_object *obj, int query) } struct sync_mode sync_notrack = { - .internal_cache_flags = LIFETIME, - .external_cache_flags = LIFETIME, + .internal_cache_flags = NO_FEATURES, + .external_cache_flags = NO_FEATURES, .internal_cache_extra = &cache_notrack_extra, .local = notrack_local, .recv = notrack_recv, -- cgit v1.2.3 From 50c09dec9ad0261d8fcc18d69b2c9ec74052955c Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 25 Jan 2009 17:53:05 +0100 Subject: src: add support for approximate timeout calculation during commit During the commit phase, the entries in the external cache entries are inserted in the kernel conntrack table. Currently, we use a fixed timeout that is specified in the config file. With this patch, if you don't specify the fixed timeout value via CommitTimeout, the daemon calculates the real timeout value during the commit phase. Signed-off-by: Pablo Neira Ayuso --- include/cache.h | 1 + include/network.h | 2 +- src/build.c | 3 +++ src/cache.c | 3 ++- src/cache_iterators.c | 22 ++++++++++++++++++++-- src/read_config_yy.y | 4 ---- 6 files changed, 27 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/include/cache.h b/include/cache.h index 1fd3881..371170d 100644 --- a/include/cache.h +++ b/include/cache.h @@ -34,6 +34,7 @@ struct cache_object { int status; int refcnt; long lifetime; + long lastupdate; char data[0]; }; diff --git a/include/network.h b/include/network.h index 740e762..7cfaf84 100644 --- a/include/network.h +++ b/include/network.h @@ -192,7 +192,7 @@ enum nta_attr { NTA_PORT, /* struct nfct_attr_grp_port */ NTA_STATE = 4, /* uint8_t */ NTA_STATUS, /* uint32_t */ - NTA_TIMEOUT, /* uint32_t -- unused */ + NTA_TIMEOUT, /* uint32_t */ NTA_MARK, /* uint32_t */ NTA_MASTER_IPV4 = 8, /* struct nfct_attr_grp_ipv4 */ NTA_MASTER_IPV6, /* struct nfct_attr_grp_ipv6 */ diff --git a/src/build.c b/src/build.c index e094aa0..63a85db 100644 --- a/src/build.c +++ b/src/build.c @@ -19,6 +19,7 @@ #include #include #include "network.h" +#include "conntrackd.h" static inline void * put_header(struct nethdr *n, int attr, size_t len) @@ -117,6 +118,8 @@ void build_payload(const struct nf_conntrack *ct, struct nethdr *n) if (nfct_attr_is_set(ct, ATTR_TCP_STATE)) __build_u8(ct, ATTR_TCP_STATE, n, NTA_STATE); + if (!CONFIG(commit_timeout) && nfct_attr_is_set(ct, ATTR_TIMEOUT)) + __build_u32(ct, ATTR_TIMEOUT, n, NTA_TIMEOUT); if (nfct_attr_is_set(ct, ATTR_MARK)) __build_u32(ct, ATTR_MARK, n, NTA_MARK); diff --git a/src/cache.c b/src/cache.c index 71825e1..318b8ec 100644 --- a/src/cache.c +++ b/src/cache.c @@ -249,7 +249,7 @@ static int __add(struct cache *c, struct cache_object *obj, int id) c->extra->add(obj, ((char *) obj) + c->extra_offset); c->stats.active++; - obj->lifetime = time(NULL); + obj->lifetime = obj->lastupdate = time(NULL); obj->status = C_OBJ_NEW; obj->refcnt++; return 0; @@ -287,6 +287,7 @@ void cache_update(struct cache *c, struct cache_object *obj, int id, c->extra->update(obj, ((char *) obj) + c->extra_offset); c->stats.upd_ok++; + obj->lastupdate = time(NULL); obj->status = C_OBJ_ALIVE; } diff --git a/src/cache_iterators.c b/src/cache_iterators.c index 3a1ec72..e16a621 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -108,11 +108,29 @@ struct __commit_container { static void __do_commit_step(struct __commit_container *tmp, struct cache_object *obj) { - int ret, retry = 1; + int ret, retry = 1, timeout; struct nf_conntrack *ct = obj->ct; + if (CONFIG(commit_timeout)) { + timeout = CONFIG(commit_timeout); + } else { + timeout = time(NULL) - obj->lastupdate; + if (timeout < 0) { + /* XXX: Arbitrarily set the timer to one minute, how + * can this happen? For example, an adjustment due to + * daylight-saving. Probably other situations can + * trigger this. */ + timeout = 60; + } + /* calculate an estimation of the current timeout */ + timeout = nfct_get_attr_u32(ct, ATTR_TIMEOUT) - timeout; + if (timeout < 0) { + timeout = 60; + } + } + retry: - if (nl_create_conntrack(tmp->h, ct, CONFIG(commit_timeout)) == -1) { + if (nl_create_conntrack(tmp->h, ct, timeout) == -1) { if (errno == EEXIST && retry == 1) { ret = nl_destroy_conntrack(tmp->h, ct); if (ret == 0 || (ret == -1 && errno == ENOENT)) { diff --git a/src/read_config_yy.y b/src/read_config_yy.y index d71829f..766d543 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -1141,10 +1141,6 @@ init_config(char *filename) if (CONFIG(cache_timeout) == 0) CONFIG(cache_timeout) = 180; - /* default to 180 seconds: committed entries */ - if (CONFIG(commit_timeout) == 0) - CONFIG(commit_timeout) = 180; - /* default to 15 seconds: purge kernel entries */ if (CONFIG(purge_timeout) == 0) CONFIG(purge_timeout) = 15; -- cgit v1.2.3 From cced587d766b9194b698a156d241766d5bad8a9d Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 25 Jan 2009 17:53:14 +0100 Subject: src: increase default PurgeTimeout value This patch increases the default PurgeTimeout value to 60 seconds. The former 15 seconds provides good real-time reaction in terms of user-side expected behaviour, but it is too small if you trigger random failure in a firewall cluster. Signed-off-by: Pablo Neira Ayuso --- doc/sync/alarm/conntrackd.conf | 11 +++++------ doc/sync/ftfw/conntrackd.conf | 11 +++++------ doc/sync/notrack/conntrackd.conf | 11 +++++------ src/read_config_yy.y | 4 ++-- 4 files changed, 17 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/doc/sync/alarm/conntrackd.conf b/doc/sync/alarm/conntrackd.conf index 3479a83..db7d99e 100644 --- a/doc/sync/alarm/conntrackd.conf +++ b/doc/sync/alarm/conntrackd.conf @@ -27,13 +27,12 @@ Sync { # # If the firewall replica goes from primary to backup, # the conntrackd -t command is invoked in the script. - # This command resets the timers of the conntracks that - # live in the kernel to this new value. This is useful - # to purge the connection tracking table of zombie entries - # and avoid clashes with old entries if you trigger - # several consecutive hand-overs. + # This command schedules a flush of the table in N seconds. + # This is useful to purge the connection tracking table of + # zombie entries and avoid clashes with old entries if you + # trigger several consecutive hand-overs. Default is 60 seconds # - PurgeTimeout 15 + # PurgeTimeout 60 } # diff --git a/doc/sync/ftfw/conntrackd.conf b/doc/sync/ftfw/conntrackd.conf index 4fd86d7..69572cf 100644 --- a/doc/sync/ftfw/conntrackd.conf +++ b/doc/sync/ftfw/conntrackd.conf @@ -24,13 +24,12 @@ Sync { # # If the firewall replica goes from primary to backup, # the conntrackd -t command is invoked in the script. - # This command resets the timers of the conntracks that - # live in the kernel to this new value. This is useful - # to purge the connection tracking table of zombie entries - # and avoid clashes with old entries if you trigger - # several consecutive hand-overs. + # This command schedules a flush of the table in N seconds. + # This is useful to purge the connection tracking table of + # zombie entries and avoid clashes with old entries if you + # trigger several consecutive hand-overs. Default is 60 seconds. # - PurgeTimeout 15 + # PurgeTimeout 60 # Set the acknowledgement window size. If you decrease this # value, the number of acknowlegdments increases. More diff --git a/doc/sync/notrack/conntrackd.conf b/doc/sync/notrack/conntrackd.conf index 5abf589..1df79a1 100644 --- a/doc/sync/notrack/conntrackd.conf +++ b/doc/sync/notrack/conntrackd.conf @@ -13,13 +13,12 @@ Sync { # # If the firewall replica goes from primary to backup, # the conntrackd -t command is invoked in the script. - # This command resets the timers of the conntracks that - # live in the kernel to this new value. This is useful - # to purge the connection tracking table of zombie entries - # and avoid clashes with old entries if you trigger - # several consecutive hand-overs. + # This command schedules a flush of the table in N seconds. + # This is useful to purge the connection tracking table of + # zombie entries and avoid clashes with old entries if you + # trigger several consecutive hand-overs. Default is 60 seconds. # - PurgeTimeout 15 + # PurgeTimeout 60 } # diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 766d543..049896e 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -1141,9 +1141,9 @@ init_config(char *filename) if (CONFIG(cache_timeout) == 0) CONFIG(cache_timeout) = 180; - /* default to 15 seconds: purge kernel entries */ + /* default to 60 seconds: purge kernel entries */ if (CONFIG(purge_timeout) == 0) - CONFIG(purge_timeout) = 15; + CONFIG(purge_timeout) = 60; /* default to 60 seconds of refresh time */ if (CONFIG(refresh) == 0) -- cgit v1.2.3 From 30ab4eae6a196102285fd649119fa2d9afe35a32 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 25 Jan 2009 17:53:21 +0100 Subject: netlink: set IP_CT_TCP_FLAG_CLOSE_INIT for TIME_WAIT states This patch sets IP_CT_TCP_FLAG_CLOSE_INIT if the entry is in TCP TIME_WAIT state. This patch is a workaround, the daemon should propagate the internal TCP flags to make it fully independent of possible changes in the TCP tracking code. Signed-off-by: Pablo Neira Ayuso --- src/netlink.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'src') diff --git a/src/netlink.c b/src/netlink.c index 24d61a0..a9e3d2d 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -27,6 +27,7 @@ #include #include #include +#include struct nfct_handle *nl_init_event_handler(void) { @@ -226,6 +227,12 @@ int nl_create_conntrack(struct nfct_handle *h, if (nfct_attr_is_set(ct, ATTR_TCP_STATE)) { uint8_t flags = IP_CT_TCP_FLAG_BE_LIBERAL | IP_CT_TCP_FLAG_SACK_PERM; + + /* FIXME: workaround, we should send TCP flags in updates */ + if (nfct_get_attr_u32(ct, ATTR_TCP_STATE) == + TCP_CONNTRACK_TIME_WAIT) { + flags |= IP_CT_TCP_FLAG_CLOSE_INIT; + } nfct_set_attr_u8(ct, ATTR_TCP_FLAGS_ORIG, flags); nfct_set_attr_u8(ct, ATTR_TCP_MASK_ORIG, flags); nfct_set_attr_u8(ct, ATTR_TCP_FLAGS_REPL, flags); @@ -285,6 +292,12 @@ int nl_update_conntrack(struct nfct_handle *h, if (nfct_attr_is_set(ct, ATTR_TCP_STATE)) { uint8_t flags = IP_CT_TCP_FLAG_BE_LIBERAL | IP_CT_TCP_FLAG_SACK_PERM; + + /* FIXME: workaround, we should send TCP flags in updates */ + if (nfct_get_attr_u32(ct, ATTR_TCP_STATE) == + TCP_CONNTRACK_TIME_WAIT) { + flags |= IP_CT_TCP_FLAG_CLOSE_INIT; + } nfct_set_attr_u8(ct, ATTR_TCP_FLAGS_ORIG, flags); nfct_set_attr_u8(ct, ATTR_TCP_MASK_ORIG, flags); nfct_set_attr_u8(ct, ATTR_TCP_FLAGS_REPL, flags); -- cgit v1.2.3 From c3ef4d9b32ca653571f0976f73aaa99218a36db0 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 5 Feb 2009 21:28:02 +0100 Subject: netlink: refactorize several nl_init_*_handler() functions This patch removes: * nl_init_dump_handler() * nl_init_request_handler() * nl_init_resync_handler() since they all look very similar. Signed-off-by: Pablo Neira Ayuso --- include/netlink.h | 3 --- src/netlink.c | 36 ------------------------------------ src/run.c | 8 +++++--- 3 files changed, 5 insertions(+), 42 deletions(-) (limited to 'src') diff --git a/include/netlink.h b/include/netlink.h index 9d67165..0df0cbb 100644 --- a/include/netlink.h +++ b/include/netlink.h @@ -7,9 +7,6 @@ struct nf_conntrack; struct nfct_handle; struct nfct_handle *nl_init_event_handler(void); -struct nfct_handle *nl_init_dump_handler(void); -struct nfct_handle *nl_init_request_handler(void); -struct nfct_handle *nl_init_resync_handler(void); struct nlif_handle *nl_init_interface_handler(void); int nl_send_resync(struct nfct_handle *h); diff --git a/src/netlink.c b/src/netlink.c index a9e3d2d..78cc466 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -79,42 +79,6 @@ struct nfct_handle *nl_init_event_handler(void) return h; } -struct nfct_handle *nl_init_dump_handler(void) -{ - struct nfct_handle *h; - - /* open dump netlink socket */ - h = nfct_open(CONNTRACK, 0); - if (h == NULL) - return NULL; - - return h; -} - -struct nfct_handle *nl_init_resync_handler(void) -{ - struct nfct_handle *h; - - h = nfct_open(CONNTRACK, 0); - if (h == NULL) - return NULL; - - fcntl(nfct_fd(h), F_SETFL, O_NONBLOCK); - - return h; -} - -struct nfct_handle *nl_init_request_handler(void) -{ - struct nfct_handle *h; - - h = nfct_open(CONNTRACK, 0); - if (h == NULL) - return NULL; - - return h; -} - struct nlif_handle *nl_init_interface_handler(void) { struct nlif_handle *h; diff --git a/src/run.c b/src/run.c index a483ab3..7d48865 100644 --- a/src/run.c +++ b/src/run.c @@ -33,6 +33,7 @@ #include #include #include +#include void killer(int foo) { @@ -317,7 +318,7 @@ init(void) register_fd(nfct_fd(STATE(event)), STATE(fds)); } - STATE(dump) = nl_init_dump_handler(); + STATE(dump) = nfct_open(CONNTRACK, 0); if (STATE(dump) == NULL) { dlog(LOG_ERR, "can't open netlink handler: %s", strerror(errno)); @@ -331,7 +332,7 @@ init(void) return -1; } - STATE(resync) = nl_init_resync_handler(); + STATE(resync) = nfct_open(CONNTRACK, 0); if (STATE(resync)== NULL) { dlog(LOG_ERR, "can't open netlink handler: %s", strerror(errno)); @@ -343,9 +344,10 @@ init(void) STATE(mode)->resync, NULL); register_fd(nfct_fd(STATE(resync)), STATE(fds)); + fcntl(nfct_fd(STATE(resync)), F_SETFL, O_NONBLOCK); /* no callback, it does not do anything with the output */ - STATE(request) = nl_init_request_handler(); + STATE(request) = nfct_open(CONNTRACK, 0); if (STATE(request) == NULL) { dlog(LOG_ERR, "can't open netlink handler: %s", strerror(errno)); -- cgit v1.2.3 From ba2f8458ecfa0827e09a1c40c9e29868239fafa1 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 6 Feb 2009 17:43:40 +0100 Subject: src: re-work polling strategy This patch improves the polling support included in 0.9.10. The polling now consists of getting the state table, wait for PollSecs, then purge obsolete entries, and so on. Signed-off-by: Pablo Neira Ayuso --- include/conntrackd.h | 4 +++ src/run.c | 85 ++++++++++++++++++++++++++++++++++++---------------- src/stats-mode.c | 6 ++-- src/sync-mode.c | 28 ++++++++++------- 4 files changed, 83 insertions(+), 40 deletions(-) (limited to 'src') diff --git a/include/conntrackd.h b/include/conntrackd.h index 3e10a2f..34c7629 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -114,7 +114,11 @@ struct ct_general_state { struct nfct_handle *dump; /* dump handler */ struct nfct_handle *request; /* request handler */ struct nfct_handle *resync; /* resync handler */ + struct nfct_handle *get; /* get handler */ + int get_retval; /* hackish */ + struct alarm_block resync_alarm; + struct alarm_block polling_alarm; struct fds *fds; diff --git a/src/run.c b/src/run.c index 7d48865..81f2590 100644 --- a/src/run.c +++ b/src/run.c @@ -1,5 +1,5 @@ /* - * (C) 2006-2007 by Pablo Neira Ayuso + * (C) 2006-2009 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 @@ -40,8 +40,11 @@ void killer(int foo) /* no signals while handling signals */ sigprocmask(SIG_BLOCK, &STATE(block), NULL); - if (!(CONFIG(flags) & CTD_POLL)) + if (!(CONFIG(flags) & CTD_POLL)) { nfct_close(STATE(event)); + nfct_close(STATE(resync)); + } + nfct_close(STATE(get)); nfct_close(STATE(request)); if (STATE(us_filter)) @@ -212,10 +215,13 @@ static void do_overrun_resync_alarm(struct alarm_block *a, void *data) STATE(stats).nl_kernel_table_resync++; } -static void do_poll_resync_alarm(struct alarm_block *a, void *data) +static void do_polling_alarm(struct alarm_block *a, void *data) { - nl_send_resync(STATE(resync)); - add_alarm(&STATE(resync_alarm), CONFIG(poll_kernel_secs), 0); + if (STATE(mode)->purge) + STATE(mode)->purge(); + + nl_send_resync(STATE(dump)); + add_alarm(&STATE(polling_alarm), CONFIG(poll_kernel_secs), 0); } static int event_handler(enum nf_conntrack_msg_type type, @@ -272,6 +278,17 @@ static int dump_handler(enum nf_conntrack_msg_type type, return NFCT_CB_CONTINUE; } +static int get_handler(enum nf_conntrack_msg_type type, + struct nf_conntrack *ct, + void *data) +{ + if (ct_filter_conntrack(ct, 1)) + return NFCT_CB_CONTINUE; + + STATE(get_retval) = 1; + return NFCT_CB_CONTINUE; +} + int init(void) { @@ -316,6 +333,20 @@ init(void) nfct_callback_register(STATE(event), NFCT_T_ALL, event_handler, NULL); register_fd(nfct_fd(STATE(event)), STATE(fds)); + + STATE(resync) = nfct_open(CONNTRACK, 0); + if (STATE(resync)== NULL) { + dlog(LOG_ERR, "can't open netlink handler: %s", + strerror(errno)); + dlog(LOG_ERR, "no ctnetlink kernel support?"); + return -1; + } + nfct_callback_register(STATE(resync), + NFCT_T_ALL, + STATE(mode)->resync, + NULL); + register_fd(nfct_fd(STATE(resync)), STATE(fds)); + fcntl(nfct_fd(STATE(resync)), F_SETFL, O_NONBLOCK); } STATE(dump) = nfct_open(CONNTRACK, 0); @@ -326,25 +357,22 @@ init(void) return -1; } nfct_callback_register(STATE(dump), NFCT_T_ALL, dump_handler, NULL); + if (CONFIG(flags) & CTD_POLL) + register_fd(nfct_fd(STATE(dump)), STATE(fds)); if (nl_dump_conntrack_table(STATE(dump)) == -1) { dlog(LOG_ERR, "can't get kernel conntrack table"); return -1; } - STATE(resync) = nfct_open(CONNTRACK, 0); - if (STATE(resync)== NULL) { + STATE(get) = nfct_open(CONNTRACK, 0); + if (STATE(get) == NULL) { dlog(LOG_ERR, "can't open netlink handler: %s", strerror(errno)); dlog(LOG_ERR, "no ctnetlink kernel support?"); return -1; } - nfct_callback_register(STATE(resync), - NFCT_T_ALL, - STATE(mode)->resync, - NULL); - register_fd(nfct_fd(STATE(resync)), STATE(fds)); - fcntl(nfct_fd(STATE(resync)), F_SETFL, O_NONBLOCK); + nfct_callback_register(STATE(get), NFCT_T_ALL, get_handler, NULL); /* no callback, it does not do anything with the output */ STATE(request) = nfct_open(CONNTRACK, 0); @@ -356,8 +384,8 @@ init(void) } if (CONFIG(flags) & CTD_POLL) { - init_alarm(&STATE(resync_alarm), NULL, do_poll_resync_alarm); - add_alarm(&STATE(resync_alarm), CONFIG(poll_kernel_secs), 0); + init_alarm(&STATE(polling_alarm), NULL, do_polling_alarm); + add_alarm(&STATE(polling_alarm), CONFIG(poll_kernel_secs), 0); dlog(LOG_NOTICE, "running in polling mode"); } else { init_alarm(&STATE(resync_alarm), NULL, do_overrun_resync_alarm); @@ -414,11 +442,11 @@ static void __run(struct timeval *next_alarm) if (FD_ISSET(STATE(local).fd, &readfds)) do_local_server_step(&STATE(local), NULL, local_handler); - /* conntrack event has happened */ - if (!(CONFIG(flags) & CTD_POLL) && - FD_ISSET(nfct_fd(STATE(event)), &readfds)) { - ret = nfct_catch(STATE(event)); - if (ret == -1) { + if (!(CONFIG(flags) & CTD_POLL)) { + /* conntrack event has happened */ + if (FD_ISSET(nfct_fd(STATE(event)), &readfds)) { + ret = nfct_catch(STATE(event)); + if (ret == -1) { switch(errno) { case ENOBUFS: /* We have hit ENOBUFS, it's likely that we are @@ -464,13 +492,18 @@ static void __run(struct timeval *next_alarm) STATE(stats).nl_catch_event_failed++; break; } + } + } + if (FD_ISSET(nfct_fd(STATE(resync)), &readfds)) { + nfct_catch(STATE(resync)); + if (STATE(mode)->purge) + STATE(mode)->purge(); + } + } else { + /* using polling mode */ + if (FD_ISSET(nfct_fd(STATE(dump)), &readfds)) { + nfct_catch(STATE(dump)); } - } - - if (FD_ISSET(nfct_fd(STATE(resync)), &readfds)) { - nfct_catch(STATE(resync)); - if (STATE(mode)->purge) - STATE(mode)->purge(); } if (STATE(mode)->run) diff --git a/src/stats-mode.c b/src/stats-mode.c index 226a6b8..bd20253 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -123,11 +123,11 @@ static int resync_stats(enum nf_conntrack_msg_type type, static int purge_step(void *data1, void *data2) { - int ret; struct cache_object *obj = data2; - ret = nfct_query(STATE(dump), NFCT_Q_GET, obj->ct); - if (ret == -1 && errno == ENOENT) { + STATE(get_retval) = 0; + nl_get_conntrack(STATE(get), obj->ct); /* modifies STATE(get_retval) */ + if (!STATE(get_retval)) { debug_ct(obj->ct, "purge stats"); cache_del(STATE_STATS(cache), obj); cache_object_free(obj); diff --git a/src/sync-mode.c b/src/sync-mode.c index 84a4de0..8174681 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -499,8 +499,15 @@ static int local_handler_sync(int fd, int type, void *data) return ret; } +static void mcast_send_sync(struct cache_object *obj, int query) +{ + STATE_SYNC(sync)->enqueue(obj, query); +} + static void dump_sync(struct nf_conntrack *ct) { + struct cache_object *obj; + /* This is required by kernels < 2.6.20 */ nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES); nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS); @@ -508,23 +515,22 @@ static void dump_sync(struct nf_conntrack *ct) nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); nfct_attr_unset(ct, ATTR_USE); - if (cache_update_force(STATE_SYNC(internal), ct)) - debug_ct(ct, "resync"); -} - -static void mcast_send_sync(struct cache_object *obj, int query) -{ - STATE_SYNC(sync)->enqueue(obj, query); + obj = cache_update_force(STATE_SYNC(internal), ct); + if ((CONFIG(flags) & CTD_POLL)) { + if (obj != NULL && obj->status == C_OBJ_NEW) { + debug_ct(ct, "poll"); + mcast_send_sync(obj, NET_T_STATE_NEW); + } + } } static int purge_step(void *data1, void *data2) { - int ret; - struct nfct_handle *h = STATE(dump); struct cache_object *obj = data2; - ret = nfct_query(h, NFCT_Q_GET, obj->ct); - if (ret == -1 && errno == ENOENT) { + STATE(get_retval) = 0; + nl_get_conntrack(STATE(get), obj->ct); /* modifies STATE(get_reval) */ + if (!STATE(get_retval)) { debug_ct(obj->ct, "purge resync"); if (obj->status != C_OBJ_DEAD) { cache_object_set_status(obj, C_OBJ_DEAD); -- cgit v1.2.3 From f3464ea99081fbe4f429f030ea99c60e2338c047 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 8 Feb 2009 19:13:22 +0100 Subject: netlink: add new option NetlinkOverrunResync This patch adds NetlinkOverrunResync. This option can be used to set the amount of time after which the daemon resynchronizes itself with the kernel state-table if it detects a Netlink overrun. Signed-off-by: Pablo Neira Ayuso --- doc/sync/alarm/conntrackd.conf | 13 +++++++++++++ doc/sync/ftfw/conntrackd.conf | 13 +++++++++++++ doc/sync/notrack/conntrackd.conf | 13 +++++++++++++ include/conntrackd.h | 1 + src/read_config_lex.l | 1 + src/read_config_yy.y | 23 ++++++++++++++++++++++- src/run.c | 8 ++++---- 7 files changed, 67 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/doc/sync/alarm/conntrackd.conf b/doc/sync/alarm/conntrackd.conf index ad9bcd9..5e44d0d 100644 --- a/doc/sync/alarm/conntrackd.conf +++ b/doc/sync/alarm/conntrackd.conf @@ -192,6 +192,19 @@ General { # SocketBufferSizeMaxGrowth 8388608 + # + # If the daemon detects that Netlink is dropping state-change events, + # it automatically schedules a resynchronization against the Kernel + # after 30 seconds (default value). Resynchronizations are expensive + # in terms of CPU consumption since the daemon has to get the full + # kernel state-table and purge state-entries that do not exist anymore. + # Be careful of setting a very small value here. You have the following + # choices: On (enabled, use default 30 seconds value), Off (disabled) + # or Value (in seconds, to set a specific amount of time). If not + # specified, the daemon assumes that this option is enabled. + # + # NetlinkOverrunResync On + # # By default, the daemon receives state updates following an # event-driven model. You can modify this behaviour by switching to diff --git a/doc/sync/ftfw/conntrackd.conf b/doc/sync/ftfw/conntrackd.conf index 0021ea8..92cd9d1 100644 --- a/doc/sync/ftfw/conntrackd.conf +++ b/doc/sync/ftfw/conntrackd.conf @@ -201,6 +201,19 @@ General { # SocketBufferSizeMaxGrowth 8388608 + # + # If the daemon detects that Netlink is dropping state-change events, + # it automatically schedules a resynchronization against the Kernel + # after 30 seconds (default value). Resynchronizations are expensive + # in terms of CPU consumption since the daemon has to get the full + # kernel state-table and purge state-entries that do not exist anymore. + # Be careful of setting a very small value here. You have the following + # choices: On (enabled, use default 30 seconds value), Off (disabled) + # or Value (in seconds, to set a specific amount of time). If not + # specified, the daemon assumes that this option is enabled. + # + # NetlinkOverrunResync On + # # By default, the daemon receives state updates following an # event-driven model. You can modify this behaviour by switching to diff --git a/doc/sync/notrack/conntrackd.conf b/doc/sync/notrack/conntrackd.conf index b77d589..c64291b 100644 --- a/doc/sync/notrack/conntrackd.conf +++ b/doc/sync/notrack/conntrackd.conf @@ -182,6 +182,19 @@ General { # SocketBufferSizeMaxGrowth 8388608 + # + # If the daemon detects that Netlink is dropping state-change events, + # it automatically schedules a resynchronization against the Kernel + # after 30 seconds (default value). Resynchronizations are expensive + # in terms of CPU consumption since the daemon has to get the full + # kernel state-table and purge state-entries that do not exist anymore. + # Be careful of setting a very small value here. You have the following + # choices: On (enabled, use default 30 seconds value), Off (disabled) + # or Value (in seconds, to set a specific amount of time). If not + # specified, the daemon assumes that this option is enabled. + # + # NetlinkOverrunResync On + # # By default, the daemon receives state updates following an # event-driven model. You can modify this behaviour by switching to diff --git a/include/conntrackd.h b/include/conntrackd.h index 34c7629..4051e94 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -80,6 +80,7 @@ struct ct_conf { unsigned int purge_timeout; /* purge kernel entries timeout */ unsigned int netlink_buffer_size; unsigned int netlink_buffer_size_max_grown; + unsigned int nl_overrun_resync; union inet_address *listen_to; unsigned int listen_to_len; unsigned int flags; diff --git a/src/read_config_lex.l b/src/read_config_lex.l index 9bc4c18..26c6124 100644 --- a/src/read_config_lex.l +++ b/src/read_config_lex.l @@ -121,6 +121,7 @@ notrack [N|n][O|o][T|t][R|r][A|a][C|c][K|k] "EventIterationLimit" { return T_EVENT_ITER_LIMIT; } "Default" { return T_DEFAULT; } "PollSecs" { return T_POLL_SECS; } +"NetlinkOverrunResync" { return T_NETLINK_OVERRUN_RESYNC; } {is_on} { return T_ON; } {is_off} { return T_OFF; } diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 049896e..1bea865 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -1,6 +1,6 @@ %{ /* - * (C) 2006-2007 by Pablo Neira Ayuso + * (C) 2006-2009 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 @@ -61,6 +61,7 @@ static void __max_mcast_dedicated_links_reached(void); %token T_MCAST_RCVBUFF T_MCAST_SNDBUFF T_NOTRACK T_POLL_SECS %token T_FILTER T_ADDRESS T_PROTOCOL T_STATE T_ACCEPT T_IGNORE %token T_FROM T_USERSPACE T_KERNELSPACE T_EVENT_ITER_LIMIT T_DEFAULT +%token T_NETLINK_OVERRUN_RESYNC %token T_IP T_PATH_VAL %token T_NUMBER @@ -725,6 +726,7 @@ general_line: hashsize | event_iterations_limit | poll_secs | filter + | netlink_overrun_resync ; netlink_buffer_size: T_BUFFER_SIZE T_NUMBER @@ -737,6 +739,21 @@ netlink_buffer_size_max_grown : T_BUFFER_SIZE_MAX_GROWN T_NUMBER conf.netlink_buffer_size_max_grown = $2; }; +netlink_overrun_resync : T_NETLINK_OVERRUN_RESYNC T_ON +{ + conf.nl_overrun_resync = 30; +}; + +netlink_overrun_resync : T_NETLINK_OVERRUN_RESYNC T_OFF +{ + conf.nl_overrun_resync = -1; +}; + +netlink_overrun_resync : T_NETLINK_OVERRUN_RESYNC T_NUMBER +{ + conf.nl_overrun_resync = $2; +} + family : T_FAMILY T_STRING { if (strncmp($2, "IPv6", strlen("IPv6")) == 0) @@ -1159,5 +1176,9 @@ init_config(char *filename) if (CONFIG(event_iterations_limit) == 0) CONFIG(event_iterations_limit) = 100; + /* if overrun, automatically resync with kernel after 30 seconds */ + if (CONFIG(nl_overrun_resync) == 0) + CONFIG(nl_overrun_resync) = 30; + return 0; } diff --git a/src/run.c b/src/run.c index 81f2590..5c2a3e7 100644 --- a/src/run.c +++ b/src/run.c @@ -417,9 +417,6 @@ init(void) return 0; } -/* interval of 30s. for between two overrun */ -#define OVRUN_INT 30 - static void __run(struct timeval *next_alarm) { int ret; @@ -475,7 +472,10 @@ static void __run(struct timeval *next_alarm) * we resync ourselves. */ nl_resize_socket_buffer(STATE(event)); - add_alarm(&STATE(resync_alarm), OVRUN_INT, 0); + if (CONFIG(nl_overrun_resync) > 0) { + add_alarm(&STATE(resync_alarm), + CONFIG(nl_overrun_resync),0); + } STATE(stats).nl_catch_event_failed++; STATE(stats).nl_overrun++; break; -- cgit v1.2.3 From 9c3690c82cc394214b0026157cb9ab1885542ec9 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 8 Feb 2009 19:41:23 +0100 Subject: sync-mode: flush also internal cache after reset PurgeTimeout Currently, the daemon sends a flush request to the kernel-space. With lots of entries and NetlinkOverrunResync disabled, the daemon remains in an inconsistent state due to an overrun produced by the flush report to userspace. With this patch, the daemon also flush its internal cache after the kernel flush request. Signed-off-by: Pablo Neira Ayuso --- src/sync-mode.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/sync-mode.c b/src/sync-mode.c index 8174681..63948f1 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -210,6 +210,7 @@ static void do_reset_cache_alarm(struct alarm_block *a, void *data) STATE(stats).nl_kernel_table_flush++; dlog(LOG_NOTICE, "flushing kernel conntrack table (scheduled)"); nl_flush_conntrack_table(STATE(request)); + cache_flush(STATE_SYNC(internal)); } static int init_sync(void) -- cgit v1.2.3 From 7f902c8419c891ec3ec83d40fb30afccb2a150c6 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 8 Feb 2009 20:55:34 +0100 Subject: src: add Nice clause to set the nice value Signed-off-by: Pablo Neira Ayuso --- doc/stats/conntrackd.conf | 8 ++++++++ doc/sync/alarm/conntrackd.conf | 8 ++++++++ doc/sync/ftfw/conntrackd.conf | 8 ++++++++ doc/sync/notrack/conntrackd.conf | 8 ++++++++ include/conntrackd.h | 1 + src/main.c | 1 + src/read_config_lex.l | 3 +++ src/read_config_yy.y | 11 +++++++++-- 8 files changed, 46 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/doc/stats/conntrackd.conf b/doc/stats/conntrackd.conf index 889d387..54e2322 100644 --- a/doc/stats/conntrackd.conf +++ b/doc/stats/conntrackd.conf @@ -2,6 +2,14 @@ # General settings # General { + # + # Set the nice value of the daemon. This value goes from -20 + # (most favorable scheduling) to 19 (least favorable). Using a + # negative value reduces the chances to lose state-change events. + # Default is 0. See man nice(1) for more information. + # + Nice -1 + # # Number of buckets in the caches: hash table # diff --git a/doc/sync/alarm/conntrackd.conf b/doc/sync/alarm/conntrackd.conf index 5e44d0d..aa87541 100644 --- a/doc/sync/alarm/conntrackd.conf +++ b/doc/sync/alarm/conntrackd.conf @@ -134,6 +134,14 @@ Sync { # General settings # General { + # + # Set the nice value of the daemon, this value goes from -20 + # (most favorable scheduling) to 19 (least favorable). Using a + # negative value reduces the chances to lose state-change events. + # Default is 0. See man nice(1) for more information. + # + Nice -1 + # # Number of buckets in the cache hashtable. The bigger it is, # the closer it gets to O(1) at the cost of consuming more memory. diff --git a/doc/sync/ftfw/conntrackd.conf b/doc/sync/ftfw/conntrackd.conf index 92cd9d1..a3f42a2 100644 --- a/doc/sync/ftfw/conntrackd.conf +++ b/doc/sync/ftfw/conntrackd.conf @@ -143,6 +143,14 @@ Sync { # General settings # General { + # + # Set the nice value of the daemon, this value goes from -20 + # (most favorable scheduling) to 19 (least favorable). Using a + # negative value reduces the chances to lose state-change events. + # Default is 0. See man nice(1) for more information. + # + Nice -1 + # # Number of buckets in the cache hashtable. The bigger it is, # the closer it gets to O(1) at the cost of consuming more memory. diff --git a/doc/sync/notrack/conntrackd.conf b/doc/sync/notrack/conntrackd.conf index c64291b..755b08b 100644 --- a/doc/sync/notrack/conntrackd.conf +++ b/doc/sync/notrack/conntrackd.conf @@ -124,6 +124,14 @@ Sync { # General settings # General { + # + # Set the nice value of the daemon, this value goes from -20 + # (most favorable scheduling) to 19 (least favorable). Using a + # negative value reduces the chances to lose state-change events. + # Default is 0. See man nice(1) for more information. + # + Nice -1 + # # Number of buckets in the cache hashtable. The bigger it is, # the closer it gets to O(1) at the cost of consuming more memory. diff --git a/include/conntrackd.h b/include/conntrackd.h index 4051e94..2aaa6e6 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -73,6 +73,7 @@ struct ct_conf { int mcast_default_link; struct mcast_conf mcast[MCAST_LINKS_MAX]; struct local_conf local; /* unix socket facilities */ + int nice; int limit; int refresh; int cache_timeout; /* cache entries timeout */ diff --git a/src/main.c b/src/main.c index c3271fe..8f75904 100644 --- a/src/main.c +++ b/src/main.c @@ -279,6 +279,7 @@ int main(int argc, char *argv[]) chdir("/"); close(STDIN_FILENO); + nice(CONFIG(nice)); /* Daemonize conntrackd */ if (type == DAEMON) { diff --git a/src/read_config_lex.l b/src/read_config_lex.l index 26c6124..a1830fd 100644 --- a/src/read_config_lex.l +++ b/src/read_config_lex.l @@ -35,6 +35,7 @@ nl [\n\r] is_on [o|O][n|N] is_off [o|O][f|F][f|F] integer [0-9]+ +signed_integer [\-\+][0-9]+ path \/[^\"\n ]* ip4_cidr \/[0-2]*[0-9]+ ip4_end [0-9]*[0-9]+ @@ -122,10 +123,12 @@ notrack [N|n][O|o][T|t][R|r][A|a][C|c][K|k] "Default" { return T_DEFAULT; } "PollSecs" { return T_POLL_SECS; } "NetlinkOverrunResync" { return T_NETLINK_OVERRUN_RESYNC; } +"Nice" { return T_NICE; } {is_on} { return T_ON; } {is_off} { return T_OFF; } {integer} { yylval.val = atoi(yytext); return T_NUMBER; } +{signed_integer} { yylval.val = atoi(yytext); return T_SIGNED_NUMBER; } {ip4} { yylval.string = strdup(yytext); return T_IP; } {ip6} { yylval.string = strdup(yytext); return T_IP; } {path} { yylval.string = strdup(yytext); return T_PATH_VAL; } diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 1bea865..b9a37f7 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -61,10 +61,11 @@ static void __max_mcast_dedicated_links_reached(void); %token T_MCAST_RCVBUFF T_MCAST_SNDBUFF T_NOTRACK T_POLL_SECS %token T_FILTER T_ADDRESS T_PROTOCOL T_STATE T_ACCEPT T_IGNORE %token T_FROM T_USERSPACE T_KERNELSPACE T_EVENT_ITER_LIMIT T_DEFAULT -%token T_NETLINK_OVERRUN_RESYNC +%token T_NETLINK_OVERRUN_RESYNC T_NICE %token T_IP T_PATH_VAL %token T_NUMBER +%token T_SIGNED_NUMBER %token T_STRING %% @@ -727,6 +728,7 @@ general_line: hashsize | poll_secs | filter | netlink_overrun_resync + | nice ; netlink_buffer_size: T_BUFFER_SIZE T_NUMBER @@ -752,7 +754,12 @@ netlink_overrun_resync : T_NETLINK_OVERRUN_RESYNC T_OFF netlink_overrun_resync : T_NETLINK_OVERRUN_RESYNC T_NUMBER { conf.nl_overrun_resync = $2; -} +}; + +nice : T_NICE T_SIGNED_NUMBER +{ + conf.nice = $2; +}; family : T_FAMILY T_STRING { -- cgit v1.2.3 From 22aa75829c56d06e8c4964ce84553af5d053664a Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 13 Feb 2009 18:39:54 +0100 Subject: cache_iterators: fix wrong printf format in commit-time message This patch uses the appropriate printf format to display the commit time taken (it was using %llu instead of %lu). Signed-off-by: Pablo Neira Ayuso --- src/cache_iterators.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/cache_iterators.c b/src/cache_iterators.c index e16a621..dfccc68 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -208,7 +208,7 @@ void cache_commit(struct cache *c) "committed", commit_fail); nfct_close(tmp.h); - dlog(LOG_NOTICE, "commit has taken %llu.%06llu seconds", + dlog(LOG_NOTICE, "commit has taken %lu.%06lu seconds", res.tv_sec, res.tv_usec); } -- cgit v1.2.3 From cedd1976acefbbf85d95a67a23c72ff011466d62 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 14 Feb 2009 21:26:26 +0100 Subject: src: use resync handler for polling instead of dump handler This patch moves the polling logic into the resync handler. The dump handler action depended on the daemon working mode (polling or event-driven) resulting in an inconsistent behaviour. Signed-off-by: Pablo Neira Ayuso --- src/run.c | 41 ++++++++++++++++++++--------------------- src/sync-mode.c | 26 ++++++++++++++------------ 2 files changed, 34 insertions(+), 33 deletions(-) (limited to 'src') diff --git a/src/run.c b/src/run.c index 5c2a3e7..6465699 100644 --- a/src/run.c +++ b/src/run.c @@ -40,10 +40,10 @@ void killer(int foo) /* no signals while handling signals */ sigprocmask(SIG_BLOCK, &STATE(block), NULL); - if (!(CONFIG(flags) & CTD_POLL)) { + if (!(CONFIG(flags) & CTD_POLL)) nfct_close(STATE(event)); - nfct_close(STATE(resync)); - } + + nfct_close(STATE(resync)); nfct_close(STATE(get)); nfct_close(STATE(request)); @@ -220,7 +220,7 @@ static void do_polling_alarm(struct alarm_block *a, void *data) if (STATE(mode)->purge) STATE(mode)->purge(); - nl_send_resync(STATE(dump)); + nl_send_resync(STATE(resync)); add_alarm(&STATE(polling_alarm), CONFIG(poll_kernel_secs), 0); } @@ -333,21 +333,22 @@ init(void) nfct_callback_register(STATE(event), NFCT_T_ALL, event_handler, NULL); register_fd(nfct_fd(STATE(event)), STATE(fds)); + } - STATE(resync) = nfct_open(CONNTRACK, 0); - if (STATE(resync)== NULL) { - dlog(LOG_ERR, "can't open netlink handler: %s", - strerror(errno)); - dlog(LOG_ERR, "no ctnetlink kernel support?"); - return -1; - } - nfct_callback_register(STATE(resync), - NFCT_T_ALL, - STATE(mode)->resync, - NULL); - register_fd(nfct_fd(STATE(resync)), STATE(fds)); - fcntl(nfct_fd(STATE(resync)), F_SETFL, O_NONBLOCK); + /* resynchronize (like 'dump' socket) but it also purges old entries */ + STATE(resync) = nfct_open(CONNTRACK, 0); + if (STATE(resync)== NULL) { + dlog(LOG_ERR, "can't open netlink handler: %s", + strerror(errno)); + dlog(LOG_ERR, "no ctnetlink kernel support?"); + return -1; } + nfct_callback_register(STATE(resync), + NFCT_T_ALL, + STATE(mode)->resync, + NULL); + register_fd(nfct_fd(STATE(resync)), STATE(fds)); + fcntl(nfct_fd(STATE(resync)), F_SETFL, O_NONBLOCK); STATE(dump) = nfct_open(CONNTRACK, 0); if (STATE(dump) == NULL) { @@ -357,8 +358,6 @@ init(void) return -1; } nfct_callback_register(STATE(dump), NFCT_T_ALL, dump_handler, NULL); - if (CONFIG(flags) & CTD_POLL) - register_fd(nfct_fd(STATE(dump)), STATE(fds)); if (nl_dump_conntrack_table(STATE(dump)) == -1) { dlog(LOG_ERR, "can't get kernel conntrack table"); @@ -501,8 +500,8 @@ static void __run(struct timeval *next_alarm) } } else { /* using polling mode */ - if (FD_ISSET(nfct_fd(STATE(dump)), &readfds)) { - nfct_catch(STATE(dump)); + if (FD_ISSET(nfct_fd(STATE(resync)), &readfds)) { + nfct_catch(STATE(resync)); } } diff --git a/src/sync-mode.c b/src/sync-mode.c index 63948f1..74eb36e 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -507,8 +507,6 @@ static void mcast_send_sync(struct cache_object *obj, int query) static void dump_sync(struct nf_conntrack *ct) { - struct cache_object *obj; - /* This is required by kernels < 2.6.20 */ nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES); nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS); @@ -516,13 +514,8 @@ static void dump_sync(struct nf_conntrack *ct) nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); nfct_attr_unset(ct, ATTR_USE); - obj = cache_update_force(STATE_SYNC(internal), ct); - if ((CONFIG(flags) & CTD_POLL)) { - if (obj != NULL && obj->status == C_OBJ_NEW) { - debug_ct(ct, "poll"); - mcast_send_sync(obj, NET_T_STATE_NEW); - } - } + if (cache_update_force(STATE_SYNC(internal), ct)) + debug_ct(ct, "dump"); } static int purge_step(void *data1, void *data2) @@ -566,11 +559,20 @@ static int resync_sync(enum nf_conntrack_msg_type type, nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); nfct_attr_unset(ct, ATTR_USE); - if ((obj = cache_update_force(STATE_SYNC(internal), ct))) { - debug_ct(obj->ct, "resync"); + obj = cache_update_force(STATE_SYNC(internal), ct); + if (obj == NULL) + return NFCT_CB_CONTINUE; + + switch (obj->status) { + case C_OBJ_NEW: + debug_ct(ct, "resync"); + mcast_send_sync(obj, NET_T_STATE_NEW); + break; + case C_OBJ_ALIVE: + debug_ct(ct, "resync"); mcast_send_sync(obj, NET_T_STATE_UPD); + break; } - return NFCT_CB_CONTINUE; } -- cgit v1.2.3 From fe42b4085b7dab5847bb29155ebc70b4d7880ebe Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 14 Feb 2009 21:54:50 +0100 Subject: stats-mode: fix polling based logging This patch fixes statistics logging based on polling. Signed-off-by: Pablo Neira Ayuso --- src/stats-mode.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/stats-mode.c b/src/stats-mode.c index bd20253..d561409 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -130,6 +130,7 @@ static int purge_step(void *data1, void *data2) if (!STATE(get_retval)) { debug_ct(obj->ct, "purge stats"); cache_del(STATE_STATS(cache), obj); + dlog_ct(STATE(stats_log), obj->ct, NFCT_O_PLAIN); cache_object_free(obj); } -- cgit v1.2.3 From c4ef74420bc09b82146190870186fb067ac163e9 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 15 Feb 2009 15:40:47 +0100 Subject: conntrackd: add `-f internal' and `-f external' options This patch allows flushing the internal and/or the external cache. The `-f' with no extra parameters still works to flush both the internal and the external cache. Signed-off-by: Pablo Neira Ayuso --- conntrackd.8 | 4 ++-- include/conntrackd.h | 2 ++ src/main.c | 23 +++++++++++++++++++++-- src/stats-mode.c | 1 + src/sync-mode.c | 10 ++++++++++ 5 files changed, 36 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/conntrackd.8 b/conntrackd.8 index cd1e2bd..2002738 100644 --- a/conntrackd.8 +++ b/conntrackd.8 @@ -34,8 +34,8 @@ Dump the external cache, i.e. show foreign states Display output in XML format. This option is only valid in combination with "-i" and "-e" parameters. .TP -.BI "-f " -Flush the internal and the external cache +.BI "-f " "[|internal|external]" +Flush the internal and/or external cache .TP .BI "-F " Flush the kernel conntrack table (if you use a Linux kernel >= 2.6.29, this diff --git a/include/conntrackd.h b/include/conntrackd.h index bb038a9..9b3cdf2 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -31,6 +31,8 @@ #define STATS_RUNTIME 30 /* extended runtime stats */ #define STATS_MULTICAST 31 /* multicast network stats */ #define STATS_QUEUE 32 /* queue stats */ +#define FLUSH_INT_CACHE 33 /* flush internal cache */ +#define FLUSH_EXT_CACHE 34 /* flush external cache */ #define DEFAULT_CONFIGFILE "/etc/conntrackd/conntrackd.conf" #define DEFAULT_LOCKFILE "/var/lock/conntrackd.lock" diff --git a/src/main.c b/src/main.c index 8f75904..82f0d27 100644 --- a/src/main.c +++ b/src/main.c @@ -38,7 +38,7 @@ static const char usage_daemon_commands[] = static const char usage_client_commands[] = "Client mode commands:\n" " -c, commit external cache to conntrack table\n" - " -f, flush internal and external cache\n" + " -f [|internal|external], flush internal and external cache\n" " -F, flush kernel conntrack table\n" " -i, display content of the internal cache\n" " -e, display the content of the external cache\n" @@ -144,7 +144,26 @@ int main(int argc, char *argv[]) break; case 'f': set_operation_mode(&type, REQUEST, argv); - action = FLUSH_CACHE; + if (i+1 < argc && argv[i+1][0] != '-') { + if (strncmp(argv[i+1], "internal", + strlen(argv[i+1])) == 0) { + action = FLUSH_INT_CACHE; + i++; + } else if (strncmp(argv[i+1], "external", + strlen(argv[i+1])) == 0) { + action = FLUSH_EXT_CACHE; + i++; + } else { + fprintf(stderr, "ERROR: unknown " + "parameter `%s' for " + "option `-f'\n", + argv[i+1]); + exit(EXIT_FAILURE); + } + } else { + /* default to general flushing */ + action = FLUSH_CACHE; + } break; case 'R': set_operation_mode(&type, REQUEST, argv); diff --git a/src/stats-mode.c b/src/stats-mode.c index d561409..94fc45b 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -66,6 +66,7 @@ static int local_handler_stats(int fd, int type, void *data) cache_dump(STATE_STATS(cache), fd, NFCT_O_XML); break; case FLUSH_CACHE: + case FLUSH_INT_CACHE: dlog(LOG_NOTICE, "flushing caches"); cache_flush(STATE_STATS(cache)); break; diff --git a/src/sync-mode.c b/src/sync-mode.c index 74eb36e..866b313 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -466,6 +466,16 @@ static int local_handler_sync(int fd, int type, void *data) cache_flush(STATE_SYNC(internal)); cache_flush(STATE_SYNC(external)); break; + case FLUSH_INT_CACHE: + /* inmediate flush, remove pending flush scheduled if any */ + del_alarm(&STATE_SYNC(reset_cache_alarm)); + dlog(LOG_NOTICE, "flushing internal cache"); + cache_flush(STATE_SYNC(internal)); + break; + case FLUSH_EXT_CACHE: + dlog(LOG_NOTICE, "flushing external cache"); + cache_flush(STATE_SYNC(external)); + break; case KILL: killer(0); break; -- cgit v1.2.3 From 2304918b8e82e57be87882c97dfc32c4848d68af Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 15 Feb 2009 15:56:15 +0100 Subject: conntrackd: display help information with `-h' This patch also adds missing `-v' information to the manpage. Signed-off-by: Pablo Neira Ayuso --- conntrackd.8 | 6 ++++++ src/main.c | 6 +++++- 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/conntrackd.8 b/conntrackd.8 index 2002738..cd7d084 100644 --- a/conntrackd.8 +++ b/conntrackd.8 @@ -55,6 +55,12 @@ Force a resync against the kernel connection tracking table .TP .BI "-t " Reset the in-kernel timers (See PurgeTimeout clause) +.TP +.BI "-v " +Display version information. +.TP +.BI "-h " +Display help information. .SH DIAGNOSTICS The exit code is 0 for correct function. Errors cause an exit code of 1. .SH EXAMPLES diff --git a/src/main.c b/src/main.c index 82f0d27..239e0da 100644 --- a/src/main.c +++ b/src/main.c @@ -48,7 +48,8 @@ static const char usage_client_commands[] = " -n, request resync with other node (only FT-FW and NOTRACK modes)\n" " -x, dump cache in XML format (requires -i or -e)\n" " -t, reset the kernel timeout (see PurgeTimeout clause)\n" - " -v, display conntrackd version\n"; + " -v, display conntrackd version\n" + " -h, display this help information\n"; static const char usage_options[] = "Options:\n" @@ -240,6 +241,9 @@ int main(int argc, char *argv[]) case 'v': show_version(); exit(EXIT_SUCCESS); + case 'h': + show_usage(argv[0]); + exit(EXIT_SUCCESS); default: show_usage(argv[0]); fprintf(stderr, "Unknown option: %s\n", argv[i]); -- cgit v1.2.3 From 7d355046d80aabb9d4b3e8c0eb4478882b69a497 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 15 Feb 2009 16:04:02 +0100 Subject: conntrackd: don't initialize logging for client request This patch removes the logging initialization for client requests which is of any use for them. Signed-off-by: Pablo Neira Ayuso --- src/main.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/main.c b/src/main.c index 239e0da..26937e1 100644 --- a/src/main.c +++ b/src/main.c @@ -262,12 +262,6 @@ int main(int argc, char *argv[]) exit(EXIT_FAILURE); } - /* - * Setting up logging - */ - if (init_log() == -1) - exit(EXIT_FAILURE); - if (type == REQUEST) { if (do_local_request(action, &conf.local, local_step) == -1) { fprintf(stderr, "can't connect: is conntrackd " @@ -277,6 +271,12 @@ int main(int argc, char *argv[]) exit(EXIT_SUCCESS); } + /* + * Setting up logging + */ + if (init_log() == -1) + exit(EXIT_FAILURE); + /* * lock file */ -- cgit v1.2.3 From 9d67451ca43b0a469f16d0d139e014b9a5fee33d Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 20 Feb 2009 18:33:52 +0100 Subject: headers: don't use NFCT_DIR_MAX in statistics structure This patch removes the use of NFCT_DIR_MAX. This constant is part of the old libnetfilter_conntrack API which has been removed from the git tree. It was introduced in the early days of conntrackd, thus, the use of this constant. Unfortunately, I did not notice until now. Signed-off-by: Pablo Neira Ayuso --- include/conntrackd.h | 6 ++++-- src/traffic_stats.c | 15 +++++++-------- 2 files changed, 11 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/include/conntrackd.h b/include/conntrackd.h index 9b3cdf2..9615c2e 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -128,8 +128,10 @@ struct ct_general_state { /* statistics */ struct { - uint64_t bytes[NFCT_DIR_MAX]; - uint64_t packets[NFCT_DIR_MAX]; + uint64_t bytes_orig; + uint64_t bytes_repl; + uint64_t packets_orig; + uint64_t packets_repl; time_t daemon_start_time; diff --git a/src/traffic_stats.c b/src/traffic_stats.c index 52ca09a..6535527 100644 --- a/src/traffic_stats.c +++ b/src/traffic_stats.c @@ -21,13 +21,13 @@ void update_traffic_stats(struct nf_conntrack *ct) { - STATE(stats).bytes[NFCT_DIR_ORIGINAL] += + STATE(stats).bytes_orig += nfct_get_attr_u32(ct, ATTR_ORIG_COUNTER_BYTES); - STATE(stats).bytes[NFCT_DIR_REPLY] += + STATE(stats).bytes_repl += nfct_get_attr_u32(ct, ATTR_REPL_COUNTER_BYTES); - STATE(stats).packets[NFCT_DIR_ORIGINAL] += + STATE(stats).packets_orig += nfct_get_attr_u32(ct, ATTR_ORIG_COUNTER_PACKETS); - STATE(stats).packets[NFCT_DIR_REPLY] += + STATE(stats).packets_repl += nfct_get_attr_u32(ct, ATTR_REPL_COUNTER_PACKETS); } @@ -35,10 +35,9 @@ void dump_traffic_stats(int fd) { char buf[512]; int size; - uint64_t bytes = STATE(stats).bytes[NFCT_DIR_ORIGINAL] + - STATE(stats).bytes[NFCT_DIR_REPLY]; - uint64_t packets = STATE(stats).packets[NFCT_DIR_ORIGINAL] + - STATE(stats).packets[NFCT_DIR_REPLY]; + uint64_t bytes = STATE(stats).bytes_orig + STATE(stats).bytes_repl; + uint64_t packets = STATE(stats).packets_orig + + STATE(stats).packets_repl; size = sprintf(buf, "traffic processed:\n"); size += sprintf(buf+size, "%20llu Bytes ", (unsigned long long)bytes); -- cgit v1.2.3 From 2112bbdb99a57704ec882ee0926a11c548501f0d Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 20 Feb 2009 20:24:00 +0100 Subject: sync-mode: change current link if message is correct This patch makes conntrackd change the current dedicated link if the message is correct, ie. neither malformed nor out-of-sync. Signed-off-by: Pablo Neira Ayuso --- src/sync-mode.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/sync-mode.c b/src/sync-mode.c index 866b313..02a5a46 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -35,6 +35,13 @@ #include #include +static void +mcast_change_current_link(int if_idx) +{ + if (if_idx != mcast_get_current_ifidx(STATE_SYNC(mcast_client))) + mcast_set_current_link(STATE_SYNC(mcast_client), if_idx); +} + static void do_mcast_handler_step(int if_idx, struct nethdr *net, size_t remain) { @@ -49,14 +56,14 @@ do_mcast_handler_step(int if_idx, struct nethdr *net, size_t remain) return; } - if (if_idx != mcast_get_current_ifidx(STATE_SYNC(mcast_client))) - mcast_set_current_link(STATE_SYNC(mcast_client), if_idx); - switch (STATE_SYNC(sync)->recv(net)) { case MSG_DATA: + mcast_change_current_link(if_idx); break; case MSG_DROP: + return; case MSG_CTL: + mcast_change_current_link(if_idx); return; case MSG_BAD: STATE_SYNC(error).msg_rcv_malformed++; -- cgit v1.2.3 From e83250c0381bbff232011b67c87a5b9f3a0de09a Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 20 Feb 2009 20:42:22 +0100 Subject: src: remove obsolete debug() and debug_ct() calls This patch removes debug() and debug_ct(), I haven't use the debugging information that these functions provide in years. Signed-off-by: Pablo Neira Ayuso --- src/cache_timer.c | 2 -- src/mcast.c | 17 ----------------- src/netlink.c | 1 - src/network.c | 1 - src/stats-mode.c | 8 ++------ src/sync-alarm.c | 3 --- src/sync-ftfw.c | 1 - src/sync-mode.c | 26 ++++++-------------------- src/sync-notrack.c | 1 - 9 files changed, 8 insertions(+), 52 deletions(-) (limited to 'src') diff --git a/src/cache_timer.c b/src/cache_timer.c index a9e3e3d..5881236 100644 --- a/src/cache_timer.c +++ b/src/cache_timer.c @@ -19,7 +19,6 @@ #include "cache.h" #include "conntrackd.h" #include "alarm.h" -#include "debug.h" #include @@ -27,7 +26,6 @@ static void timeout(struct alarm_block *a, void *data) { struct cache_object *obj = data; - debug_ct(obj->ct, "expired timeout"); cache_del(obj->cache, obj); cache_object_free(obj); } diff --git a/src/mcast.c b/src/mcast.c index 70205d8..bc530d3 100644 --- a/src/mcast.c +++ b/src/mcast.c @@ -19,7 +19,6 @@ */ #include "mcast.h" -#include "debug.h" #include #include @@ -73,7 +72,6 @@ struct mcast_sock *mcast_server_create(struct mcast_conf *conf) } if ((m->fd = socket(conf->ipproto, SOCK_DGRAM, 0)) == -1) { - debug("mcast_sock_server_create:socket"); free(m); return NULL; } @@ -84,7 +82,6 @@ struct mcast_sock *mcast_server_create(struct mcast_conf *conf) strncpy(ifr.ifr_name, conf->iface, sizeof(ifr.ifr_name)); if (ioctl(m->fd, SIOCGIFMTU, &ifr) == -1) { - debug("ioctl"); close(m->fd); free(m); return NULL; @@ -94,7 +91,6 @@ struct mcast_sock *mcast_server_create(struct mcast_conf *conf) if (setsockopt(m->fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) { - debug("mcast_sock_server_create:setsockopt1"); close(m->fd); free(m); return NULL; @@ -109,7 +105,6 @@ struct mcast_sock *mcast_server_create(struct mcast_conf *conf) sizeof(int)) == -1) { /* not supported in linux kernel < 2.6.14 */ if (errno != ENOPROTOOPT) { - debug("mcast_sock_server_create:setsockopt2"); close(m->fd); free(m); return NULL; @@ -119,7 +114,6 @@ struct mcast_sock *mcast_server_create(struct mcast_conf *conf) getsockopt(m->fd, SOL_SOCKET, SO_RCVBUF, &conf->rcvbuf, &socklen); if (bind(m->fd, (struct sockaddr *) &m->addr, m->sockaddr_len) == -1) { - debug("mcast_sock_server_create:bind"); close(m->fd); free(m); return NULL; @@ -129,7 +123,6 @@ struct mcast_sock *mcast_server_create(struct mcast_conf *conf) case AF_INET: if (setsockopt(m->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq.ipv4, sizeof(mreq.ipv4)) < 0) { - debug("mcast_sock_server_create:setsockopt2"); close(m->fd); free(m); return NULL; @@ -138,7 +131,6 @@ struct mcast_sock *mcast_server_create(struct mcast_conf *conf) case AF_INET6: if (setsockopt(m->fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq.ipv6, sizeof(mreq.ipv6)) < 0) { - debug("mcast_sock_server_create:setsockopt2"); close(m->fd); free(m); return NULL; @@ -207,7 +199,6 @@ __mcast_client_create_ipv4(struct mcast_sock *m, struct mcast_conf *conf) if (setsockopt(m->fd, IPPROTO_IP, IP_MULTICAST_LOOP, &no, sizeof(int)) < 0) { - debug("mcast_sock_client_create:setsockopt2"); close(m->fd); return -1; } @@ -215,7 +206,6 @@ __mcast_client_create_ipv4(struct mcast_sock *m, struct mcast_conf *conf) if (setsockopt(m->fd, IPPROTO_IP, IP_MULTICAST_IF, &conf->ifa.interface_addr, sizeof(struct in_addr)) == -1) { - debug("mcast_sock_client_create:setsockopt3"); close(m->fd); return -1; } @@ -237,7 +227,6 @@ __mcast_client_create_ipv6(struct mcast_sock *m, struct mcast_conf *conf) if (setsockopt(m->fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &no, sizeof(int)) < 0) { - debug("mcast_sock_client_create:setsockopt2"); close(m->fd); return -1; } @@ -245,7 +234,6 @@ __mcast_client_create_ipv6(struct mcast_sock *m, struct mcast_conf *conf) if (setsockopt(m->fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &conf->ifa.interface_index6, sizeof(unsigned int)) == -1) { - debug("mcast_sock_client_create:setsockopt3"); close(m->fd); return -1; } @@ -267,14 +255,12 @@ struct mcast_sock *mcast_client_create(struct mcast_conf *conf) m->interface_idx = conf->interface_idx; if ((m->fd = socket(conf->ipproto, SOCK_DGRAM, 0)) == -1) { - debug("mcast_sock_client_create:socket"); free(m); return NULL; } if (setsockopt(m->fd, SOL_SOCKET, SO_NO_CHECK, &conf->checksum, sizeof(int)) == -1) { - debug("mcast_sock_client_create:setsockopt1"); close(m->fd); free(m); return NULL; @@ -289,7 +275,6 @@ struct mcast_sock *mcast_client_create(struct mcast_conf *conf) sizeof(int)) == -1) { /* not supported in linux kernel < 2.6.14 */ if (errno != ENOPROTOOPT) { - debug("mcast_sock_server_create:setsockopt2"); close(m->fd); free(m); return NULL; @@ -376,7 +361,6 @@ ssize_t mcast_send(struct mcast_sock *m, void *data, int size) (struct sockaddr *) &m->addr, m->sockaddr_len); if (ret == -1) { - debug("mcast_sock_send"); m->stats.error++; return ret; } @@ -399,7 +383,6 @@ ssize_t mcast_recv(struct mcast_sock *m, void *data, int size) (struct sockaddr *)&m->addr, &sin_size); if (ret == -1) { - debug("mcast_sock_recv"); m->stats.error++; return ret; } diff --git a/src/netlink.c b/src/netlink.c index 78cc466..ef729c1 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -20,7 +20,6 @@ #include "conntrackd.h" #include "filter.h" #include "log.h" -#include "debug.h" #include #include diff --git a/src/network.c b/src/network.c index f71aef0..690b28e 100644 --- a/src/network.c +++ b/src/network.c @@ -19,7 +19,6 @@ #include "conntrackd.h" #include "network.h" #include "log.h" -#include "debug.h" #include #include diff --git a/src/stats-mode.c b/src/stats-mode.c index 94fc45b..af1c136 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -18,7 +18,6 @@ #include "netlink.h" #include "traffic_stats.h" -#include "debug.h" #include "cache.h" #include "log.h" #include "conntrackd.h" @@ -97,8 +96,7 @@ static void dump_stats(struct nf_conntrack *ct) nfct_attr_unset(ct, ATTR_TIMEOUT); nfct_attr_unset(ct, ATTR_USE); - if (cache_update_force(STATE_STATS(cache), ct)) - debug_ct(ct, "resync entry"); + cache_update_force(STATE_STATS(cache), ct); } static int resync_stats(enum nf_conntrack_msg_type type, @@ -116,8 +114,7 @@ static int resync_stats(enum nf_conntrack_msg_type type, nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); nfct_attr_unset(ct, ATTR_USE); - if (!cache_update_force(STATE_STATS(cache), ct)) - debug_ct(ct, "stats resync"); + cache_update_force(STATE_STATS(cache), ct); return NFCT_CB_CONTINUE; } @@ -129,7 +126,6 @@ static int purge_step(void *data1, void *data2) STATE(get_retval) = 0; nl_get_conntrack(STATE(get), obj->ct); /* modifies STATE(get_retval) */ if (!STATE(get_retval)) { - debug_ct(obj->ct, "purge stats"); cache_del(STATE_STATS(cache), obj); dlog_ct(STATE(stats_log), obj->ct, NFCT_O_PLAIN); cache_object_free(obj); diff --git a/src/sync-alarm.c b/src/sync-alarm.c index 1815447..a59ae11 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -22,7 +22,6 @@ #include "alarm.h" #include "cache.h" #include "queue.h" -#include "debug.h" #include #include @@ -38,8 +37,6 @@ static void refresher(struct alarm_block *a, void *data) { struct cache_object *obj = data; - debug_ct(obj->ct, "persistence update"); - add_alarm(a, random() % CONFIG(refresh) + 1, ((random() % 5 + 1) * 200000) - 1); diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 91ce25d..d608e5b 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -19,7 +19,6 @@ #include "conntrackd.h" #include "sync.h" #include "queue.h" -#include "debug.h" #include "network.h" #include "alarm.h" #include "log.h" diff --git a/src/sync-mode.c b/src/sync-mode.c index 02a5a46..d1a941b 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -25,7 +25,6 @@ #include "network.h" #include "fds.h" #include "event.h" -#include "debug.h" #include "queue.h" #include @@ -166,10 +165,6 @@ static void mcast_handler(struct mcast_sock *m, int if_idx) } } - debug("recv sq: %u fl:%u len:%u (rem:%d)\n", - ntohl(net->seq), net->flags, - ntohs(net->len), remain); - HDR_NETWORK2HOST(net); do_mcast_handler_step(if_idx, net, remain); @@ -531,8 +526,7 @@ static void dump_sync(struct nf_conntrack *ct) nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); nfct_attr_unset(ct, ATTR_USE); - if (cache_update_force(STATE_SYNC(internal), ct)) - debug_ct(ct, "dump"); + cache_update_force(STATE_SYNC(internal), ct); } static int purge_step(void *data1, void *data2) @@ -542,7 +536,6 @@ static int purge_step(void *data1, void *data2) STATE(get_retval) = 0; nl_get_conntrack(STATE(get), obj->ct); /* modifies STATE(get_reval) */ if (!STATE(get_retval)) { - debug_ct(obj->ct, "purge resync"); if (obj->status != C_OBJ_DEAD) { cache_object_set_status(obj, C_OBJ_DEAD); mcast_send_sync(obj, NET_T_STATE_DEL); @@ -582,11 +575,9 @@ static int resync_sync(enum nf_conntrack_msg_type type, switch (obj->status) { case C_OBJ_NEW: - debug_ct(ct, "resync"); mcast_send_sync(obj, NET_T_STATE_NEW); break; case C_OBJ_ALIVE: - debug_ct(ct, "resync"); mcast_send_sync(obj, NET_T_STATE_UPD); break; } @@ -615,11 +606,9 @@ retry: return; } mcast_send_sync(obj, NET_T_STATE_NEW); - debug_ct(obj->ct, "internal new"); } else { cache_del(STATE_SYNC(internal), obj); cache_object_free(obj); - debug_ct(ct, "can't add"); goto retry; } } @@ -628,11 +617,10 @@ static void event_update_sync(struct nf_conntrack *ct) { struct cache_object *obj; - if ((obj = cache_update_force(STATE_SYNC(internal), ct)) == NULL) { - debug_ct(ct, "can't update"); + obj = cache_update_force(STATE_SYNC(internal), ct); + if (obj == NULL) return; - } - debug_ct(obj->ct, "internal update"); + mcast_send_sync(obj, NET_T_STATE_UPD); } @@ -642,16 +630,14 @@ static int event_destroy_sync(struct nf_conntrack *ct) int id; obj = cache_find(STATE_SYNC(internal), ct, &id); - if (obj == NULL) { - debug_ct(ct, "can't destroy"); + if (obj == NULL) return 0; - } + if (obj->status != C_OBJ_DEAD) { cache_object_set_status(obj, C_OBJ_DEAD); mcast_send_sync(obj, NET_T_STATE_DEL); cache_object_put(obj); } - debug_ct(ct, "internal destroy"); return 1; } diff --git a/src/sync-notrack.c b/src/sync-notrack.c index 7bd4351..57c3368 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -19,7 +19,6 @@ #include "conntrackd.h" #include "sync.h" #include "queue.h" -#include "debug.h" #include "network.h" #include "log.h" #include "cache.h" -- cgit v1.2.3 From 158fdcef1536da826bcc68294b17f6be354dd913 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 21 Feb 2009 14:05:25 +0100 Subject: mcast: fix compilation warning due missing header This patch includes libnfnetlink.h header in mcast.c to remove a compilation warning due to missing prototype declaration. Signed-off-by: Pablo Neira Ayuso --- src/mcast.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/mcast.c b/src/mcast.c index bc530d3..ba472f6 100644 --- a/src/mcast.c +++ b/src/mcast.c @@ -28,6 +28,7 @@ #include #include #include +#include struct mcast_sock *mcast_server_create(struct mcast_conf *conf) { -- cgit v1.2.3 From ae94864dee8596fcaf19ffe5670d192a0efd5fd6 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 21 Feb 2009 14:18:56 +0100 Subject: config: add NetlinkBufferSize and NetlinkBufferSizeMaxGrowth This patch adds two alias that removes an inconsistency in the configuration file names. Now, the clauses that refers to Netlink starts by the prefix "Netlink". Signed-off-by: Pablo Neira Ayuso --- doc/stats/conntrackd.conf | 4 ++-- doc/sync/alarm/conntrackd.conf | 4 ++-- doc/sync/ftfw/conntrackd.conf | 4 ++-- doc/sync/notrack/conntrackd.conf | 4 ++-- src/read_config_lex.l | 8 +++++--- 5 files changed, 13 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/doc/stats/conntrackd.conf b/doc/stats/conntrackd.conf index 54e2322..1f1a697 100644 --- a/doc/stats/conntrackd.conf +++ b/doc/stats/conntrackd.conf @@ -49,12 +49,12 @@ General { # # Netlink socket buffer size # - SocketBufferSize 262142 + NetlinkBufferSize 262142 # # Increase the socket buffer up to maximun if required # - SocketBufferSizeMaxGrown 655355 + NetlinkBufferSizeMaxGrowth 655355 # # Event filtering: This clause allows you to filter certain traffic, diff --git a/doc/sync/alarm/conntrackd.conf b/doc/sync/alarm/conntrackd.conf index aa87541..cefda00 100644 --- a/doc/sync/alarm/conntrackd.conf +++ b/doc/sync/alarm/conntrackd.conf @@ -190,7 +190,7 @@ General { # and high CPU consumption. This example configuration file sets the # size to 2 MBytes to avoid this sort of problems. # - SocketBufferSize 2097152 + NetlinkBufferSize 2097152 # # The daemon doubles the size of the netlink event socket buffer size @@ -198,7 +198,7 @@ General { # maximum buffer size growth that can be reached. This example file # sets the size to 8 MBytes. # - SocketBufferSizeMaxGrowth 8388608 + NetlinkBufferSizeMaxGrowth 8388608 # # If the daemon detects that Netlink is dropping state-change events, diff --git a/doc/sync/ftfw/conntrackd.conf b/doc/sync/ftfw/conntrackd.conf index 790026b..d7e4123 100644 --- a/doc/sync/ftfw/conntrackd.conf +++ b/doc/sync/ftfw/conntrackd.conf @@ -199,7 +199,7 @@ General { # and high CPU consumption. This example configuration file sets the # size to 2 MBytes to avoid this sort of problems. # - SocketBufferSize 2097152 + NetlinkBufferSize 2097152 # # The daemon doubles the size of the netlink event socket buffer size @@ -207,7 +207,7 @@ General { # maximum buffer size growth that can be reached. This example file # sets the size to 8 MBytes. # - SocketBufferSizeMaxGrowth 8388608 + NetlinkBufferSizeMaxGrowth 8388608 # # If the daemon detects that Netlink is dropping state-change events, diff --git a/doc/sync/notrack/conntrackd.conf b/doc/sync/notrack/conntrackd.conf index 755b08b..884d536 100644 --- a/doc/sync/notrack/conntrackd.conf +++ b/doc/sync/notrack/conntrackd.conf @@ -180,7 +180,7 @@ General { # and high CPU consumption. This example configuration file sets the # size to 2 MBytes to avoid this sort of problems. # - SocketBufferSize 2097152 + NetlinkBufferSize 2097152 # # The daemon doubles the size of the netlink event socket buffer size @@ -188,7 +188,7 @@ General { # maximum buffer size growth that can be reached. This example file # sets the size to 8 MBytes. # - SocketBufferSizeMaxGrowth 8388608 + NetlinkBufferSizeMaxGrowth 8388608 # # If the daemon detects that Netlink is dropping state-change events, diff --git a/src/read_config_lex.l b/src/read_config_lex.l index a1830fd..d75e299 100644 --- a/src/read_config_lex.l +++ b/src/read_config_lex.l @@ -82,9 +82,11 @@ notrack [N|n][O|o][T|t][R|r][A|a][C|c][K|k] "Sync" { return T_SYNC; } "Stats" { return T_STATS; } "RelaxTransitions" { return T_RELAX_TRANSITIONS; } -"SocketBufferSize" { return T_BUFFER_SIZE; } -"SocketBufferSizeMaxGrown" { return T_BUFFER_SIZE_MAX_GROWN; } -"SocketBufferSizeMaxGrowth" { return T_BUFFER_SIZE_MAX_GROWN; } +"SocketBufferSize" { return T_BUFFER_SIZE; /* alias */ } +"SocketBufferSizeMaxGrown" { return T_BUFFER_SIZE_MAX_GROWN; /* alias */ } +"SocketBufferSizeMaxGrowth" { return T_BUFFER_SIZE_MAX_GROWN; /* alias */ } +"NetlinkBufferSize" { return T_BUFFER_SIZE; } +"NetlinkBufferSizeMaxGrowth" { return T_BUFFER_SIZE_MAX_GROWN; } "Mode" { return T_SYNC_MODE; } "ListenTo" { return T_LISTEN_TO; } "Family" { return T_FAMILY; } -- cgit v1.2.3 From abaa6410806e8a9a5d66243d56885d7be00ab524 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 21 Feb 2009 16:38:57 +0100 Subject: netlink: use u8 getter for TCP states This patch replace nfct_get_attr_u32 by nfct_get_attr_u8 which is the correct size of a TCP state. Set also the CLOSE_INIT flag for CLOSE TCP state (as nf_conntrack_proto_tcp allows). Signed-off-by: Pablo Neira Ayuso --- src/netlink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/netlink.c b/src/netlink.c index ef729c1..cca6f3a 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -192,7 +192,7 @@ int nl_create_conntrack(struct nfct_handle *h, IP_CT_TCP_FLAG_SACK_PERM; /* FIXME: workaround, we should send TCP flags in updates */ - if (nfct_get_attr_u32(ct, ATTR_TCP_STATE) == + if (nfct_get_attr_u8(ct, ATTR_TCP_STATE) >= TCP_CONNTRACK_TIME_WAIT) { flags |= IP_CT_TCP_FLAG_CLOSE_INIT; } -- cgit v1.2.3 From 9bf002ff7935e7dff625683787fc3a06ac2ef2cb Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 21 Feb 2009 19:13:06 +0100 Subject: src: fix compilation issue in gentoo due to missing include limits.h This patch adds include limits.h to mcast.c and sync-mode.c. Why Gentoo maintainers did not report me the problem? :( http://bugs.gentoo.org/show_bug.cgi?id=256497 Signed-off-by: Pablo Neira Ayuso --- src/mcast.c | 1 + src/sync-mode.c | 1 + 2 files changed, 2 insertions(+) (limited to 'src') diff --git a/src/mcast.c b/src/mcast.c index ba472f6..8f11762 100644 --- a/src/mcast.c +++ b/src/mcast.c @@ -28,6 +28,7 @@ #include #include #include +#include #include struct mcast_sock *mcast_server_create(struct mcast_conf *conf) diff --git a/src/sync-mode.c b/src/sync-mode.c index d1a941b..26e1358 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -32,6 +32,7 @@ #include #include #include +#include #include static void -- cgit v1.2.3 From 39fdc2e703eb5e82b2bec25e49900684cf689386 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 9 Mar 2009 11:32:36 +0100 Subject: sync-mode: rename mcast_send_sync() to sync_send() This patch is a cleanup. It renames the function mcast_send_sync() to sync_send() since the function itself is not related to multicast anymore (it enqueues state-changes to the upper layer). Signed-off-by: Pablo Neira Ayuso --- src/sync-mode.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/sync-mode.c b/src/sync-mode.c index 26e1358..ba504a5 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -513,7 +513,7 @@ static int local_handler_sync(int fd, int type, void *data) return ret; } -static void mcast_send_sync(struct cache_object *obj, int query) +static void sync_send(struct cache_object *obj, int query) { STATE_SYNC(sync)->enqueue(obj, query); } @@ -539,7 +539,7 @@ static int purge_step(void *data1, void *data2) if (!STATE(get_retval)) { if (obj->status != C_OBJ_DEAD) { cache_object_set_status(obj, C_OBJ_DEAD); - mcast_send_sync(obj, NET_T_STATE_DEL); + sync_send(obj, NET_T_STATE_DEL); cache_object_put(obj); } } @@ -576,10 +576,10 @@ static int resync_sync(enum nf_conntrack_msg_type type, switch (obj->status) { case C_OBJ_NEW: - mcast_send_sync(obj, NET_T_STATE_NEW); + sync_send(obj, NET_T_STATE_NEW); break; case C_OBJ_ALIVE: - mcast_send_sync(obj, NET_T_STATE_UPD); + sync_send(obj, NET_T_STATE_UPD); break; } return NFCT_CB_CONTINUE; @@ -606,7 +606,7 @@ retry: cache_object_free(obj); return; } - mcast_send_sync(obj, NET_T_STATE_NEW); + sync_send(obj, NET_T_STATE_NEW); } else { cache_del(STATE_SYNC(internal), obj); cache_object_free(obj); @@ -622,7 +622,7 @@ static void event_update_sync(struct nf_conntrack *ct) if (obj == NULL) return; - mcast_send_sync(obj, NET_T_STATE_UPD); + sync_send(obj, NET_T_STATE_UPD); } static int event_destroy_sync(struct nf_conntrack *ct) @@ -636,7 +636,7 @@ static int event_destroy_sync(struct nf_conntrack *ct) if (obj->status != C_OBJ_DEAD) { cache_object_set_status(obj, C_OBJ_DEAD); - mcast_send_sync(obj, NET_T_STATE_DEL); + sync_send(obj, NET_T_STATE_DEL); cache_object_put(obj); } return 1; -- cgit v1.2.3 From 56b484e3acc7205f0ebd71eec6905253eeace132 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 9 Mar 2009 11:37:17 +0100 Subject: sync-mode: rename mcast_iface structure to interface This patch renames the mcast_iface to interface since this nlif handler is not related with multicast itself, but to monitor the link interface used to propagate state-changes. This patch is a cleanup. Signed-off-by: Pablo Neira Ayuso --- include/conntrackd.h | 2 +- src/sync-mode.c | 26 +++++++++++++------------- 2 files changed, 14 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/include/conntrackd.h b/include/conntrackd.h index 9615c2e..536abc9 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -165,7 +165,7 @@ struct ct_sync_state { struct mcast_sock_multi *mcast_server; /* multicast incoming */ struct mcast_sock_multi *mcast_client; /* multicast outgoing */ - struct nlif_handle *mcast_iface; + struct nlif_handle *interface; struct queue *tx_queue; struct alarm_block reset_cache_alarm; diff --git a/src/sync-mode.c b/src/sync-mode.c index ba504a5..b452cba 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -175,7 +175,7 @@ static void mcast_handler(struct mcast_sock *m, int if_idx) } /* select a new interface candidate in a round robin basis */ -static void mcast_iface_candidate(void) +static void interface_candidate(void) { int i, idx; unsigned int flags; @@ -185,7 +185,7 @@ static void mcast_iface_candidate(void) idx = mcast_get_ifidx(STATE_SYNC(mcast_client), i); if (idx == mcast_get_current_ifidx(STATE_SYNC(mcast_client))) continue; - nlif_get_ifflags(STATE_SYNC(mcast_iface), idx, &flags); + nlif_get_ifflags(STATE_SYNC(interface), idx, &flags); if (flags & (IFF_RUNNING | IFF_UP)) { mcast_set_current_link(STATE_SYNC(mcast_client), i); dlog(LOG_NOTICE, "device `%s' becomes multicast " @@ -197,15 +197,15 @@ static void mcast_iface_candidate(void) dlog(LOG_ERR, "no dedicated links available!"); } -static void mcast_iface_handler(void) +static void interface_handler(void) { int idx = mcast_get_current_ifidx(STATE_SYNC(mcast_client)); unsigned int flags; - nlif_catch(STATE_SYNC(mcast_iface)); - nlif_get_ifflags(STATE_SYNC(mcast_iface), idx, &flags); + nlif_catch(STATE_SYNC(interface)); + nlif_get_ifflags(STATE_SYNC(interface), idx, &flags); if (!(flags & IFF_RUNNING) || !(flags & IFF_UP)) - mcast_iface_candidate(); + interface_candidate(); } static void do_reset_cache_alarm(struct alarm_block *a, void *data) @@ -299,12 +299,12 @@ static int init_sync(void) return -1; } - STATE_SYNC(mcast_iface) = nl_init_interface_handler(); - if (!STATE_SYNC(mcast_iface)) { + STATE_SYNC(interface) = nl_init_interface_handler(); + if (!STATE_SYNC(interface)) { dlog(LOG_ERR, "can't open interface watcher"); return -1; } - if (register_fd(nlif_fd(STATE_SYNC(mcast_iface)), STATE(fds)) == -1) + if (register_fd(nlif_fd(STATE_SYNC(interface)), STATE(fds)) == -1) return -1; STATE_SYNC(tx_queue) = queue_create(INT_MAX, QUEUE_F_EVFD); @@ -337,8 +337,8 @@ static void run_sync(fd_set *readfds) if (FD_ISSET(queue_get_eventfd(STATE_SYNC(tx_queue)), readfds)) STATE_SYNC(sync)->xmit(); - if (FD_ISSET(nlif_fd(STATE_SYNC(mcast_iface)), readfds)) - mcast_iface_handler(); + if (FD_ISSET(nlif_fd(STATE_SYNC(interface)), readfds)) + interface_handler(); /* flush pending messages */ mcast_buffered_pending_netmsg(STATE_SYNC(mcast_client)); @@ -352,7 +352,7 @@ static void kill_sync(void) mcast_server_destroy_multi(STATE_SYNC(mcast_server)); mcast_client_destroy_multi(STATE_SYNC(mcast_client)); - nlif_close(STATE_SYNC(mcast_iface)); + nlif_close(STATE_SYNC(interface)); mcast_buffered_destroy(); queue_destroy(STATE_SYNC(tx_queue)); @@ -502,7 +502,7 @@ static int local_handler_sync(int fd, int type, void *data) case STATS_MULTICAST: mcast_dump_stats_extended(fd, STATE_SYNC(mcast_client), STATE_SYNC(mcast_server), - STATE_SYNC(mcast_iface)); + STATE_SYNC(interface)); break; default: if (STATE_SYNC(sync)->local) -- cgit v1.2.3 From 656d5ad7c69a5a7d356c6251743890f1eec0bb71 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 12 Mar 2009 21:09:27 +0100 Subject: sync-mode: add abstract layer to make daemon independent of multicast This patch reworks conntrackd to make it independent of the protocol used to propagate state-changes. This patch adds the channel layer abstraction, this layer allows you to add support for different protocols like unicast UDP or TIPC. Signed-off-by: Pablo Neira Ayuso --- include/Makefile.am | 2 +- include/channel.h | 95 +++++++++++++++++++++++++++ include/conntrackd.h | 10 +-- include/mcast.h | 26 ++------ include/network.h | 5 -- src/Makefile.am | 1 + src/channel.c | 180 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/channel_mcast.c | 123 +++++++++++++++++++++++++++++++++++ src/mcast.c | 169 +---------------------------------------------- src/multichannel.c | 110 +++++++++++++++++++++++++++++++ src/network.c | 61 ----------------- src/read_config_yy.y | 69 +++++++++++--------- src/sync-alarm.c | 4 +- src/sync-ftfw.c | 4 +- src/sync-mode.c | 82 +++++++++-------------- src/sync-notrack.c | 4 +- 16 files changed, 596 insertions(+), 349 deletions(-) create mode 100644 include/channel.h create mode 100644 src/channel.c create mode 100644 src/channel_mcast.c create mode 100644 src/multichannel.c (limited to 'src') diff --git a/include/Makefile.am b/include/Makefile.am index c3f8904..0265620 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -3,5 +3,5 @@ noinst_HEADERS = alarm.h jhash.h cache.h linux_list.h linux_rbtree.h \ sync.h conntrackd.h local.h \ debug.h log.h hash.h mcast.h conntrack.h \ network.h filter.h queue.h vector.h cidr.h \ - traffic_stats.h netlink.h fds.h event.h bitops.h + traffic_stats.h netlink.h fds.h event.h bitops.h channel.h diff --git a/include/channel.h b/include/channel.h new file mode 100644 index 0000000..ac1a93c --- /dev/null +++ b/include/channel.h @@ -0,0 +1,95 @@ +#ifndef _CHANNEL_H_ +#define _CHANNEL_H_ + +#include "mcast.h" + +struct channel; +struct nethdr; + +enum { + CHANNEL_MCAST, + CHANNEL_MAX, +}; + +struct mcast_channel { + struct mcast_sock *client; + struct mcast_sock *server; +}; + +#define CHANNEL_F_DEFAULT (1 << 0) +#define CHANNEL_F_BUFFERED (1 << 1) +#define CHANNEL_F_MAX (1 << 2) + +union channel_type_conf { + struct mcast_conf mcast; +}; + +struct channel_conf { + int channel_type; + char channel_ifname[IFNAMSIZ]; + unsigned int channel_flags; + union channel_type_conf u; +}; + +struct nlif_handle; + +struct channel_ops { + void * (*open)(void *conf); + void (*close)(void *channel); + int (*send)(void *channel, const void *data, int len); + int (*recv)(void *channel, char *buf, int len); + int (*get_fd)(void *channel); + void (*stats)(struct channel *c, int fd); + void (*stats_extended)(struct channel *c, int active, + struct nlif_handle *h, int fd); +}; + +struct channel_buffer; + +struct channel { + int channel_type; + int channel_ifindex; + int channel_ifmtu; + unsigned int channel_flags; + struct channel_buffer *buffer; + struct channel_ops *ops; + void *data; +}; + +void channel_init(void); +struct channel *channel_open(struct channel_conf *conf); +void channel_close(struct channel *c); + +int channel_send(struct channel *c, const struct nethdr *net); +int channel_send_flush(struct channel *c); +int channel_recv(struct channel *c, char *buf, int size); + +int channel_get_fd(struct channel *c); +void channel_stats(struct channel *c, int fd); +void channel_stats_extended(struct channel *c, int active, + struct nlif_handle *h, int fd); + +#define MULTICHANNEL_MAX 4 + +struct multichannel { + int channel_num; + struct channel *channel[MULTICHANNEL_MAX]; + struct channel *current; +}; + +struct multichannel *multichannel_open(struct channel_conf *conf, int len); +void multichannel_close(struct multichannel *m); + +int multichannel_send(struct multichannel *c, const struct nethdr *net); +int multichannel_send_flush(struct multichannel *c); +int multichannel_recv(struct multichannel *c, char *buf, int size); + +void multichannel_stats(struct multichannel *m, int fd); +void multichannel_stats_extended(struct multichannel *m, + struct nlif_handle *h, int fd); + +int multichannel_get_ifindex(struct multichannel *m, int i); +int multichannel_get_current_ifindex(struct multichannel *m); +void multichannel_set_current_channel(struct multichannel *m, int i); + +#endif /* _CHANNEL_H_ */ diff --git a/include/conntrackd.h b/include/conntrackd.h index 536abc9..cfb1ac5 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -5,6 +5,7 @@ #include "local.h" #include "alarm.h" #include "filter.h" +#include "channel.h" #include #include @@ -71,9 +72,9 @@ struct ct_conf { int syslog_facility; char lockfile[FILENAME_MAXLEN]; int hashsize; /* hashtable size */ - int mcast_links; - int mcast_default_link; - struct mcast_conf mcast[MCAST_LINKS_MAX]; + int channel_num; + int channel_default; + struct channel_conf channel[MULTICHANNEL_MAX]; struct local_conf local; /* unix socket facilities */ int nice; int limit; @@ -163,8 +164,7 @@ struct ct_sync_state { struct cache *internal; /* internal events cache (netlink) */ struct cache *external; /* external events cache (mcast) */ - struct mcast_sock_multi *mcast_server; /* multicast incoming */ - struct mcast_sock_multi *mcast_client; /* multicast outgoing */ + struct multichannel *channel; struct nlif_handle *interface; struct queue *tx_queue; diff --git a/include/mcast.h b/include/mcast.h index 623f390..68d18e8 100644 --- a/include/mcast.h +++ b/include/mcast.h @@ -42,38 +42,22 @@ struct mcast_sock { struct mcast_stats stats; }; -#define MCAST_LINKS_MAX 4 - -struct mcast_sock_multi { - int num_links; - int max_mtu; - struct mcast_sock *current_link; - struct mcast_sock *multi[MCAST_LINKS_MAX]; -}; - struct mcast_sock *mcast_server_create(struct mcast_conf *conf); void mcast_server_destroy(struct mcast_sock *m); -struct mcast_sock_multi *mcast_server_create_multi(struct mcast_conf *conf, int conf_len); -void mcast_server_destroy_multi(struct mcast_sock_multi *m); struct mcast_sock *mcast_client_create(struct mcast_conf *conf); void mcast_client_destroy(struct mcast_sock *m); -struct mcast_sock_multi *mcast_client_create_multi(struct mcast_conf *conf, int conf_len); -void mcast_client_destroy_multi(struct mcast_sock_multi*m); ssize_t mcast_send(struct mcast_sock *m, void *data, int size); ssize_t mcast_recv(struct mcast_sock *m, void *data, int size); int mcast_get_fd(struct mcast_sock *m); -int mcast_get_ifidx(struct mcast_sock_multi *m, int i); -int mcast_get_current_ifidx(struct mcast_sock_multi *m); - -struct mcast_sock *mcast_get_current_link(struct mcast_sock_multi *m); -void mcast_set_current_link(struct mcast_sock_multi *m, int i); -void mcast_dump_stats(int fd, const struct mcast_sock_multi *s, const struct mcast_sock_multi *r); +int mcast_snprintf_stats(char *buf, size_t buflen, char *ifname, + struct mcast_stats *s, struct mcast_stats *r); -struct nlif_handle; +int mcast_snprintf_stats2(char *buf, size_t buflen, const char *ifname, + const char *status, int active, + struct mcast_stats *s, struct mcast_stats *r); -void mcast_dump_stats_extended(int fd, const struct mcast_sock_multi *s, const struct mcast_sock_multi *r, const struct nlif_handle *h); #endif diff --git a/include/network.h b/include/network.h index 29a6113..7019d7d 100644 --- a/include/network.h +++ b/include/network.h @@ -106,11 +106,6 @@ int mcast_track_is_seq_set(void); struct mcast_conf; -int mcast_buffered_init(int mtu); -void mcast_buffered_destroy(void); -int mcast_buffered_send_netmsg(struct mcast_sock_multi *m, const struct nethdr *net); -ssize_t mcast_buffered_pending_netmsg(struct mcast_sock_multi *m); - #define IS_DATA(x) (x->type <= NET_T_STATE_MAX && \ (x->flags & ~(NET_F_HELLO | NET_F_HELLO_BACK)) == 0) #define IS_ACK(x) (x->type == NET_T_CTL && x->flags & NET_F_ACK) diff --git a/src/Makefile.am b/src/Makefile.am index 8ba09e1..54cfda4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -19,6 +19,7 @@ conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c rbtree.c \ traffic_stats.c stats-mode.c \ network.c cidr.c \ build.c parse.c \ + channel.c multichannel.c channel_mcast.c \ read_config_yy.y read_config_lex.l # yacc and lex generate dirty code diff --git a/src/channel.c b/src/channel.c new file mode 100644 index 0000000..733fd03 --- /dev/null +++ b/src/channel.c @@ -0,0 +1,180 @@ +/* + * (C) 2009 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 +#include +#include +#include +#include +#include + +#include "channel.h" +#include "network.h" + +static struct channel_ops *ops[CHANNEL_MAX]; +extern struct channel_ops channel_mcast; + +void channel_init(void) +{ + ops[CHANNEL_MCAST] = &channel_mcast; +} + +#define HEADERSIZ 28 /* IP header (20 bytes) + UDP header 8 (bytes) */ + +struct channel_buffer { + char *data; + int size; + int len; +}; + +static struct channel_buffer * +channel_buffer_open(int mtu) +{ + struct channel_buffer *b; + + b = calloc(sizeof(struct channel_buffer), 1); + if (b == NULL) + return NULL; + + b->size = mtu - HEADERSIZ; + + b->data = malloc(b->size); + if (b->data == NULL) { + free(b); + return NULL; + } + return b; +} + +static void +channel_buffer_close(struct channel_buffer *b) +{ + free(b->data); + free(b); +} + +struct channel * +channel_open(struct channel_conf *conf) +{ + struct channel *c; + struct ifreq ifr; + int fd; + + if (conf->channel_type >= CHANNEL_MAX) + return NULL; + if (!conf->channel_ifname[0]) + return NULL; + if (conf->channel_flags >= CHANNEL_F_MAX) + return NULL; + + c = calloc(sizeof(struct channel), 1); + if (c == NULL) + return NULL; + + c->channel_type = conf->channel_type; + + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd == -1) { + free(c); + return NULL; + } + strncpy(ifr.ifr_name, conf->channel_ifname, sizeof(ifr.ifr_name)); + + if (ioctl(fd, SIOCGIFMTU, &ifr) == -1) { + free(c); + return NULL; + } + close(fd); + c->channel_ifmtu = ifr.ifr_mtu; + + c->channel_ifindex = if_nametoindex(conf->channel_ifname); + if (c->channel_ifindex == 0) { + free(c); + return NULL; + } + c->ops = ops[conf->channel_type]; + + if (conf->channel_flags & CHANNEL_F_BUFFERED) { + c->buffer = channel_buffer_open(c->channel_ifmtu); + if (c->buffer == NULL) { + free(c); + return NULL; + } + } + c->channel_flags = conf->channel_flags; + + c->data = c->ops->open(&conf->u); + if (c->data == NULL) { + channel_buffer_close(c->buffer); + free(c); + return NULL; + } + return c; +} + +void +channel_close(struct channel *c) +{ + c->ops->close(c->data); + if (c->channel_flags & CHANNEL_F_BUFFERED) + channel_buffer_close(c->buffer); + free(c); +} + +int channel_send(struct channel *c, const struct nethdr *net) +{ + int ret = 0, len = ntohs(net->len); + + if (!(c->channel_flags & CHANNEL_F_BUFFERED)) { + c->ops->send(c->data, net, len); + return 1; + } +retry: + if (c->buffer->len + len < c->buffer->size) { + memcpy(c->buffer->data + c->buffer->len, net, len); + c->buffer->len += len; + } else { + c->ops->send(c->data, c->buffer->data, c->buffer->len); + ret = 1; + c->buffer->len = 0; + goto retry; + } + return ret; +} + +int channel_send_flush(struct channel *c) +{ + if (!(c->channel_flags & CHANNEL_F_BUFFERED) || c->buffer->len == 0) + return 0; + + c->ops->send(c->data, c->buffer->data, c->buffer->len); + c->buffer->len = 0; + return 1; +} + +int channel_recv(struct channel *c, char *buf, int size) +{ + return c->ops->recv(c->data, buf, size); +} + +int channel_get_fd(struct channel *c) +{ + return c->ops->get_fd(c->data); +} + +void channel_stats(struct channel *c, int fd) +{ + return c->ops->stats(c, fd); +} + +void channel_stats_extended(struct channel *c, int active, + struct nlif_handle *h, int fd) +{ + return c->ops->stats_extended(c, active, h, fd); +} diff --git a/src/channel_mcast.c b/src/channel_mcast.c new file mode 100644 index 0000000..898b194 --- /dev/null +++ b/src/channel_mcast.c @@ -0,0 +1,123 @@ +/* + * (C) 2009 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 +#include + +#include "channel.h" +#include "mcast.h" + +static void +*channel_mcast_open(void *conf) +{ + struct mcast_channel *m; + struct mcast_conf *c = conf; + + m = calloc(sizeof(struct mcast_channel), 1); + if (m == NULL) + return NULL; + + m->client = mcast_client_create(c); + if (m->client == NULL) { + free(m); + return NULL; + } + + m->server = mcast_server_create(c); + if (m->server == NULL) { + mcast_client_destroy(m->client); + free(m); + return NULL; + } + return m; +} + +static int +channel_mcast_send(void *channel, const void *data, int len) +{ + struct mcast_channel *m = channel; + return mcast_send(m->client, data, len); +} + +static int +channel_mcast_recv(void *channel, char *buf, int size) +{ + struct mcast_channel *m = channel; + return mcast_recv(m->server, buf, size); +} + +static void +channel_mcast_close(void *channel) +{ + struct mcast_channel *m = channel; + mcast_client_destroy(m->client); + mcast_server_destroy(m->server); + free(m); +} + +static int +channel_mcast_get_fd(void *channel) +{ + struct mcast_channel *m = channel; + return mcast_get_fd(m->server); +} + +static void +channel_mcast_stats(struct channel *c, int fd) +{ + struct mcast_channel *m = c->data; + char ifname[IFNAMSIZ], buf[512]; + int size; + + if_indextoname(c->channel_ifindex, ifname); + size = mcast_snprintf_stats(buf, sizeof(buf), ifname, + &m->client->stats, &m->server->stats); + send(fd, buf, size, 0); +} + +static void +channel_mcast_stats_extended(struct channel *c, int active, + struct nlif_handle *h, int fd) +{ + struct mcast_channel *m = c->data; + char ifname[IFNAMSIZ], buf[512]; + const char *status; + unsigned int flags; + int size; + + if_indextoname(c->channel_ifindex, ifname); + nlif_get_ifflags(h, c->channel_ifindex, &flags); + /* + * IFF_UP shows administrative status + * IFF_RUNNING shows carrier status + */ + if (flags & IFF_UP) { + if (!(flags & IFF_RUNNING)) + status = "NO-CARRIER"; + else + status = "RUNNING"; + } else { + status = "DOWN"; + } + size = mcast_snprintf_stats2(buf, sizeof(buf), + ifname, status, active, + &m->client->stats, + &m->server->stats); + send(fd, buf, size, 0); +} + +struct channel_ops channel_mcast = { + .open = channel_mcast_open, + .close = channel_mcast_close, + .send = channel_mcast_send, + .recv = channel_mcast_recv, + .get_fd = channel_mcast_get_fd, + .stats = channel_mcast_stats, + .stats_extended = channel_mcast_stats_extended, +}; diff --git a/src/mcast.c b/src/mcast.c index 8f11762..8eedd07 100644 --- a/src/mcast.c +++ b/src/mcast.c @@ -143,52 +143,12 @@ struct mcast_sock *mcast_server_create(struct mcast_conf *conf) return m; } -struct mcast_sock_multi * -mcast_server_create_multi(struct mcast_conf *conf, int conf_len) -{ - struct mcast_sock_multi *m; - int i, j; - - if (conf_len <= 0 || conf_len > MCAST_LINKS_MAX) - return NULL; - - m = calloc(sizeof(struct mcast_sock_multi), 1); - if (m == NULL) - return NULL; - - m->max_mtu = INT_MAX; - for (i=0; imulti[i] = mcast_server_create(&conf[i]); - if (m->multi[i] == NULL) { - for (j=0; jmulti[j]); - } - free(m); - return NULL; - } - if (m->max_mtu > conf[i].mtu) - m->max_mtu = conf[i].mtu; - } - m->num_links = conf_len; - - return m; -} - void mcast_server_destroy(struct mcast_sock *m) { close(m->fd); free(m); } -void mcast_server_destroy_multi(struct mcast_sock_multi *m) -{ - int i; - - for (i=0; inum_links; i++) - mcast_server_destroy(m->multi[i]); - free(m); -} - static int __mcast_client_create_ipv4(struct mcast_sock *m, struct mcast_conf *conf) { @@ -306,52 +266,12 @@ struct mcast_sock *mcast_client_create(struct mcast_conf *conf) return m; } -struct mcast_sock_multi * -mcast_client_create_multi(struct mcast_conf *conf, int conf_len) -{ - struct mcast_sock_multi *m; - int i, j; - - if (conf_len <= 0 || conf_len > MCAST_LINKS_MAX) - return NULL; - - m = calloc(sizeof(struct mcast_sock_multi), 1); - if (m == NULL) - return NULL; - - m->max_mtu = INT_MAX; - for (i=0; imulti[i] = mcast_client_create(&conf[i]); - if (m->multi[i] == NULL) { - for (j=0; jmulti[j]); - } - free(m); - return NULL; - } - if (m->max_mtu > conf[i].mtu) - m->max_mtu = conf[i].mtu; - } - m->num_links = conf_len; - - return m; -} - void mcast_client_destroy(struct mcast_sock *m) { close(m->fd); free(m); } -void mcast_client_destroy_multi(struct mcast_sock_multi *m) -{ - int i; - - for (i=0; inum_links; i++) - mcast_client_destroy(m->multi[i]); - free(m); -} - ssize_t mcast_send(struct mcast_sock *m, void *data, int size) { ssize_t ret; @@ -395,32 +315,12 @@ ssize_t mcast_recv(struct mcast_sock *m, void *data, int size) return ret; } -void mcast_set_current_link(struct mcast_sock_multi *m, int i) -{ - m->current_link = m->multi[i]; -} - -struct mcast_sock *mcast_get_current_link(struct mcast_sock_multi *m) -{ - return m->current_link; -} - int mcast_get_fd(struct mcast_sock *m) { return m->fd; } -int mcast_get_current_ifidx(struct mcast_sock_multi *m) -{ - return m->current_link->interface_idx; -} - -int mcast_get_ifidx(struct mcast_sock_multi *m, int i) -{ - return m->multi[i]->interface_idx; -} - -static int +int mcast_snprintf_stats(char *buf, size_t buflen, char *ifname, struct mcast_stats *s, struct mcast_stats *r) { @@ -443,7 +343,7 @@ mcast_snprintf_stats(char *buf, size_t buflen, char *ifname, return size; } -static int +int mcast_snprintf_stats2(char *buf, size_t buflen, const char *ifname, const char *status, int active, struct mcast_stats *s, struct mcast_stats *r) @@ -467,68 +367,3 @@ mcast_snprintf_stats2(char *buf, size_t buflen, const char *ifname, (unsigned long long)r->error); return size; } - -void -mcast_dump_stats(int fd, - const struct mcast_sock_multi *s, - const struct mcast_sock_multi *r) -{ - int i; - struct mcast_stats snd = { 0, 0, 0}; - struct mcast_stats rcv = { 0, 0, 0}; - char ifname[IFNAMSIZ], buf[512]; - int size; - - /* it is the same for the receiver, no need to do it twice */ - if_indextoname(s->current_link->interface_idx, ifname); - - for (i=0; inum_links && inum_links; i++) { - snd.bytes += s->multi[i]->stats.bytes; - snd.messages += s->multi[i]->stats.messages; - snd.error += s->multi[i]->stats.error; - rcv.bytes += r->multi[i]->stats.bytes; - rcv.messages += r->multi[i]->stats.messages; - rcv.error += r->multi[i]->stats.error; - } - size = mcast_snprintf_stats(buf, sizeof(buf), ifname, &snd, &rcv); - send(fd, buf, size, 0); -} - -void -mcast_dump_stats_extended(int fd, - const struct mcast_sock_multi *s, - const struct mcast_sock_multi *r, - const struct nlif_handle *h) -{ - int i; - char buf[4096]; - int size = 0; - - for (i=0; inum_links && inum_links; i++) { - int idx = s->multi[i]->interface_idx, active; - unsigned int flags; - char ifname[IFNAMSIZ]; - const char *status; - - if_indextoname(idx, ifname); - nlif_get_ifflags(h, idx, &flags); - active = (s->multi[i] == s->current_link); - /* - * IFF_UP shows administrative status - * IFF_RUNNING shows carrier status - */ - if (flags & IFF_UP) { - if (!(flags & IFF_RUNNING)) - status = "NO-CARRIER"; - else - status = "RUNNING"; - } else { - status = "DOWN"; - } - size += mcast_snprintf_stats2(buf+size, sizeof(buf), - ifname, status, active, - &s->multi[i]->stats, - &r->multi[i]->stats); - } - send(fd, buf, size, 0); -} diff --git a/src/multichannel.c b/src/multichannel.c new file mode 100644 index 0000000..ab0f04c --- /dev/null +++ b/src/multichannel.c @@ -0,0 +1,110 @@ +/* + * (C) 2009 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 + +#include "channel.h" +#include "network.h" + +struct multichannel * +multichannel_open(struct channel_conf *conf, int len) +{ + struct multichannel *m; + int i, set_default_channel = 0; + + if (len <= 0 || len > MULTICHANNEL_MAX) + return NULL; + + m = calloc(sizeof(struct multichannel), 1); + if (m == NULL) + return NULL; + + m->channel_num = len; + for (i = 0; i < len; i++) { + m->channel[i] = channel_open(&conf[i]); + if (m->channel[i] == NULL) { + int j; + + for (j=0; jchannel[j]); + } + free(m); + return NULL; + } + if (conf[i].channel_flags & CHANNEL_F_DEFAULT) { + m->current = m->channel[i]; + set_default_channel = 1; + } + } + if (!set_default_channel) + m->current = m->channel[0]; + + return m; +} + +int multichannel_send(struct multichannel *c, const struct nethdr *net) +{ + return channel_send(c->current, net); +} + +int multichannel_send_flush(struct multichannel *c) +{ + return channel_send_flush(c->current); +} + +int multichannel_recv(struct multichannel *c, char *buf, int size) +{ + return channel_recv(c->current, buf, size); +} + +void multichannel_close(struct multichannel *m) +{ + int i; + + for (i = 0; i < m->channel_num; i++) { + channel_close(m->channel[i]); + } + free(m); +} + +void multichannel_stats(struct multichannel *m, int fd) +{ + channel_stats(m->current, fd); +} + +void +multichannel_stats_extended(struct multichannel *m, + struct nlif_handle *h, int fd) +{ + int i, active; + + for (i = 0; i < m->channel_num; i++) { + if (m->current == m->channel[i]) { + active = 1; + } else { + active = 0; + } + channel_stats_extended(m->channel[i], active, h, fd); + } +} + +int multichannel_get_ifindex(struct multichannel *m, int i) +{ + return m->channel[i]->channel_ifindex; +} + +int multichannel_get_current_ifindex(struct multichannel *m) +{ + return m->current->channel_ifindex; +} + +void multichannel_set_current_channel(struct multichannel *m, int i) +{ + m->current = m->channel[i]; +} diff --git a/src/network.c b/src/network.c index 690b28e..bdfa10c 100644 --- a/src/network.c +++ b/src/network.c @@ -65,67 +65,6 @@ void nethdr_set_ctl(struct nethdr *net) __nethdr_set(net, NETHDR_SIZ); } -static size_t tx_buflenmax; -static size_t tx_buflen = 0; -static char *tx_buf; - -#define HEADERSIZ 28 /* IP header (20 bytes) + UDP header 8 (bytes) */ - -int mcast_buffered_init(int if_mtu) -{ - int mtu = if_mtu - HEADERSIZ; - - /* default to Ethernet MTU 1500 bytes */ - if (if_mtu == 0) - mtu = 1500 - HEADERSIZ; - - tx_buf = malloc(mtu); - if (tx_buf == NULL) - return -1; - - tx_buflenmax = mtu; - - return 0; -} - -void mcast_buffered_destroy(void) -{ - free(tx_buf); -} - -/* return 0 if it is not sent, otherwise return 1 */ -int -mcast_buffered_send_netmsg(struct mcast_sock_multi *m, const struct nethdr *net) -{ - int ret = 0, len = ntohs(net->len); - -retry: - if (tx_buflen + len < tx_buflenmax) { - memcpy(tx_buf + tx_buflen, net, len); - tx_buflen += len; - } else { - mcast_send(mcast_get_current_link(m), tx_buf, tx_buflen); - ret = 1; - tx_buflen = 0; - goto retry; - } - - return ret; -} - -ssize_t mcast_buffered_pending_netmsg(struct mcast_sock_multi *m) -{ - ssize_t ret; - - if (tx_buflen == 0) - return 0; - - ret = mcast_send(mcast_get_current_link(m), tx_buf, tx_buflen); - tx_buflen = 0; - - return ret; -} - static int local_seq_set = 0; /* this function only tracks, it does not update the last sequence received */ diff --git a/src/read_config_yy.y b/src/read_config_yy.y index b9a37f7..b3a2640 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -181,18 +181,18 @@ checksum: T_CHECKSUM T_ON * XXX: The use of Checksum outside of the Multicast clause is broken * if we have more than one dedicated links. */ - conf.mcast[0].checksum = 0; + conf.channel[0].u.mcast.checksum = 0; }; checksum: T_CHECKSUM T_OFF { fprintf(stderr, "WARNING: The use of `Checksum' outside the " "`Multicast' clause is ambiguous.\n"); - /* + /* * XXX: The use of Checksum outside of the Multicast clause is broken * if we have more than one dedicated links. */ - conf.mcast[0].checksum = 1; + conf.channel[0].u.mcast.checksum = 1; }; ignore_traffic : T_IGNORE_TRAFFIC '{' ignore_traffic_options '}' @@ -256,13 +256,18 @@ ignore_traffic_option : T_IPV6_ADDR T_IP multicast_line : T_MULTICAST '{' multicast_options '}' { - conf.mcast_links++; + conf.channel[conf.channel_num].channel_type = CHANNEL_MCAST; + conf.channel[conf.channel_num].channel_flags = CHANNEL_F_BUFFERED; + conf.channel_num++; }; multicast_line : T_MULTICAST T_DEFAULT '{' multicast_options '}' { - conf.mcast_default_link = conf.mcast_links; - conf.mcast_links++; + conf.channel[conf.channel_num].channel_type = CHANNEL_MCAST; + conf.channel[conf.channel_num].channel_flags = CHANNEL_F_DEFAULT | + CHANNEL_F_BUFFERED; + conf.channel_default = conf.channel_num; + conf.channel_num++; }; multicast_options : @@ -272,19 +277,19 @@ multicast_option : T_IPV4_ADDR T_IP { __max_mcast_dedicated_links_reached(); - if (!inet_aton($2, &conf.mcast[conf.mcast_links].in)) { + if (!inet_aton($2, &conf.channel[conf.channel_num].u.mcast.in)) { fprintf(stderr, "%s is not a valid IPv4 address\n", $2); break; } - if (conf.mcast[conf.mcast_links].ipproto == AF_INET6) { + if (conf.channel[conf.channel_num].u.mcast.ipproto == AF_INET6) { fprintf(stderr, "Your multicast address is IPv4 but " "is binded to an IPv6 interface? Surely " "this is not what you want\n"); break; } - conf.mcast[conf.mcast_links].ipproto = AF_INET; + conf.channel[conf.channel_num].u.mcast.ipproto = AF_INET; }; multicast_option : T_IPV6_ADDR T_IP @@ -292,7 +297,8 @@ multicast_option : T_IPV6_ADDR T_IP __max_mcast_dedicated_links_reached(); #ifdef HAVE_INET_PTON_IPV6 - if (inet_pton(AF_INET6, $2, &conf.mcast[conf.mcast_links].in) <= 0) { + if (inet_pton(AF_INET6, $2, + &conf.channel[conf.channel_num].u.mcast.in) <= 0) { fprintf(stderr, "%s is not a valid IPv6 address\n", $2); break; } @@ -301,17 +307,17 @@ multicast_option : T_IPV6_ADDR T_IP break; #endif - if (conf.mcast[conf.mcast_links].ipproto == AF_INET) { + if (conf.channel[conf.channel_num].u.mcast.ipproto == AF_INET) { fprintf(stderr, "Your multicast address is IPv6 but " "is binded to an IPv4 interface? Surely " "this is not what you want\n"); break; } - conf.mcast[conf.mcast_links].ipproto = AF_INET6; + conf.channel[conf.channel_num].u.mcast.ipproto = AF_INET6; - if (conf.mcast[conf.mcast_links].iface[0] && - !conf.mcast[conf.mcast_links].ifa.interface_index6) { + if (conf.channel[conf.channel_num].u.mcast.iface[0] && + !conf.channel[conf.channel_num].u.mcast.ifa.interface_index6) { unsigned int idx; idx = if_nametoindex($2); @@ -320,8 +326,8 @@ multicast_option : T_IPV6_ADDR T_IP break; } - conf.mcast[conf.mcast_links].ifa.interface_index6 = idx; - conf.mcast[conf.mcast_links].ipproto = AF_INET6; + conf.channel[conf.channel_num].u.mcast.ifa.interface_index6 = idx; + conf.channel[conf.channel_num].u.mcast.ipproto = AF_INET6; } }; @@ -329,19 +335,19 @@ multicast_option : T_IPV4_IFACE T_IP { __max_mcast_dedicated_links_reached(); - if (!inet_aton($2, &conf.mcast[conf.mcast_links].ifa)) { + if (!inet_aton($2, &conf.channel[conf.channel_num].u.mcast.ifa)) { fprintf(stderr, "%s is not a valid IPv4 address\n", $2); break; } - if (conf.mcast[conf.mcast_links].ipproto == AF_INET6) { + if (conf.channel[conf.channel_num].u.mcast.ipproto == AF_INET6) { fprintf(stderr, "Your multicast interface is IPv4 but " "is binded to an IPv6 interface? Surely " "this is not what you want\n"); break; } - conf.mcast[conf.mcast_links].ipproto = AF_INET; + conf.channel[conf.channel_num].u.mcast.ipproto = AF_INET; }; multicast_option : T_IPV6_IFACE T_IP @@ -355,18 +361,19 @@ multicast_option : T_IFACE T_STRING __max_mcast_dedicated_links_reached(); - strncpy(conf.mcast[conf.mcast_links].iface, $2, IFNAMSIZ); + strncpy(conf.channel[conf.channel_num].channel_ifname, $2, IFNAMSIZ); + strncpy(conf.channel[conf.channel_num].u.mcast.iface, $2, IFNAMSIZ); idx = if_nametoindex($2); if (!idx) { fprintf(stderr, "%s is an invalid interface.\n", $2); break; } - conf.mcast[conf.mcast_links].interface_idx = idx; + conf.channel[conf.channel_num].u.mcast.interface_idx = idx; - if (conf.mcast[conf.mcast_links].ipproto == AF_INET6) { - conf.mcast[conf.mcast_links].ifa.interface_index6 = idx; - conf.mcast[conf.mcast_links].ipproto = AF_INET6; + if (conf.channel[conf.channel_num].u.mcast.ipproto == AF_INET6) { + conf.channel[conf.channel_num].u.mcast.ifa.interface_index6 = idx; + conf.channel[conf.channel_num].u.mcast.ipproto = AF_INET6; } }; @@ -379,31 +386,31 @@ multicast_option : T_BACKLOG T_NUMBER multicast_option : T_GROUP T_NUMBER { __max_mcast_dedicated_links_reached(); - conf.mcast[conf.mcast_links].port = $2; + conf.channel[conf.channel_num].u.mcast.port = $2; }; multicast_option: T_MCAST_SNDBUFF T_NUMBER { __max_mcast_dedicated_links_reached(); - conf.mcast[conf.mcast_links].sndbuf = $2; + conf.channel[conf.channel_num].u.mcast.sndbuf = $2; }; multicast_option: T_MCAST_RCVBUFF T_NUMBER { __max_mcast_dedicated_links_reached(); - conf.mcast[conf.mcast_links].rcvbuf = $2; + conf.channel[conf.channel_num].u.mcast.rcvbuf = $2; }; multicast_option: T_CHECKSUM T_ON { __max_mcast_dedicated_links_reached(); - conf.mcast[conf.mcast_links].checksum = 0; + conf.channel[conf.channel_num].u.mcast.checksum = 0; }; multicast_option: T_CHECKSUM T_OFF { __max_mcast_dedicated_links_reached(); - conf.mcast[conf.mcast_links].checksum = 1; + conf.channel[conf.channel_num].u.mcast.checksum = 1; }; hashsize : T_HASHSIZE T_NUMBER @@ -1128,10 +1135,10 @@ static void __kernel_filter_add_state(int value) static void __max_mcast_dedicated_links_reached(void) { - if (conf.mcast_links >= MCAST_LINKS_MAX) { + if (conf.channel_num >= MULTICHANNEL_MAX) { fprintf(stderr, "ERROR: too many dedicated links in " "the configuration file (Maximum: %d).\n", - MCAST_LINKS_MAX); + MULTICHANNEL_MAX); exit(EXIT_FAILURE); } } diff --git a/src/sync-alarm.c b/src/sync-alarm.c index a59ae11..caa6bb2 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -125,7 +125,7 @@ static int tx_queue_xmit(struct queue_node *n, const void *data) net = queue_node_data(n); nethdr_set_ctl(net); HDR_HOST2NETWORK(net); - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); + multichannel_send(STATE_SYNC(channel), net); queue_object_free((struct queue_object *)n); break; case Q_ELEM_OBJ: { @@ -137,7 +137,7 @@ static int tx_queue_xmit(struct queue_node *n, const void *data) obj = cache_data_get_object(STATE_SYNC(internal), ca); type = object_status_to_network_type(obj->status); net = BUILD_NETMSG(obj->ct, type); - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); + multichannel_send(STATE_SYNC(channel), net); cache_object_put(obj); break; } diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index d608e5b..cacbb13 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -494,7 +494,7 @@ static int tx_queue_xmit(struct queue_node *n, const void *data) dp("tx_queue sq: %u fl:%u len:%u\n", ntohl(net->seq), net->flags, ntohs(net->len)); - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); + multichannel_send(STATE_SYNC(channel), net); HDR_NETWORK2HOST(net); if (IS_ACK(net) || IS_NACK(net) || IS_RESYNC(net)) { @@ -523,7 +523,7 @@ static int tx_queue_xmit(struct queue_node *n, const void *data) dp("tx_list sq: %u fl:%u len:%u\n", ntohl(net->seq), net->flags, ntohs(net->len)); - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); + multichannel_send(STATE_SYNC(channel), net); cn->seq = ntohl(net->seq); if (queue_add(rs_queue, &cn->qnode) < 0) { if (errno == ENOSPC) { diff --git a/src/sync-mode.c b/src/sync-mode.c index b452cba..22609df 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -38,12 +38,12 @@ static void mcast_change_current_link(int if_idx) { - if (if_idx != mcast_get_current_ifidx(STATE_SYNC(mcast_client))) - mcast_set_current_link(STATE_SYNC(mcast_client), if_idx); + if (if_idx != multichannel_get_current_ifindex(STATE_SYNC(channel))) + multichannel_set_current_channel(STATE_SYNC(channel), if_idx); } static void -do_mcast_handler_step(int if_idx, struct nethdr *net, size_t remain) +do_channel_handler_step(int if_idx, struct nethdr *net, size_t remain) { char __ct[nfct_maxsize()]; struct nf_conntrack *ct = (struct nf_conntrack *)(void*) __ct; @@ -122,14 +122,14 @@ retry: } } -/* handler for multicast messages received */ -static void mcast_handler(struct mcast_sock *m, int if_idx) +/* handler for messages received */ +static void channel_handler(struct channel *m, int if_idx) { ssize_t numbytes; ssize_t remain; char __net[65536], *ptr = __net; /* XXX: maximum MTU for IPv4 */ - numbytes = mcast_recv(m, __net, sizeof(__net)); + numbytes = channel_recv(m, __net, sizeof(__net)); if (numbytes <= 0) return; @@ -168,7 +168,7 @@ static void mcast_handler(struct mcast_sock *m, int if_idx) HDR_NETWORK2HOST(net); - do_mcast_handler_step(if_idx, net, remain); + do_channel_handler_step(if_idx, net, remain); ptr += net->len; remain -= net->len; } @@ -181,13 +181,13 @@ static void interface_candidate(void) unsigned int flags; char buf[IFNAMSIZ]; - for (i=0; inum_links; i++) { - idx = mcast_get_ifidx(STATE_SYNC(mcast_client), i); - if (idx == mcast_get_current_ifidx(STATE_SYNC(mcast_client))) + for (i=0; ichannel_num; i++) { + idx = multichannel_get_ifindex(STATE_SYNC(channel), i); + if (idx == multichannel_get_current_ifindex(STATE_SYNC(channel))) continue; nlif_get_ifflags(STATE_SYNC(interface), idx, &flags); if (flags & (IFF_RUNNING | IFF_UP)) { - mcast_set_current_link(STATE_SYNC(mcast_client), i); + multichannel_set_current_channel(STATE_SYNC(channel), i); dlog(LOG_NOTICE, "device `%s' becomes multicast " "dedicated link", if_indextoname(idx, buf)); @@ -199,7 +199,7 @@ static void interface_candidate(void) static void interface_handler(void) { - int idx = mcast_get_current_ifidx(STATE_SYNC(mcast_client)); + int idx = multichannel_get_current_ifindex(STATE_SYNC(channel)); unsigned int flags; nlif_catch(STATE_SYNC(interface)); @@ -267,38 +267,21 @@ static int init_sync(void) return -1; } - /* multicast server to receive events from the wire */ - STATE_SYNC(mcast_server) = - mcast_server_create_multi(CONFIG(mcast), CONFIG(mcast_links)); - if (STATE_SYNC(mcast_server) == NULL) { - dlog(LOG_ERR, "can't open multicast server!"); + channel_init(); + + /* channel to send events on the wire */ + STATE_SYNC(channel) = + multichannel_open(CONFIG(channel), CONFIG(channel_num)); + if (STATE_SYNC(channel) == NULL) { + dlog(LOG_ERR, "can't open channel socket"); return -1; } - for (i=0; inum_links; i++) { - int fd = mcast_get_fd(STATE_SYNC(mcast_server)->multi[i]); + for (i=0; ichannel_num; i++) { + int fd = channel_get_fd(STATE_SYNC(channel)->channel[i]); if (register_fd(fd, STATE(fds)) == -1) return -1; } - /* multicast client to send events on the wire */ - STATE_SYNC(mcast_client) = - mcast_client_create_multi(CONFIG(mcast), CONFIG(mcast_links)); - if (STATE_SYNC(mcast_client) == NULL) { - dlog(LOG_ERR, "can't open client multicast socket"); - mcast_server_destroy_multi(STATE_SYNC(mcast_server)); - return -1; - } - /* we only use one link to send events, but all to receive them */ - mcast_set_current_link(STATE_SYNC(mcast_client), - CONFIG(mcast_default_link)); - - if (mcast_buffered_init(STATE_SYNC(mcast_client)->max_mtu) == -1) { - dlog(LOG_ERR, "can't init tx buffer!"); - mcast_server_destroy_multi(STATE_SYNC(mcast_server)); - mcast_client_destroy_multi(STATE_SYNC(mcast_client)); - return -1; - } - STATE_SYNC(interface) = nl_init_interface_handler(); if (!STATE_SYNC(interface)) { dlog(LOG_ERR, "can't open interface watcher"); @@ -328,10 +311,10 @@ static void run_sync(fd_set *readfds) { int i; - for (i=0; inum_links; i++) { - int fd = mcast_get_fd(STATE_SYNC(mcast_server)->multi[i]); + for (i=0; ichannel_num; i++) { + int fd = channel_get_fd(STATE_SYNC(channel)->channel[i]); if (FD_ISSET(fd, readfds)) - mcast_handler(STATE_SYNC(mcast_server)->multi[i], i); + channel_handler(STATE_SYNC(channel)->channel[i], i); } if (FD_ISSET(queue_get_eventfd(STATE_SYNC(tx_queue)), readfds)) @@ -341,7 +324,7 @@ static void run_sync(fd_set *readfds) interface_handler(); /* flush pending messages */ - mcast_buffered_pending_netmsg(STATE_SYNC(mcast_client)); + multichannel_send_flush(STATE_SYNC(channel)); } static void kill_sync(void) @@ -349,12 +332,10 @@ static void kill_sync(void) cache_destroy(STATE_SYNC(internal)); cache_destroy(STATE_SYNC(external)); - mcast_server_destroy_multi(STATE_SYNC(mcast_server)); - mcast_client_destroy_multi(STATE_SYNC(mcast_client)); + multichannel_close(STATE_SYNC(channel)); nlif_close(STATE_SYNC(interface)); - mcast_buffered_destroy(); queue_destroy(STATE_SYNC(tx_queue)); if (STATE_SYNC(sync)->kill) @@ -486,23 +467,20 @@ static int local_handler_sync(int fd, int type, void *data) cache_stats(STATE_SYNC(internal), fd); cache_stats(STATE_SYNC(external), fd); dump_traffic_stats(fd); - mcast_dump_stats(fd, STATE_SYNC(mcast_client), - STATE_SYNC(mcast_server)); + multichannel_stats(STATE_SYNC(channel), fd); dump_stats_sync(fd); break; case STATS_NETWORK: dump_stats_sync_extended(fd); - mcast_dump_stats(fd, STATE_SYNC(mcast_client), - STATE_SYNC(mcast_server)); + multichannel_stats(STATE_SYNC(channel), fd); break; case STATS_CACHE: cache_stats_extended(STATE_SYNC(internal), fd); cache_stats_extended(STATE_SYNC(external), fd); break; case STATS_MULTICAST: - mcast_dump_stats_extended(fd, STATE_SYNC(mcast_client), - STATE_SYNC(mcast_server), - STATE_SYNC(interface)); + multichannel_stats_extended(STATE_SYNC(channel), + STATE_SYNC(interface), fd); break; default: if (STATE_SYNC(sync)->local) diff --git a/src/sync-notrack.c b/src/sync-notrack.c index 57c3368..737ee52 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -134,7 +134,7 @@ static int tx_queue_xmit(struct queue_node *n, const void *data2) else nethdr_set_ctl(net); HDR_HOST2NETWORK(net); - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); + multichannel_send(STATE_SYNC(channel), net); queue_del(n); queue_object_free((struct queue_object *)n); break; @@ -150,7 +150,7 @@ static int tx_queue_xmit(struct queue_node *n, const void *data2) type = object_status_to_network_type(obj->status);; net = BUILD_NETMSG(obj->ct, type); - mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net); + multichannel_send(STATE_SYNC(channel), net); queue_del(n); cache_object_put(obj); break; -- cgit v1.2.3 From 338d8fc2da19f5d6a75c339d9e6ecac43b68a1e4 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 12 Mar 2009 21:19:19 +0100 Subject: sync-mode: rename mcast_track_*() by nethdr_track_*() This patch is a cleanup. It renames the mcast_track_*() functions by nethdr_track_*() because this functions are related to message sequence tracking. They are not stick to multicast at all. Signed-off-by: Pablo Neira Ayuso --- include/network.h | 6 +++--- src/network.c | 6 +++--- src/sync-alarm.c | 2 +- src/sync-ftfw.c | 6 +++--- src/sync-notrack.c | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/include/network.h b/include/network.h index 7019d7d..b182339 100644 --- a/include/network.h +++ b/include/network.h @@ -100,9 +100,9 @@ enum { SEQ_BEFORE, }; -int mcast_track_seq(uint32_t seq, uint32_t *exp_seq); -void mcast_track_update_seq(uint32_t seq); -int mcast_track_is_seq_set(void); +int nethdr_track_seq(uint32_t seq, uint32_t *exp_seq); +void nethdr_track_update_seq(uint32_t seq); +int nethdr_track_is_seq_set(void); struct mcast_conf; diff --git a/src/network.c b/src/network.c index bdfa10c..6a66a2b 100644 --- a/src/network.c +++ b/src/network.c @@ -68,7 +68,7 @@ void nethdr_set_ctl(struct nethdr *net) static int local_seq_set = 0; /* this function only tracks, it does not update the last sequence received */ -int mcast_track_seq(uint32_t seq, uint32_t *exp_seq) +int nethdr_track_seq(uint32_t seq, uint32_t *exp_seq) { int ret = SEQ_UNKNOWN; @@ -104,7 +104,7 @@ out: return ret; } -void mcast_track_update_seq(uint32_t seq) +void nethdr_track_update_seq(uint32_t seq) { if (!local_seq_set) local_seq_set = 1; @@ -112,7 +112,7 @@ void mcast_track_update_seq(uint32_t seq) STATE_SYNC(last_seq_recv) = seq; } -int mcast_track_is_seq_set() +int nethdr_track_is_seq_set() { return local_seq_set; } diff --git a/src/sync-alarm.c b/src/sync-alarm.c index caa6bb2..4757026 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -102,7 +102,7 @@ static int alarm_recv(const struct nethdr *net) * just joined the cluster, instead they just get resynchronized in * RefreshTime seconds at worst case. */ - mcast_track_seq(net->seq, &exp_seq); + nethdr_track_seq(net->seq, &exp_seq); return 0; } diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index cacbb13..e026b1c 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -129,7 +129,7 @@ static void tx_queue_add_ctlmsg2(uint32_t flags) /* this function is called from the alarm framework */ static void do_alive_alarm(struct alarm_block *a, void *data) { - if (ack_from_set && mcast_track_is_seq_set()) { + if (ack_from_set && nethdr_track_is_seq_set()) { /* exp_seq contains the last update received */ tx_queue_add_ctlmsg(NET_F_ACK, ack_from, @@ -396,7 +396,7 @@ static int ftfw_recv(const struct nethdr *net) goto bypass; } - switch (mcast_track_seq(net->seq, &exp_seq)) { + switch (nethdr_track_seq(net->seq, &exp_seq)) { case SEQ_AFTER: ret = digest_msg(net); if (ret == MSG_BAD) { @@ -446,7 +446,7 @@ bypass: out: if ((ret == MSG_DATA || ret == MSG_CTL)) - mcast_track_update_seq(net->seq); + nethdr_track_update_seq(net->seq); return ret; } diff --git a/src/sync-notrack.c b/src/sync-notrack.c index 737ee52..6502bcd 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -114,12 +114,12 @@ static int notrack_recv(const struct nethdr *net) int ret; unsigned int exp_seq; - mcast_track_seq(net->seq, &exp_seq); + nethdr_track_seq(net->seq, &exp_seq); ret = digest_msg(net); if (ret != MSG_BAD) - mcast_track_update_seq(net->seq); + nethdr_track_update_seq(net->seq); return ret; } -- cgit v1.2.3 From 41e8560ea7c09533d03f523380c1cb5c62d87261 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 13 Mar 2009 14:00:59 +0100 Subject: sync-mode: add unicast UDP support to propagate state-changes This patch adds support for unicast UDP to the channel infrastructure. With this patch, you can select UDP unicast to propagate state-changes instead of multicast. Signed-off-by: Pablo Neira Ayuso --- doc/sync/alarm/conntrackd.conf | 52 +++++++- doc/sync/ftfw/conntrackd.conf | 52 +++++++- doc/sync/notrack/conntrackd.conf | 52 +++++++- include/Makefile.am | 2 +- include/channel.h | 9 ++ include/conntrackd.h | 1 + include/udp.h | 58 +++++++++ src/Makefile.am | 4 +- src/channel.c | 2 + src/channel_udp.c | 123 ++++++++++++++++++ src/read_config_lex.l | 10 +- src/read_config_yy.y | 170 ++++++++++++++++++++++--- src/udp.c | 261 +++++++++++++++++++++++++++++++++++++++ 13 files changed, 764 insertions(+), 32 deletions(-) create mode 100644 include/udp.h create mode 100644 src/channel_udp.c create mode 100644 src/udp.c (limited to 'src') diff --git a/doc/sync/alarm/conntrackd.conf b/doc/sync/alarm/conntrackd.conf index cefda00..9197db3 100644 --- a/doc/sync/alarm/conntrackd.conf +++ b/doc/sync/alarm/conntrackd.conf @@ -88,7 +88,7 @@ Sync { # of the sender buffer. The default size is usually around # ~100 KBytes which is fairly small for busy firewalls. # - McastSndSocketBuffer 1249280 + SndSocketBuffer 1249280 # The multicast receiver uses a buffer to enqueue the packets # that the socket is pending to handle. The default size of this @@ -100,7 +100,7 @@ Sync { # the receiver buffer. The default size is usually around # ~100 KBytes which is fairly small for busy firewalls. # - McastRcvSocketBuffer 1249280 + RcvSocketBuffer 1249280 # # Enable/Disable message checksumming. This is a good @@ -124,10 +124,54 @@ Sync { # Group 3781 # IPv4_interface 192.168.100.101 # Interface eth3 - # # McastSndSocketBuffer 1249280 - # # McastRcvSocketBuffer 1249280 + # # SndSocketBuffer 1249280 + # # RcvSocketBuffer 1249280 # Checksum on # } + + # + # You can use Unicast UDP instead of Multicast to propagate events. + # Note that you cannot use unicast UDP and Multicast at the same + # time, you can only select one. + # + # UDP { + # + # UDP address that this firewall uses to listen to events. + # + # IPv4_address 192.168.2.100 + + # + # Destination UDP address that receives events, ie. the other + # firewall's dedicated link address. + # + # IPv4_Destination_Address 192.168.2.101 + + # + # UDP port used + # + # Port 3780 + + # + # The name of the interface that you are going to use to + # send the synchronization messages. + # + # Interface eth2 + + # + # The sender socket buffer size + # + # SndSocketBuffer 1249280 + + # + # The receiver socket buffer size + # + # RcvSocketBuffer 1249280 + + # + # Enable/Disable message checksumming. + # + # Checksum on + # } } # diff --git a/doc/sync/ftfw/conntrackd.conf b/doc/sync/ftfw/conntrackd.conf index d7e4123..be78850 100644 --- a/doc/sync/ftfw/conntrackd.conf +++ b/doc/sync/ftfw/conntrackd.conf @@ -97,7 +97,7 @@ Sync { # of the sender buffer. The default size is usually around # ~100 KBytes which is fairly small for busy firewalls. # - McastSndSocketBuffer 1249280 + SndSocketBuffer 1249280 # The multicast receiver uses a buffer to enqueue the packets # that the socket is pending to handle. The default size of this @@ -109,7 +109,7 @@ Sync { # the receiver buffer. The default size is usually around # ~100 KBytes which is fairly small for busy firewalls. # - McastRcvSocketBuffer 1249280 + RcvSocketBuffer 1249280 # # Enable/Disable message checksumming. This is a good @@ -133,10 +133,54 @@ Sync { # Group 3781 # IPv4_interface 192.168.100.101 # Interface eth3 - # # McastSndSocketBuffer 1249280 - # # McastRcvSocketBuffer 1249280 + # # SndSocketBuffer 1249280 + # # RcvSocketBuffer 1249280 # Checksum on # } + + # + # You can use Unicast UDP instead of Multicast to propagate events. + # Note that you cannot use unicast UDP and Multicast at the same + # time, you can only select one. + # + # UDP { + # + # UDP address that this firewall uses to listen to events. + # + # IPv4_address 192.168.2.100 + + # + # Destination UDP address that receives events, ie. the other + # firewall's dedicated link address. + # + # IPv4_Destination_Address 192.168.2.101 + + # + # UDP port used + # + # Port 3780 + + # + # The name of the interface that you are going to use to + # send the synchronization messages. + # + # Interface eth2 + + # + # The sender socket buffer size + # + # SndSocketBuffer 1249280 + + # + # The receiver socket buffer size + # + # RcvSocketBuffer 1249280 + + # + # Enable/Disable message checksumming. + # + # Checksum on + # } } # diff --git a/doc/sync/notrack/conntrackd.conf b/doc/sync/notrack/conntrackd.conf index 884d536..173eab5 100644 --- a/doc/sync/notrack/conntrackd.conf +++ b/doc/sync/notrack/conntrackd.conf @@ -76,7 +76,7 @@ Sync { # Note: This protocol is best effort, it is really recommended # to increase the buffer size. # - McastSndSocketBuffer 1249280 + SndSocketBuffer 1249280 # The multicast receiver uses a buffer to enqueue the packets # that the socket is pending to handle. The default size of this @@ -90,7 +90,7 @@ Sync { # Note: This protocol is best effort, it is really recommended # to increase the buffer size. # - McastRcvSocketBuffer 1249280 + RcvSocketBuffer 1249280 # # Enable/Disable message checksumming. This is a good @@ -114,10 +114,54 @@ Sync { # Group 3781 # IPv4_interface 192.168.100.101 # Interface eth3 - # # McastSndSocketBuffer 1249280 - # # McastRcvSocketBuffer 1249280 + # # SndSocketBuffer 1249280 + # # RcvSocketBuffer 1249280 # Checksum on # } + + # + # You can use Unicast UDP instead of Multicast to propagate events. + # Note that you cannot use unicast UDP and Multicast at the same + # time, you can only select one. + # + # UDP { + # + # UDP address that this firewall uses to listen to events. + # + # IPv4_address 192.168.2.100 + + # + # Destination UDP address that receives events, ie. the other + # firewall's dedicated link address. + # + # IPv4_Destination_Address 192.168.2.101 + + # + # UDP port used + # + # Port 3780 + + # + # The name of the interface that you are going to use to + # send the synchronization messages. + # + # Interface eth2 + + # + # The sender socket buffer size + # + # SndSocketBuffer 1249280 + + # + # The receiver socket buffer size + # + # RcvSocketBuffer 1249280 + + # + # Enable/Disable message checksumming. + # + # Checksum on + # } } # diff --git a/include/Makefile.am b/include/Makefile.am index 0265620..f02ce89 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -1,6 +1,6 @@ noinst_HEADERS = alarm.h jhash.h cache.h linux_list.h linux_rbtree.h \ - sync.h conntrackd.h local.h \ + sync.h conntrackd.h local.h udp.h \ debug.h log.h hash.h mcast.h conntrack.h \ network.h filter.h queue.h vector.h cidr.h \ traffic_stats.h netlink.h fds.h event.h bitops.h channel.h diff --git a/include/channel.h b/include/channel.h index ac1a93c..42534e0 100644 --- a/include/channel.h +++ b/include/channel.h @@ -2,12 +2,15 @@ #define _CHANNEL_H_ #include "mcast.h" +#include "udp.h" struct channel; struct nethdr; enum { + CHANNEL_NONE, CHANNEL_MCAST, + CHANNEL_UDP, CHANNEL_MAX, }; @@ -16,12 +19,18 @@ struct mcast_channel { struct mcast_sock *server; }; +struct udp_channel { + struct udp_sock *client; + struct udp_sock *server; +}; + #define CHANNEL_F_DEFAULT (1 << 0) #define CHANNEL_F_BUFFERED (1 << 1) #define CHANNEL_F_MAX (1 << 2) union channel_type_conf { struct mcast_conf mcast; + struct udp_conf udp; }; struct channel_conf { diff --git a/include/conntrackd.h b/include/conntrackd.h index cfb1ac5..f30a094 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -74,6 +74,7 @@ struct ct_conf { int hashsize; /* hashtable size */ int channel_num; int channel_default; + int channel_type_global; struct channel_conf channel[MULTICHANNEL_MAX]; struct local_conf local; /* unix socket facilities */ int nice; diff --git a/include/udp.h b/include/udp.h new file mode 100644 index 0000000..02b8af1 --- /dev/null +++ b/include/udp.h @@ -0,0 +1,58 @@ +#ifndef _UDP_H_ +#define _UDP_H_ + +#include +#include + +struct udp_conf { + int ipproto; + int reuseaddr; + int checksum; + unsigned short port; + union { + struct in_addr inet_addr; + struct in6_addr inet_addr6; + } server; + union { + struct in_addr inet_addr; + struct in6_addr inet_addr6; + } client; + int sndbuf; + int rcvbuf; +}; + +struct udp_stats { + uint64_t bytes; + uint64_t messages; + uint64_t error; +}; + +struct udp_sock { + int fd; + union { + struct sockaddr_in ipv4; + struct sockaddr_in6 ipv6; + } addr; + socklen_t sockaddr_len; + struct udp_stats stats; +}; + +struct udp_sock *udp_server_create(struct udp_conf *conf); +void udp_server_destroy(struct udp_sock *m); + +struct udp_sock *udp_client_create(struct udp_conf *conf); +void udp_client_destroy(struct udp_sock *m); + +ssize_t udp_send(struct udp_sock *m, const void *data, int size); +ssize_t udp_recv(struct udp_sock *m, void *data, int size); + +int udp_get_fd(struct udp_sock *m); + +int udp_snprintf_stats(char *buf, size_t buflen, char *ifname, + struct udp_stats *s, struct udp_stats *r); + +int udp_snprintf_stats2(char *buf, size_t buflen, const char *ifname, + const char *status, int active, + struct udp_stats *s, struct udp_stats *r); + +#endif diff --git a/src/Makefile.am b/src/Makefile.am index 54cfda4..667040c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -11,7 +11,7 @@ conntrack_LDADD = ../extensions/libct_proto_tcp.la ../extensions/libct_proto_udp conntrack_LDFLAGS = $(all_libraries) @LIBNETFILTER_CONNTRACK_LIBS@ conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c rbtree.c \ - local.c log.c mcast.c netlink.c vector.c \ + local.c log.c mcast.c udp.c netlink.c vector.c \ filter.c fds.c event.c \ cache.c cache_iterators.c \ cache_timer.c cache_wt.c \ @@ -19,7 +19,7 @@ conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c rbtree.c \ traffic_stats.c stats-mode.c \ network.c cidr.c \ build.c parse.c \ - channel.c multichannel.c channel_mcast.c \ + channel.c multichannel.c channel_mcast.c channel_udp.c \ read_config_yy.y read_config_lex.l # yacc and lex generate dirty code diff --git a/src/channel.c b/src/channel.c index 733fd03..255026a 100644 --- a/src/channel.c +++ b/src/channel.c @@ -19,10 +19,12 @@ static struct channel_ops *ops[CHANNEL_MAX]; extern struct channel_ops channel_mcast; +extern struct channel_ops channel_udp; void channel_init(void) { ops[CHANNEL_MCAST] = &channel_mcast; + ops[CHANNEL_UDP] = &channel_udp; } #define HEADERSIZ 28 /* IP header (20 bytes) + UDP header 8 (bytes) */ diff --git a/src/channel_udp.c b/src/channel_udp.c new file mode 100644 index 0000000..1c15b47 --- /dev/null +++ b/src/channel_udp.c @@ -0,0 +1,123 @@ +/* + * (C) 2009 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 +#include + +#include "channel.h" +#include "udp.h" + +static void +*channel_udp_open(void *conf) +{ + struct udp_channel *m; + struct udp_conf *c = conf; + + m = calloc(sizeof(struct udp_channel), 1); + if (m == NULL) + return NULL; + + m->client = udp_client_create(c); + if (m->client == NULL) { + free(m); + return NULL; + } + + m->server = udp_server_create(c); + if (m->server == NULL) { + udp_client_destroy(m->client); + free(m); + return NULL; + } + return m; +} + +static int +channel_udp_send(void *channel, const void *data, int len) +{ + struct udp_channel *m = channel; + return udp_send(m->client, data, len); +} + +static int +channel_udp_recv(void *channel, char *buf, int size) +{ + struct udp_channel *m = channel; + return udp_recv(m->server, buf, size); +} + +static void +channel_udp_close(void *channel) +{ + struct udp_channel *m = channel; + udp_client_destroy(m->client); + udp_server_destroy(m->server); + free(m); +} + +static int +channel_udp_get_fd(void *channel) +{ + struct udp_channel *m = channel; + return udp_get_fd(m->server); +} + +static void +channel_udp_stats(struct channel *c, int fd) +{ + struct udp_channel *m = c->data; + char ifname[IFNAMSIZ], buf[512]; + int size; + + if_indextoname(c->channel_ifindex, ifname); + size = udp_snprintf_stats(buf, sizeof(buf), ifname, + &m->client->stats, &m->server->stats); + send(fd, buf, size, 0); +} + +static void +channel_udp_stats_extended(struct channel *c, int active, + struct nlif_handle *h, int fd) +{ + struct udp_channel *m = c->data; + char ifname[IFNAMSIZ], buf[512]; + const char *status; + unsigned int flags; + int size; + + if_indextoname(c->channel_ifindex, ifname); + nlif_get_ifflags(h, c->channel_ifindex, &flags); + /* + * IFF_UP shows administrative status + * IFF_RUNNING shows carrier status + */ + if (flags & IFF_UP) { + if (!(flags & IFF_RUNNING)) + status = "NO-CARRIER"; + else + status = "RUNNING"; + } else { + status = "DOWN"; + } + size = udp_snprintf_stats2(buf, sizeof(buf), + ifname, status, active, + &m->client->stats, + &m->server->stats); + send(fd, buf, size, 0); +} + +struct channel_ops channel_udp = { + .open = channel_udp_open, + .close = channel_udp_close, + .send = channel_udp_send, + .recv = channel_udp_recv, + .get_fd = channel_udp_get_fd, + .stats = channel_udp_stats, + .stats_extended = channel_udp_stats_extended, +}; diff --git a/src/read_config_lex.l b/src/read_config_lex.l index d75e299..44ccf0b 100644 --- a/src/read_config_lex.l +++ b/src/read_config_lex.l @@ -58,11 +58,14 @@ notrack [N|n][O|o][T|t][R|r][A|a][C|c][K|k] "UNIX" { return T_UNIX; } "IPv4_address" { return T_IPV4_ADDR; } "IPv6_address" { return T_IPV6_ADDR; } +"IPv4_Destination_Address" { return T_IPV4_DEST_ADDR; } +"IPv6_Destination_Address" { return T_IPV6_DEST_ADDR; } "IPv4_interface" { return T_IPV4_IFACE; } "IPv6_interface" { return T_IPV6_IFACE; } "Interface" { return T_IFACE; } "Port" { return T_PORT; } "Multicast" { return T_MULTICAST; } +"UDP" { return T_UDP; } "HashSize" { return T_HASHSIZE; } "RefreshTime" { return T_REFRESH; } "CacheTimeout" { return T_EXPIRE; } @@ -75,6 +78,7 @@ notrack [N|n][O|o][T|t][R|r][A|a][C|c][K|k] "StripNAT" { return T_STRIP_NAT; } "Backlog" { return T_BACKLOG; } "Group" { return T_GROUP; } +"Port" { return T_PORT; } "LogFile" { return T_LOG; } "Syslog" { return T_SYSLOG; } "LockFile" { return T_LOCK; } @@ -109,8 +113,10 @@ notrack [N|n][O|o][T|t][R|r][A|a][C|c][K|k] "LISTEN" { return T_LISTEN; } "LogFileBufferSize" { return T_STAT_BUFFER_SIZE; } "DestroyTimeout" { return T_DESTROY_TIMEOUT; } -"McastSndSocketBuffer" { return T_MCAST_SNDBUFF; } -"McastRcvSocketBuffer" { return T_MCAST_RCVBUFF; } +"McastSndSocketBuffer" { return T_SNDBUFF; /* deprecated */ } +"McastRcvSocketBuffer" { return T_RCVBUFF; /* deprecated */ } +"SndSocketBuffer" { return T_SNDBUFF; } +"RcvSocketBuffer" { return T_RCVBUFF; } "Filter" { return T_FILTER; } "Protocol" { return T_PROTOCOL; } "Address" { return T_ADDRESS; } diff --git a/src/read_config_yy.y b/src/read_config_yy.y index b3a2640..cfcd574 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -38,7 +38,7 @@ struct ct_conf conf; static void __kernel_filter_start(void); static void __kernel_filter_add_state(int value); -static void __max_mcast_dedicated_links_reached(void); +static void __max_dedicated_links_reached(void); %} %union { @@ -58,10 +58,10 @@ static void __max_mcast_dedicated_links_reached(void); %token T_ESTABLISHED T_SYN_SENT T_SYN_RECV T_FIN_WAIT %token T_CLOSE_WAIT T_LAST_ACK T_TIME_WAIT T_CLOSE T_LISTEN %token T_SYSLOG T_WRITE_THROUGH T_STAT_BUFFER_SIZE T_DESTROY_TIMEOUT -%token T_MCAST_RCVBUFF T_MCAST_SNDBUFF T_NOTRACK T_POLL_SECS +%token T_RCVBUFF T_SNDBUFF T_NOTRACK T_POLL_SECS %token T_FILTER T_ADDRESS T_PROTOCOL T_STATE T_ACCEPT T_IGNORE %token T_FROM T_USERSPACE T_KERNELSPACE T_EVENT_ITER_LIMIT T_DEFAULT -%token T_NETLINK_OVERRUN_RESYNC T_NICE +%token T_NETLINK_OVERRUN_RESYNC T_NICE T_IPV4_DEST_ADDR T_IPV6_DEST_ADDR %token T_IP T_PATH_VAL %token T_NUMBER @@ -256,6 +256,13 @@ ignore_traffic_option : T_IPV6_ADDR T_IP multicast_line : T_MULTICAST '{' multicast_options '}' { + if (conf.channel_type_global != CHANNEL_NONE && + conf.channel_type_global != CHANNEL_MCAST) { + fprintf(stderr, "ERROR: Cannot use `Multicast' with other " + "dedicated link protocols!\n"); + exit(EXIT_FAILURE); + } + conf.channel_type_global = CHANNEL_MCAST; conf.channel[conf.channel_num].channel_type = CHANNEL_MCAST; conf.channel[conf.channel_num].channel_flags = CHANNEL_F_BUFFERED; conf.channel_num++; @@ -263,6 +270,13 @@ multicast_line : T_MULTICAST '{' multicast_options '}' multicast_line : T_MULTICAST T_DEFAULT '{' multicast_options '}' { + if (conf.channel_type_global != CHANNEL_NONE && + conf.channel_type_global != CHANNEL_MCAST) { + fprintf(stderr, "ERROR: Cannot use `Multicast' with other " + "dedicated link protocols!\n"); + exit(EXIT_FAILURE); + } + conf.channel_type_global = CHANNEL_MCAST; conf.channel[conf.channel_num].channel_type = CHANNEL_MCAST; conf.channel[conf.channel_num].channel_flags = CHANNEL_F_DEFAULT | CHANNEL_F_BUFFERED; @@ -275,7 +289,7 @@ multicast_options : multicast_option : T_IPV4_ADDR T_IP { - __max_mcast_dedicated_links_reached(); + __max_dedicated_links_reached(); if (!inet_aton($2, &conf.channel[conf.channel_num].u.mcast.in)) { fprintf(stderr, "%s is not a valid IPv4 address\n", $2); @@ -294,7 +308,7 @@ multicast_option : T_IPV4_ADDR T_IP multicast_option : T_IPV6_ADDR T_IP { - __max_mcast_dedicated_links_reached(); + __max_dedicated_links_reached(); #ifdef HAVE_INET_PTON_IPV6 if (inet_pton(AF_INET6, $2, @@ -333,7 +347,7 @@ multicast_option : T_IPV6_ADDR T_IP multicast_option : T_IPV4_IFACE T_IP { - __max_mcast_dedicated_links_reached(); + __max_dedicated_links_reached(); if (!inet_aton($2, &conf.channel[conf.channel_num].u.mcast.ifa)) { fprintf(stderr, "%s is not a valid IPv4 address\n", $2); @@ -359,7 +373,7 @@ multicast_option : T_IFACE T_STRING { unsigned int idx; - __max_mcast_dedicated_links_reached(); + __max_dedicated_links_reached(); strncpy(conf.channel[conf.channel_num].channel_ifname, $2, IFNAMSIZ); strncpy(conf.channel[conf.channel_num].u.mcast.iface, $2, IFNAMSIZ); @@ -385,34 +399,159 @@ multicast_option : T_BACKLOG T_NUMBER multicast_option : T_GROUP T_NUMBER { - __max_mcast_dedicated_links_reached(); + __max_dedicated_links_reached(); conf.channel[conf.channel_num].u.mcast.port = $2; }; -multicast_option: T_MCAST_SNDBUFF T_NUMBER +multicast_option: T_SNDBUFF T_NUMBER { - __max_mcast_dedicated_links_reached(); + __max_dedicated_links_reached(); conf.channel[conf.channel_num].u.mcast.sndbuf = $2; }; -multicast_option: T_MCAST_RCVBUFF T_NUMBER +multicast_option: T_RCVBUFF T_NUMBER { - __max_mcast_dedicated_links_reached(); + __max_dedicated_links_reached(); conf.channel[conf.channel_num].u.mcast.rcvbuf = $2; }; multicast_option: T_CHECKSUM T_ON { - __max_mcast_dedicated_links_reached(); + __max_dedicated_links_reached(); conf.channel[conf.channel_num].u.mcast.checksum = 0; }; multicast_option: T_CHECKSUM T_OFF { - __max_mcast_dedicated_links_reached(); + __max_dedicated_links_reached(); conf.channel[conf.channel_num].u.mcast.checksum = 1; }; +udp_line : T_UDP '{' udp_options '}' +{ + if (conf.channel_type_global != CHANNEL_NONE && + conf.channel_type_global != CHANNEL_UDP) { + fprintf(stderr, "ERROR: Cannot use `UDP' with other " + "dedicated link protocols!\n"); + exit(EXIT_FAILURE); + } + conf.channel_type_global = CHANNEL_UDP; + conf.channel[conf.channel_num].channel_type = CHANNEL_UDP; + conf.channel[conf.channel_num].channel_flags = CHANNEL_F_BUFFERED; + conf.channel_num++; +}; + +udp_line : T_UDP T_DEFAULT '{' udp_options '}' +{ + if (conf.channel_type_global != CHANNEL_NONE && + conf.channel_type_global != CHANNEL_UDP) { + fprintf(stderr, "ERROR: Cannot use `UDP' with other " + "dedicated link protocols!\n"); + exit(EXIT_FAILURE); + } + conf.channel_type_global = CHANNEL_UDP; + conf.channel[conf.channel_num].channel_type = CHANNEL_UDP; + conf.channel[conf.channel_num].channel_flags = CHANNEL_F_DEFAULT | + CHANNEL_F_BUFFERED; + conf.channel_default = conf.channel_num; + conf.channel_num++; +}; + +udp_options : + | udp_options udp_option; + +udp_option : T_IPV4_ADDR T_IP +{ + __max_dedicated_links_reached(); + + if (!inet_aton($2, &conf.channel[conf.channel_num].u.udp.server)) { + fprintf(stderr, "%s is not a valid IPv4 address\n", $2); + break; + } + conf.channel[conf.channel_num].u.udp.ipproto = AF_INET; +}; + +udp_option : T_IPV6_ADDR T_IP +{ + __max_dedicated_links_reached(); + +#ifdef HAVE_INET_PTON_IPV6 + if (inet_pton(AF_INET6, $2, + &conf.channel[conf.channel_num].u.udp.server) <= 0) { + fprintf(stderr, "%s is not a valid IPv6 address\n", $2); + break; + } +#else + fprintf(stderr, "Cannot find inet_pton(), IPv6 unsupported!"); + break; +#endif + conf.channel[conf.channel_num].u.udp.ipproto = AF_INET6; +}; + +udp_option : T_IPV4_DEST_ADDR T_IP +{ + __max_dedicated_links_reached(); + + if (!inet_aton($2, &conf.channel[conf.channel_num].u.udp.client)) { + fprintf(stderr, "%s is not a valid IPv4 address\n", $2); + break; + } + conf.channel[conf.channel_num].u.udp.ipproto = AF_INET; +}; + +udp_option : T_IPV6_DEST_ADDR T_IP +{ + __max_dedicated_links_reached(); + +#ifdef HAVE_INET_PTON_IPV6 + if (inet_pton(AF_INET6, $2, + &conf.channel[conf.channel_num].u.udp.client) <= 0) { + fprintf(stderr, "%s is not a valid IPv6 address\n", $2); + break; + } +#else + fprintf(stderr, "Cannot find inet_pton(), IPv6 unsupported!"); + break; +#endif + conf.channel[conf.channel_num].u.udp.ipproto = AF_INET6; +}; + +udp_option : T_IFACE T_STRING +{ + __max_dedicated_links_reached(); + strncpy(conf.channel[conf.channel_num].channel_ifname, $2, IFNAMSIZ); +}; + +udp_option : T_PORT T_NUMBER +{ + __max_dedicated_links_reached(); + conf.channel[conf.channel_num].u.udp.port = $2; +}; + +udp_option: T_SNDBUFF T_NUMBER +{ + __max_dedicated_links_reached(); + conf.channel[conf.channel_num].u.udp.sndbuf = $2; +}; + +udp_option: T_RCVBUFF T_NUMBER +{ + __max_dedicated_links_reached(); + conf.channel[conf.channel_num].u.udp.rcvbuf = $2; +}; + +udp_option: T_CHECKSUM T_ON +{ + __max_dedicated_links_reached(); + conf.channel[conf.channel_num].u.udp.checksum = 0; +}; + +udp_option: T_CHECKSUM T_OFF +{ + __max_dedicated_links_reached(); + conf.channel[conf.channel_num].u.udp.checksum = 1; +}; + hashsize : T_HASHSIZE T_NUMBER { conf.hashsize = $2; @@ -493,6 +632,7 @@ sync_line: refreshtime | purge | checksum | multicast_line + | udp_line | relax_transitions | delay_destroy_msgs | sync_mode_alarm @@ -1133,7 +1273,7 @@ static void __kernel_filter_add_state(int value) &filter_proto); } -static void __max_mcast_dedicated_links_reached(void) +static void __max_dedicated_links_reached(void) { if (conf.channel_num >= MULTICHANNEL_MAX) { fprintf(stderr, "ERROR: too many dedicated links in " diff --git a/src/udp.c b/src/udp.c new file mode 100644 index 0000000..bad8db8 --- /dev/null +++ b/src/udp.c @@ -0,0 +1,261 @@ +/* + * (C) 2009 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 "udp.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct udp_sock *udp_server_create(struct udp_conf *conf) +{ + int yes = 1; + struct udp_sock *m; + socklen_t socklen = sizeof(int); + + m = calloc(sizeof(struct udp_sock), 1); + if (m == NULL) + return NULL; + + switch(conf->ipproto) { + case AF_INET: + m->addr.ipv4.sin_family = AF_INET; + m->addr.ipv4.sin_port = htons(conf->port); + m->addr.ipv4.sin_addr.s_addr = conf->server.inet_addr.s_addr; + m->sockaddr_len = sizeof(struct sockaddr_in); + break; + + case AF_INET6: + m->addr.ipv6.sin6_family = AF_INET6; + m->addr.ipv6.sin6_port = htons(conf->port); + m->addr.ipv6.sin6_addr = conf->server.inet_addr6; + m->sockaddr_len = sizeof(struct sockaddr_in6); + break; + } + + m->fd = socket(conf->ipproto, SOCK_DGRAM, 0); + if (m->fd == -1) { + free(m); + return NULL; + } + + if (setsockopt(m->fd, SOL_SOCKET, SO_REUSEADDR, &yes, + sizeof(int)) == -1) { + close(m->fd); + free(m); + return NULL; + } + +#ifndef SO_RCVBUFFORCE +#define SO_RCVBUFFORCE 33 +#endif + + if (conf->rcvbuf && + setsockopt(m->fd, SOL_SOCKET, SO_RCVBUFFORCE, &conf->rcvbuf, + sizeof(int)) == -1) { + /* not supported in linux kernel < 2.6.14 */ + if (errno != ENOPROTOOPT) { + close(m->fd); + free(m); + return NULL; + } + } + + getsockopt(m->fd, SOL_SOCKET, SO_RCVBUF, &conf->rcvbuf, &socklen); + + if (bind(m->fd, (struct sockaddr *) &m->addr, m->sockaddr_len) == -1) { + close(m->fd); + free(m); + return NULL; + } + + return m; +} + +void udp_server_destroy(struct udp_sock *m) +{ + close(m->fd); + free(m); +} + +struct udp_sock *udp_client_create(struct udp_conf *conf) +{ + int ret = 0; + struct udp_sock *m; + socklen_t socklen = sizeof(int); + + m = calloc(sizeof(struct udp_sock), 1); + if (m == NULL) + return NULL; + + m->fd = socket(conf->ipproto, SOCK_DGRAM, 0); + if (m->fd == -1) { + free(m); + return NULL; + } + + if (setsockopt(m->fd, SOL_SOCKET, SO_NO_CHECK, &conf->checksum, + sizeof(int)) == -1) { + close(m->fd); + free(m); + return NULL; + } + +#ifndef SO_SNDBUFFORCE +#define SO_SNDBUFFORCE 32 +#endif + + if (conf->sndbuf && + setsockopt(m->fd, SOL_SOCKET, SO_SNDBUFFORCE, &conf->sndbuf, + sizeof(int)) == -1) { + /* not supported in linux kernel < 2.6.14 */ + if (errno != ENOPROTOOPT) { + close(m->fd); + free(m); + return NULL; + } + } + + getsockopt(m->fd, SOL_SOCKET, SO_SNDBUF, &conf->sndbuf, &socklen); + + switch(conf->ipproto) { + case AF_INET: + m->addr.ipv4.sin_family = AF_INET; + m->addr.ipv4.sin_port = htons(conf->port); + m->addr.ipv4.sin_addr = conf->client.inet_addr; + m->sockaddr_len = sizeof(struct sockaddr_in); + break; + case AF_INET6: + m->addr.ipv6.sin6_family = AF_INET6; + m->addr.ipv6.sin6_port = htons(conf->port); + memcpy(&m->addr.ipv6.sin6_addr, &conf->client.inet_addr6, + sizeof(struct in6_addr)); + m->sockaddr_len = sizeof(struct sockaddr_in6); + break; + default: + ret = -1; + break; + } + + if (ret == -1) { + close(m->fd); + free(m); + m = NULL; + } + + return m; +} + +void udp_client_destroy(struct udp_sock *m) +{ + close(m->fd); + free(m); +} + +ssize_t udp_send(struct udp_sock *m, const void *data, int size) +{ + ssize_t ret; + + ret = sendto(m->fd, + data, + size, + 0, + (struct sockaddr *) &m->addr, + m->sockaddr_len); + if (ret == -1) { + m->stats.error++; + return ret; + } + + m->stats.bytes += ret; + m->stats.messages++; + + return ret; +} + +ssize_t udp_recv(struct udp_sock *m, void *data, int size) +{ + ssize_t ret; + socklen_t sin_size = sizeof(struct sockaddr_in); + + ret = recvfrom(m->fd, + data, + size, + 0, + (struct sockaddr *)&m->addr, + &sin_size); + if (ret == -1) { + m->stats.error++; + return ret; + } + + m->stats.bytes += ret; + m->stats.messages++; + + return ret; +} + +int udp_get_fd(struct udp_sock *m) +{ + return m->fd; +} + +int +udp_snprintf_stats(char *buf, size_t buflen, char *ifname, + struct udp_stats *s, struct udp_stats *r) +{ + size_t size; + + size = snprintf(buf, buflen, "UDP traffic (active device=%s):\n" + "%20llu Bytes sent " + "%20llu Bytes recv\n" + "%20llu Pckts sent " + "%20llu Pckts recv\n" + "%20llu Error send " + "%20llu Error recv\n\n", + ifname, + (unsigned long long)s->bytes, + (unsigned long long)r->bytes, + (unsigned long long)s->messages, + (unsigned long long)r->messages, + (unsigned long long)s->error, + (unsigned long long)r->error); + return size; +} + +int +udp_snprintf_stats2(char *buf, size_t buflen, const char *ifname, + const char *status, int active, + struct udp_stats *s, struct udp_stats *r) +{ + size_t size; + + size = snprintf(buf, buflen, + "UDP traffic device=%s status=%s role=%s:\n" + "%20llu Bytes sent " + "%20llu Bytes recv\n" + "%20llu Pckts sent " + "%20llu Pckts recv\n" + "%20llu Error send " + "%20llu Error recv\n\n", + ifname, status, active ? "ACTIVE" : "BACKUP", + (unsigned long long)s->bytes, + (unsigned long long)r->bytes, + (unsigned long long)s->messages, + (unsigned long long)r->messages, + (unsigned long long)s->error, + (unsigned long long)r->error); + return size; +} -- cgit v1.2.3 From 5dda1cf738b529d25b22344f9cd1851c8bdab713 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 13 Mar 2009 21:20:08 +0100 Subject: sync-mode: fix wrong output stats refering lost/malformed packets This patch fixes a misleading output that shows the number of lost and malformed packets. Instead, those numbers show the number of the number of lost and malformed messages. Signed-off-by: Pablo Neira Ayuso --- src/sync-mode.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/sync-mode.c b/src/sync-mode.c index 22609df..04b2171 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -347,9 +347,9 @@ static void dump_stats_sync(int fd) char buf[512]; int size; - size = sprintf(buf, "multicast sequence tracking:\n" - "%20llu Pckts mfrm " - "%20llu Pckts lost\n\n", + size = sprintf(buf, "message sequence tracking:\n" + "%20llu Msgs mfrm " + "%20llu Msgs lost\n\n", (unsigned long long)STATE_SYNC(error).msg_rcv_malformed, (unsigned long long)STATE_SYNC(error).msg_rcv_lost); -- cgit v1.2.3 From e36d5e5750801f764a1a899891d4da70934074e7 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 13 Mar 2009 21:40:44 +0100 Subject: sync-mode: save one tab inside switch, cleanup This patch saves one tab in the code. Signed-off-by: Pablo Neira Ayuso --- src/sync-mode.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/sync-mode.c b/src/sync-mode.c index 04b2171..8fb933f 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -57,20 +57,20 @@ do_channel_handler_step(int if_idx, struct nethdr *net, size_t remain) } switch (STATE_SYNC(sync)->recv(net)) { - case MSG_DATA: - mcast_change_current_link(if_idx); - break; - case MSG_DROP: - return; - case MSG_CTL: - mcast_change_current_link(if_idx); - return; - case MSG_BAD: - STATE_SYNC(error).msg_rcv_malformed++; - STATE_SYNC(error).msg_rcv_bad_header++; - return; - default: - break; + case MSG_DATA: + mcast_change_current_link(if_idx); + break; + case MSG_CTL: + mcast_change_current_link(if_idx); + return; + case MSG_BAD: + STATE_SYNC(error).msg_rcv_malformed++; + STATE_SYNC(error).msg_rcv_bad_header++; + return; + case MSG_DROP: + return; + default: + break; } if (net->type > NET_T_STATE_MAX) { -- cgit v1.2.3 From 7d02950e06511a83f80deee96cc79428ba83dd7f Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 17 Mar 2009 16:34:53 +0100 Subject: sync-mode: cleanup reminiscent of multicast dependency This patch is a cleanup, it removes a couple of reminiscent references to multicast (as now conntrackd is independent of the protocol used to replicate state-changes, currently supports unicast UDP and multicast). Signed-off-by: Pablo Neira Ayuso --- src/sync-mode.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/sync-mode.c b/src/sync-mode.c index 8fb933f..bd831aa 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -188,7 +188,7 @@ static void interface_candidate(void) nlif_get_ifflags(STATE_SYNC(interface), idx, &flags); if (flags & (IFF_RUNNING | IFF_UP)) { multichannel_set_current_channel(STATE_SYNC(channel), i); - dlog(LOG_NOTICE, "device `%s' becomes multicast " + dlog(LOG_NOTICE, "device `%s' becomes " "dedicated link", if_indextoname(idx, buf)); return; @@ -301,7 +301,7 @@ static int init_sync(void) init_alarm(&STATE_SYNC(reset_cache_alarm), NULL, do_reset_cache_alarm); - /* initialization of multicast sequence generation */ + /* initialization of message sequence generation */ STATE_SYNC(last_seq_sent) = time(NULL); return 0; -- cgit v1.2.3 From 0d3d11e1bf8b10214f547c2e7b38b4ea9edb6f5f Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 17 Mar 2009 16:36:41 +0100 Subject: mcast: mcast_send() takes a const pointer to buffer This patch removes a compilation warning. The buffer passed to be sent must be const. Signed-off-by: Pablo Neira Ayuso --- include/mcast.h | 2 +- src/mcast.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/include/mcast.h b/include/mcast.h index 68d18e8..30aefc0 100644 --- a/include/mcast.h +++ b/include/mcast.h @@ -48,7 +48,7 @@ void mcast_server_destroy(struct mcast_sock *m); struct mcast_sock *mcast_client_create(struct mcast_conf *conf); void mcast_client_destroy(struct mcast_sock *m); -ssize_t mcast_send(struct mcast_sock *m, void *data, int size); +ssize_t mcast_send(struct mcast_sock *m, const void *data, int size); ssize_t mcast_recv(struct mcast_sock *m, void *data, int size); int mcast_get_fd(struct mcast_sock *m); diff --git a/src/mcast.c b/src/mcast.c index 8eedd07..3dff855 100644 --- a/src/mcast.c +++ b/src/mcast.c @@ -272,7 +272,7 @@ void mcast_client_destroy(struct mcast_sock *m) free(m); } -ssize_t mcast_send(struct mcast_sock *m, void *data, int size) +ssize_t mcast_send(struct mcast_sock *m, const void *data, int size) { ssize_t ret; -- cgit v1.2.3 From 59f5b36aaee6341cdd03981476d91e167c5b6b31 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 17 Mar 2009 16:43:34 +0100 Subject: sync-mode: change `multicast' by `link' for `-s' option This patch obsoletes `-s multicast' by `-s link' to display the dedicated link statistics, as the current dedicated link protocol use can be unicast UDP or multicast. The term "link" is more generic. Signed-off-by: Pablo Neira Ayuso --- conntrackd.8 | 2 +- include/conntrackd.h | 2 +- src/main.c | 11 +++++++++-- src/sync-mode.c | 2 +- 4 files changed, 12 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/conntrackd.8 b/conntrackd.8 index cd7d084..cf15044 100644 --- a/conntrackd.8 +++ b/conntrackd.8 @@ -44,7 +44,7 @@ option will not flush your internal and external cache). .BI "-k " Kill the daemon .TP -.BI "-s " "[|network|cache|runtime]" +.BI "-s " "[|network|cache|runtime|link|queue]" Dump statistics. If no parameter is passed, it displays the general statistics. If "network" is passed as parameter it displays the networking statistics. If "cache" is passed as parameter, it shows the extended cache statistics. diff --git a/include/conntrackd.h b/include/conntrackd.h index f30a094..3411eb0 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -30,7 +30,7 @@ #define STATS_NETWORK 28 /* extended network stats */ #define STATS_CACHE 29 /* extended cache stats */ #define STATS_RUNTIME 30 /* extended runtime stats */ -#define STATS_MULTICAST 31 /* multicast network stats */ +#define STATS_LINK 31 /* dedicated link stats */ #define STATS_QUEUE 32 /* queue stats */ #define FLUSH_INT_CACHE 33 /* flush internal cache */ #define FLUSH_EXT_CACHE 34 /* flush external cache */ diff --git a/src/main.c b/src/main.c index 26937e1..62ae599 100644 --- a/src/main.c +++ b/src/main.c @@ -43,7 +43,7 @@ static const char usage_client_commands[] = " -i, display content of the internal cache\n" " -e, display the content of the external cache\n" " -k, kill conntrack daemon\n" - " -s [|network|cache|runtime|multicast|queue], dump statistics\n" + " -s [|network|cache|runtime|link|queue], dump statistics\n" " -R, resync with kernel conntrack table\n" " -n, request resync with other node (only FT-FW and NOTRACK modes)\n" " -x, dump cache in XML format (requires -i or -e)\n" @@ -200,7 +200,14 @@ int main(int argc, char *argv[]) i++; } else if (strncmp(argv[i+1], "multicast", strlen(argv[i+1])) == 0) { - action = STATS_MULTICAST; + fprintf(stderr, "WARNING: use `link' " + "instead of `multicast' as " + "parameter.\n"); + action = STATS_LINK; + i++; + } else if (strncmp(argv[i+1], "link", + strlen(argv[i+1])) == 0) { + action = STATS_LINK; i++; } else if (strncmp(argv[i+1], "queue", strlen(argv[i+1])) == 0) { diff --git a/src/sync-mode.c b/src/sync-mode.c index bd831aa..776b4ab 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -478,7 +478,7 @@ static int local_handler_sync(int fd, int type, void *data) cache_stats_extended(STATE_SYNC(internal), fd); cache_stats_extended(STATE_SYNC(external), fd); break; - case STATS_MULTICAST: + case STATS_LINK: multichannel_stats_extended(STATE_SYNC(channel), STATE_SYNC(interface), fd); break; -- cgit v1.2.3 From 28255df51433846bad67cccb69bb285660ef1667 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 19 Mar 2009 01:42:13 +0100 Subject: parse: fix broken destination port address translation This patch fixes a bug in the message parser which leads to treat a destination PAT as a source PAT. Reported-by: Habib Sahnoun Signed-off-by: Pablo Neira Ayuso --- src/parse.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/parse.c b/src/parse.c index 75daac1..76287fd 100644 --- a/src/parse.c +++ b/src/parse.c @@ -114,7 +114,7 @@ static struct parser h[NTA_MAX] = { }, [NTA_DPAT_PORT] = { .parse = parse_u16, - .attr = ATTR_SNAT_PORT, + .attr = ATTR_DNAT_PORT, .size = NTA_SIZE(sizeof(uint16_t)), }, [NTA_NAT_SEQ_ADJ] = { -- cgit v1.2.3 From f7b4b7bd19b16d11491f18891942f6d48c2fcf7e Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 20 Mar 2009 14:05:31 +0100 Subject: udp: fix missing scope_id in the socket creation This patch fixes an EINVAL error returned by bind() when opening an UDP server socket to propagate state-changes over the dedicated link. This patch also includes the change of the example configuration files in case that you want to use UDP over IPv6. Signed-off-by: Pablo Neira Ayuso --- doc/sync/alarm/conntrackd.conf | 8 ++++++++ doc/sync/ftfw/conntrackd.conf | 8 ++++++++ doc/sync/notrack/conntrackd.conf | 8 ++++++++ include/udp.h | 9 +++++++-- src/read_config_yy.y | 13 +++++++++++-- src/udp.c | 5 +++-- 6 files changed, 45 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/doc/sync/alarm/conntrackd.conf b/doc/sync/alarm/conntrackd.conf index 9197db3..8eb22dd 100644 --- a/doc/sync/alarm/conntrackd.conf +++ b/doc/sync/alarm/conntrackd.conf @@ -139,12 +139,20 @@ Sync { # UDP address that this firewall uses to listen to events. # # IPv4_address 192.168.2.100 + # + # or you may want to use an IPv6 address: + # + # IPv6_address fe80::215:58ff:fe28:5a27 # # Destination UDP address that receives events, ie. the other # firewall's dedicated link address. # # IPv4_Destination_Address 192.168.2.101 + # + # or you may want to use an IPv6 address: + # + # IPv6_Destination_Address fe80::2d0:59ff:fe2a:775c # # UDP port used diff --git a/doc/sync/ftfw/conntrackd.conf b/doc/sync/ftfw/conntrackd.conf index be78850..059f7b3 100644 --- a/doc/sync/ftfw/conntrackd.conf +++ b/doc/sync/ftfw/conntrackd.conf @@ -148,12 +148,20 @@ Sync { # UDP address that this firewall uses to listen to events. # # IPv4_address 192.168.2.100 + # + # or you may want to use an IPv6 address: + # + # IPv6_address fe80::215:58ff:fe28:5a27 # # Destination UDP address that receives events, ie. the other # firewall's dedicated link address. # # IPv4_Destination_Address 192.168.2.101 + # + # or you may want to use an IPv6 address: + # + # IPv6_Destination_Address fe80::2d0:59ff:fe2a:775c # # UDP port used diff --git a/doc/sync/notrack/conntrackd.conf b/doc/sync/notrack/conntrackd.conf index 173eab5..96ef547 100644 --- a/doc/sync/notrack/conntrackd.conf +++ b/doc/sync/notrack/conntrackd.conf @@ -129,12 +129,20 @@ Sync { # UDP address that this firewall uses to listen to events. # # IPv4_address 192.168.2.100 + # + # or you may want to use an IPv6 address: + # + # IPv6_address fe80::215:58ff:fe28:5a27 # # Destination UDP address that receives events, ie. the other # firewall's dedicated link address. # # IPv4_Destination_Address 192.168.2.101 + # + # or you may want to use an IPv6 address: + # + # IPv6_Destination_Address fe80::2d0:59ff:fe2a:775c # # UDP port used diff --git a/include/udp.h b/include/udp.h index 02b8af1..6c659b9 100644 --- a/include/udp.h +++ b/include/udp.h @@ -10,8 +10,13 @@ struct udp_conf { int checksum; unsigned short port; union { - struct in_addr inet_addr; - struct in6_addr inet_addr6; + struct { + struct in_addr inet_addr; + } ipv4; + struct { + struct in6_addr inet_addr6; + int scope_id; + } ipv6; } server; union { struct in_addr inet_addr; diff --git a/src/read_config_yy.y b/src/read_config_yy.y index cfcd574..7b62cf3 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -464,7 +464,7 @@ udp_option : T_IPV4_ADDR T_IP { __max_dedicated_links_reached(); - if (!inet_aton($2, &conf.channel[conf.channel_num].u.udp.server)) { + if (!inet_aton($2, &conf.channel[conf.channel_num].u.udp.server.ipv4)) { fprintf(stderr, "%s is not a valid IPv4 address\n", $2); break; } @@ -477,7 +477,7 @@ udp_option : T_IPV6_ADDR T_IP #ifdef HAVE_INET_PTON_IPV6 if (inet_pton(AF_INET6, $2, - &conf.channel[conf.channel_num].u.udp.server) <= 0) { + &conf.channel[conf.channel_num].u.udp.server.ipv6) <= 0) { fprintf(stderr, "%s is not a valid IPv6 address\n", $2); break; } @@ -518,8 +518,17 @@ udp_option : T_IPV6_DEST_ADDR T_IP udp_option : T_IFACE T_STRING { + int idx; + __max_dedicated_links_reached(); strncpy(conf.channel[conf.channel_num].channel_ifname, $2, IFNAMSIZ); + + idx = if_nametoindex($2); + if (!idx) { + fprintf(stderr, "%s is an invalid interface.\n", $2); + break; + } + conf.channel[conf.channel_num].u.udp.server.ipv6.scope_id = idx; }; udp_option : T_PORT T_NUMBER diff --git a/src/udp.c b/src/udp.c index bad8db8..d9943a0 100644 --- a/src/udp.c +++ b/src/udp.c @@ -33,14 +33,15 @@ struct udp_sock *udp_server_create(struct udp_conf *conf) case AF_INET: m->addr.ipv4.sin_family = AF_INET; m->addr.ipv4.sin_port = htons(conf->port); - m->addr.ipv4.sin_addr.s_addr = conf->server.inet_addr.s_addr; + m->addr.ipv4.sin_addr = conf->server.ipv4.inet_addr; m->sockaddr_len = sizeof(struct sockaddr_in); break; case AF_INET6: m->addr.ipv6.sin6_family = AF_INET6; m->addr.ipv6.sin6_port = htons(conf->port); - m->addr.ipv6.sin6_addr = conf->server.inet_addr6; + m->addr.ipv6.sin6_addr = conf->server.ipv6.inet_addr6; + m->addr.ipv6.sin6_scope_id = conf->server.ipv6.scope_id; m->sockaddr_len = sizeof(struct sockaddr_in6); break; } -- cgit v1.2.3 From 16e6a01a6454dc791b7af593390616b4a29724c7 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 20 Mar 2009 16:03:08 +0100 Subject: mcast: remove several unused structure fields This patch removes several structure fields that are unused. Signed-off-by: Pablo Neira Ayuso --- include/mcast.h | 4 ---- src/mcast.c | 17 ----------------- src/read_config_yy.y | 4 +--- 3 files changed, 1 insertion(+), 24 deletions(-) (limited to 'src') diff --git a/include/mcast.h b/include/mcast.h index 30aefc0..38c77f9 100644 --- a/include/mcast.h +++ b/include/mcast.h @@ -18,11 +18,8 @@ struct mcast_conf { struct in_addr interface_addr; unsigned int interface_index6; } ifa; - int mtu; - int interface_idx; int sndbuf; int rcvbuf; - char iface[IFNAMSIZ]; }; struct mcast_stats { @@ -38,7 +35,6 @@ struct mcast_sock { struct sockaddr_in6 ipv6; } addr; socklen_t sockaddr_len; - int interface_idx; struct mcast_stats stats; }; diff --git a/src/mcast.c b/src/mcast.c index 3dff855..600fdc2 100644 --- a/src/mcast.c +++ b/src/mcast.c @@ -46,8 +46,6 @@ struct mcast_sock *mcast_server_create(struct mcast_conf *conf) return NULL; memset(m, 0, sizeof(struct mcast_sock)); - m->interface_idx = conf->interface_idx; - switch(conf->ipproto) { case AF_INET: mreq.ipv4.imr_multiaddr.s_addr = conf->in.inet_addr.s_addr; @@ -78,19 +76,6 @@ struct mcast_sock *mcast_server_create(struct mcast_conf *conf) return NULL; } - if(conf->iface[0]) { - struct ifreq ifr; - - strncpy(ifr.ifr_name, conf->iface, sizeof(ifr.ifr_name)); - - if (ioctl(m->fd, SIOCGIFMTU, &ifr) == -1) { - close(m->fd); - free(m); - return NULL; - } - conf->mtu = ifr.ifr_mtu; - } - if (setsockopt(m->fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) { close(m->fd); @@ -214,8 +199,6 @@ struct mcast_sock *mcast_client_create(struct mcast_conf *conf) return NULL; memset(m, 0, sizeof(struct mcast_sock)); - m->interface_idx = conf->interface_idx; - if ((m->fd = socket(conf->ipproto, SOCK_DGRAM, 0)) == -1) { free(m); return NULL; diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 7b62cf3..4e60d95 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -330,7 +330,7 @@ multicast_option : T_IPV6_ADDR T_IP conf.channel[conf.channel_num].u.mcast.ipproto = AF_INET6; - if (conf.channel[conf.channel_num].u.mcast.iface[0] && + if (conf.channel[conf.channel_num].channel_ifname[0] && !conf.channel[conf.channel_num].u.mcast.ifa.interface_index6) { unsigned int idx; @@ -376,14 +376,12 @@ multicast_option : T_IFACE T_STRING __max_dedicated_links_reached(); strncpy(conf.channel[conf.channel_num].channel_ifname, $2, IFNAMSIZ); - strncpy(conf.channel[conf.channel_num].u.mcast.iface, $2, IFNAMSIZ); idx = if_nametoindex($2); if (!idx) { fprintf(stderr, "%s is an invalid interface.\n", $2); break; } - conf.channel[conf.channel_num].u.mcast.interface_idx = idx; if (conf.channel[conf.channel_num].u.mcast.ipproto == AF_INET6) { conf.channel[conf.channel_num].u.mcast.ifa.interface_index6 = idx; -- cgit v1.2.3 From 899785226af55b1c09b2b4d57345da2e07e5f729 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 20 Mar 2009 17:21:44 +0100 Subject: config: obsolete `ListenTo' clause This patch obsoletes the `ListenTo' clause which is a reminiscent of the intial event filtering code. Signed-off-by: Pablo Neira Ayuso --- include/conntrackd.h | 2 -- src/read_config_yy.y | 26 ++------------------------ 2 files changed, 2 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/include/conntrackd.h b/include/conntrackd.h index 3411eb0..83f4e24 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -86,8 +86,6 @@ struct ct_conf { unsigned int netlink_buffer_size; unsigned int netlink_buffer_size_max_grown; int nl_overrun_resync; - union inet_address *listen_to; - unsigned int listen_to_len; unsigned int flags; int family; /* protocol family */ unsigned int resend_queue_size; /* FTFW protocol */ diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 4e60d95..8ed000f 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -730,30 +730,8 @@ delay_destroy_msgs: T_DELAY listen_to: T_LISTEN_TO T_IP { - union inet_address addr; - -#ifdef HAVE_INET_PTON_IPV6 - if (inet_pton(AF_INET6, $2, &addr.ipv6) <= 0) -#endif - if (inet_aton($2, &addr.ipv4) <= 0) { - fprintf(stderr, "%s is not a valid IP address\n", $2); - exit(EXIT_FAILURE); - } - - if (CONFIG(listen_to_len) == 0 || CONFIG(listen_to_len) % 16) { - CONFIG(listen_to) = realloc(CONFIG(listen_to), - sizeof(union inet_address) * - (CONFIG(listen_to_len) + 16)); - if (CONFIG(listen_to) == NULL) { - fprintf(stderr, "cannot init listen_to array\n"); - exit(EXIT_FAILURE); - } - - memset(CONFIG(listen_to) + - (CONFIG(listen_to_len) * sizeof(union inet_address)), - 0, sizeof(union inet_address) * 16); - - } + fprintf(stderr, "WARNING: The clause `ListenTo' is obsolete, " + "ignoring.\n"); }; state_replication: T_REPLICATE states T_FOR state_proto -- cgit v1.2.3 From 0114456525a8a805d0a53040b7170b7c7d7f7007 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 20 Mar 2009 19:39:38 +0100 Subject: sync-mode: fix broken dedicated-link change in multichannel layer This patch fixes a problem that was introduced while adding the multichannel support. Signed-off-by: Pablo Neira Ayuso --- include/channel.h | 1 + src/multichannel.c | 6 ++++++ src/sync-mode.c | 17 +++++------------ 3 files changed, 12 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/include/channel.h b/include/channel.h index 42534e0..1d3c48c 100644 --- a/include/channel.h +++ b/include/channel.h @@ -100,5 +100,6 @@ void multichannel_stats_extended(struct multichannel *m, int multichannel_get_ifindex(struct multichannel *m, int i); int multichannel_get_current_ifindex(struct multichannel *m); void multichannel_set_current_channel(struct multichannel *m, int i); +void multichannel_change_current_channel(struct multichannel *m, int i); #endif /* _CHANNEL_H_ */ diff --git a/src/multichannel.c b/src/multichannel.c index ab0f04c..de69d5c 100644 --- a/src/multichannel.c +++ b/src/multichannel.c @@ -108,3 +108,9 @@ void multichannel_set_current_channel(struct multichannel *m, int i) { m->current = m->channel[i]; } + +void multichannel_change_current_channel(struct multichannel *m, int i) +{ + if (m->current != m->channel[i]) + m->current = m->channel[i]; +} diff --git a/src/sync-mode.c b/src/sync-mode.c index 776b4ab..298fcd2 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -36,14 +36,7 @@ #include static void -mcast_change_current_link(int if_idx) -{ - if (if_idx != multichannel_get_current_ifindex(STATE_SYNC(channel))) - multichannel_set_current_channel(STATE_SYNC(channel), if_idx); -} - -static void -do_channel_handler_step(int if_idx, struct nethdr *net, size_t remain) +do_channel_handler_step(int i, struct nethdr *net, size_t remain) { char __ct[nfct_maxsize()]; struct nf_conntrack *ct = (struct nf_conntrack *)(void*) __ct; @@ -58,10 +51,10 @@ do_channel_handler_step(int if_idx, struct nethdr *net, size_t remain) switch (STATE_SYNC(sync)->recv(net)) { case MSG_DATA: - mcast_change_current_link(if_idx); + multichannel_change_current_channel(STATE_SYNC(channel), i); break; case MSG_CTL: - mcast_change_current_link(if_idx); + multichannel_change_current_channel(STATE_SYNC(channel), i); return; case MSG_BAD: STATE_SYNC(error).msg_rcv_malformed++; @@ -123,7 +116,7 @@ retry: } /* handler for messages received */ -static void channel_handler(struct channel *m, int if_idx) +static void channel_handler(struct channel *m, int i) { ssize_t numbytes; ssize_t remain; @@ -168,7 +161,7 @@ static void channel_handler(struct channel *m, int if_idx) HDR_NETWORK2HOST(net); - do_channel_handler_step(if_idx, net, remain); + do_channel_handler_step(i, net, remain); ptr += net->len; remain -= net->len; } -- cgit v1.2.3 From 70744136608e3ee38f15c994fc2633cf5e3c9fa2 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 31 Mar 2009 15:31:59 +0200 Subject: conntrack: fix missing bits in `-C' command This patch fixes some missing bits for the `-C' conntrack command like the manpage information, the usage help, the `--counters' synonymous and the commands vs. options checking. Signed-off-by: Pablo Neira Ayuso --- conntrack.8 | 2 ++ src/conntrack.c | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/conntrack.8 b/conntrack.8 index 94f4e41..280af9c 100644 --- a/conntrack.8 +++ b/conntrack.8 @@ -19,6 +19,8 @@ conntrack \- command line interface for netfilter connection tracking .BR "conntrack -E [table] parameters" .br .BR "conntrack -F [table]" +.br +.BR "conntrack -C [table]" .SH DESCRIPTION .B conntrack provides a full featured userspace interface to the netfilter connection tracking system that is intended to replace the old /proc/net/ip_conntrack interface. This tool can be used to search, list, inspect and maintain the connection tracking subsystem of the Linux kernel. diff --git a/src/conntrack.c b/src/conntrack.c index c746ae8..2764d80 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -77,6 +77,7 @@ static struct option original_opts[] = { {"get", 1, 0, 'G'}, {"flush", 1, 0, 'F'}, {"event", 1, 0, 'E'}, + {"counter", 2, 0, 'C'}, {"version", 0, 0, 'V'}, {"help", 0, 0, 'h'}, {"orig-src", 1, 0, 's'}, @@ -141,6 +142,7 @@ static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = /*EXP_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, /*EXP_EVENT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, /*CT_COUNT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*EXP_COUNT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, }; static LIST_HEAD(proto_list); @@ -553,7 +555,8 @@ static const char usage_commands[] = " -I [table] parameters\t\tCreate a conntrack or expectation\n" " -U [table] parameters\t\tUpdate a conntrack\n" " -E [table] [options]\t\tShow events\n" - " -F [table]\t\t\tFlush table\n"; + " -F [table]\t\t\tFlush table\n" + " -C [table]\t\t\tShow counter\n"; static const char usage_tables[] = "Tables: conntrack, expect\n"; -- cgit v1.2.3 From ff1768673f093c2bfc8e271513b20fc4aa4efeb3 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 31 Mar 2009 15:36:36 +0200 Subject: conntrack: add `-S' command to display kernel statistics This patch adds `-S' command to display kernel statistics. Using raw `cat' on /proc and the hexadecimal output is not very handy. This option parses the /proc entry and display the information is a more human friendly way. Signed-off-by: Pablo Neira Ayuso --- conntrack.8 | 5 +++ include/conntrack.h | 5 ++- src/conntrack.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 92 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/conntrack.8 b/conntrack.8 index 280af9c..208f7a2 100644 --- a/conntrack.8 +++ b/conntrack.8 @@ -21,6 +21,8 @@ conntrack \- command line interface for netfilter connection tracking .BR "conntrack -F [table]" .br .BR "conntrack -C [table]" +.br +.BR "conntrack -S " .SH DESCRIPTION .B conntrack provides a full featured userspace interface to the netfilter connection tracking system that is intended to replace the old /proc/net/ip_conntrack interface. This tool can be used to search, list, inspect and maintain the connection tracking subsystem of the Linux kernel. @@ -77,6 +79,9 @@ Flush the whole given table .TP .BI "-C, --count " Show the table counter. +.TP +.BI "-S, --stats " +Show the in-kernel connection tracking system statistics. .SS PARAMETERS .TP .BI "-z, --zero " diff --git a/include/conntrack.h b/include/conntrack.h index 87a262d..e1f8d0a 100644 --- a/include/conntrack.h +++ b/include/conntrack.h @@ -65,8 +65,11 @@ enum action { EXP_COUNT_BIT = 16, EXP_COUNT = (1 << EXP_COUNT_BIT), + + X_STATS_BIT = 17, + X_STATS = (1 << X_STATS_BIT), }; -#define NUMBER_OF_CMD 17 +#define NUMBER_OF_CMD 18 enum options { CT_OPT_ORIG_SRC_BIT = 0, diff --git a/src/conntrack.c b/src/conntrack.c index 2764d80..9c5e69b 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -59,10 +59,10 @@ #include static const char cmdflags[NUMBER_OF_CMD] -= {'L','I','U','D','G','F','E','V','h','L','I','D','G','F','E','C','C'}; += {'L','I','U','D','G','F','E','V','h','L','I','D','G','F','E','C','C','S'}; static const char cmd_need_param[NUMBER_OF_CMD] -= { 2, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, 0, 2, 2, 2, 2}; += { 2, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, 0, 2, 2, 2, 2, 2}; static const char *optflags[NUMBER_OF_OPT] = { "src","dst","reply-src","reply-dst","protonum","timeout","status","zero", @@ -78,6 +78,7 @@ static struct option original_opts[] = { {"flush", 1, 0, 'F'}, {"event", 1, 0, 'E'}, {"counter", 2, 0, 'C'}, + {"stats", 0, 0, 'S'}, {"version", 0, 0, 'V'}, {"help", 0, 0, 'h'}, {"orig-src", 1, 0, 's'}, @@ -143,6 +144,7 @@ static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = /*EXP_EVENT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, /*CT_COUNT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, /*EXP_COUNT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*X_STATS*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, }; static LIST_HEAD(proto_list); @@ -556,7 +558,8 @@ static const char usage_commands[] = " -U [table] parameters\t\tUpdate a conntrack\n" " -E [table] [options]\t\tShow events\n" " -F [table]\t\t\tFlush table\n" - " -C [table]\t\t\tShow counter\n"; + " -C [table]\t\t\tShow counter\n" + " -S\t\t\t\tShow statistics\n"; static const char usage_tables[] = "Tables: conntrack, expect\n"; @@ -872,6 +875,75 @@ static int count_exp_cb(enum nf_conntrack_msg_type type, return NFCT_CB_CONTINUE; } +#ifndef CT_STATS_PROC +#define CT_STATS_PROC "/proc/net/stat/nf_conntrack" +#endif + +/* As of 2.6.29, we have 16 entries, this is enough */ +#ifndef CT_STATS_ENTRIES_MAX +#define CT_STATS_ENTRIES_MAX 64 +#endif + +/* maximum string length currently is 13 characters */ +#ifndef CT_STATS_STRING_MAX +#define CT_STATS_STRING_MAX 64 +#endif + +static int display_proc_conntrack_stats(void) +{ + int ret = 0; + FILE *fd; + char buf[4096], *token, *nl; + char output[CT_STATS_ENTRIES_MAX][CT_STATS_STRING_MAX]; + unsigned int value[CT_STATS_ENTRIES_MAX], i, max; + + fd = fopen(CT_STATS_PROC, "r"); + if (fd == NULL) + return -1; + + if (fgets(buf, sizeof(buf), fd) == NULL) { + ret = -1; + goto out_err; + } + + /* trim off trailing \n */ + nl = strchr(buf, '\n'); + if (nl != NULL) { + *nl = '\0'; + nl = strchr(buf, '\n'); + } + token = strtok(buf, " "); + for (i=0; token != NULL && i Date: Tue, 31 Mar 2009 15:36:39 +0200 Subject: conntrack: remove broken command checking code This patch removes the broken command checking. This is better handled by the option checkings which comes just after this one. This patch also fixes some inconsistencies in the command parameter checking when long names are used. Signed-off-by: Pablo Neira Ayuso --- src/conntrack.c | 28 ++++++---------------------- 1 file changed, 6 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index 9c5e69b..0305408 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -58,12 +58,6 @@ #include #include -static const char cmdflags[NUMBER_OF_CMD] -= {'L','I','U','D','G','F','E','V','h','L','I','D','G','F','E','C','C','S'}; - -static const char cmd_need_param[NUMBER_OF_CMD] -= { 2, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, 0, 2, 2, 2, 2, 2}; - static const char *optflags[NUMBER_OF_OPT] = { "src","dst","reply-src","reply-dst","protonum","timeout","status","zero", "event-mask","tuple-src","tuple-dst","mask-src","mask-dst","nat-range","mark", @@ -71,12 +65,12 @@ static const char *optflags[NUMBER_OF_OPT] = { static struct option original_opts[] = { {"dump", 2, 0, 'L'}, - {"create", 1, 0, 'I'}, - {"delete", 1, 0, 'D'}, - {"update", 1, 0, 'U'}, - {"get", 1, 0, 'G'}, - {"flush", 1, 0, 'F'}, - {"event", 1, 0, 'E'}, + {"create", 2, 0, 'I'}, + {"delete", 2, 0, 'D'}, + {"update", 2, 0, 'U'}, + {"get", 2, 0, 'G'}, + {"flush", 2, 0, 'F'}, + {"event", 2, 0, 'E'}, {"counter", 2, 0, 'C'}, {"stats", 0, 0, 'S'}, {"version", 0, 0, 'V'}, @@ -255,15 +249,6 @@ exit_error(enum exittype status, const char *msg, ...) exit(status); } -static void -generic_cmd_check(int command, int local_options) -{ - if (cmd_need_param[command] == 0 && !local_options) - exit_error(PARAMETER_PROBLEM, - "You need to supply parameters to `-%c'", - cmdflags[command]); -} - static int bit2cmd(int command) { int i; @@ -1212,7 +1197,6 @@ int main(int argc, char *argv[]) family = AF_INET; cmd = bit2cmd(command); - generic_cmd_check(cmd, options); generic_opt_check(options, NUMBER_OF_OPT, commands_v_options[cmd], -- cgit v1.2.3 From 934d6efec6cdaded075b9b2c3de9d245cdb9d686 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 31 Mar 2009 21:49:36 +0200 Subject: config: cleanup error reporting during config file parsing This patch cleans up the error reporting. Signed-off-by: Pablo Neira Ayuso --- src/read_config_yy.y | 254 +++++++++++++++++++++++++++++---------------------- 1 file changed, 143 insertions(+), 111 deletions(-) (limited to 'src') diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 8ed000f..152f33e 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -24,6 +24,7 @@ #include #include #include +#include #include "conntrackd.h" #include "bitops.h" #include "cidr.h" @@ -36,6 +37,13 @@ extern int yylineno; struct ct_conf conf; +enum { + CTD_CFG_ERROR = 0, + CTD_CFG_WARN, +}; + +static void print_err(int err, const char *msg, ...); + static void __kernel_filter_start(void); static void __kernel_filter_add_state(int value); static void __max_dedicated_links_reached(void); @@ -131,15 +139,15 @@ syslog_facility : T_SYSLOG T_STRING else if (!strcmp($2, "local7")) conf.syslog_facility = LOG_LOCAL7; else { - fprintf(stderr, "'%s' is not a known syslog facility, " - "ignoring.\n", $2); + print_err(CTD_CFG_WARN, "'%s' is not a known syslog facility, " + "ignoring", $2); break; } if (conf.stats.syslog_facility != -1 && conf.syslog_facility != conf.stats.syslog_facility) - fprintf(stderr, "WARNING: Conflicting Syslog facility " - "values, defaulting to General.\n"); + print_err(CTD_CFG_WARN, "conflicting Syslog facility " + "values, defaulting to General"); }; lock : T_LOCK T_PATH_VAL @@ -149,8 +157,7 @@ lock : T_LOCK T_PATH_VAL strip_nat: T_STRIP_NAT { - fprintf(stderr, "Notice: StripNAT clause is obsolete. " - "Please, remove it from conntrackd.conf\n"); + print_err(CTD_CFG_WARN, "`StripNAT' clause is obsolete, ignoring"); }; refreshtime : T_REFRESH T_NUMBER @@ -175,8 +182,8 @@ purge: T_PURGE T_NUMBER checksum: T_CHECKSUM T_ON { - fprintf(stderr, "WARNING: The use of `Checksum' outside the " - "`Multicast' clause is ambiguous.\n"); + print_err(CTD_CFG_WARN, "the use of `Checksum' outside the " + "`Multicast' clause is ambiguous"); /* * XXX: The use of Checksum outside of the Multicast clause is broken * if we have more than one dedicated links. @@ -186,8 +193,8 @@ checksum: T_CHECKSUM T_ON checksum: T_CHECKSUM T_OFF { - fprintf(stderr, "WARNING: The use of `Checksum' outside the " - "`Multicast' clause is ambiguous.\n"); + print_err(CTD_CFG_WARN, "the use of `Checksum' outside the " + "`Multicast' clause is ambiguous"); /* * XXX: The use of Checksum outside of the Multicast clause is broken * if we have more than one dedicated links. @@ -201,8 +208,8 @@ ignore_traffic : T_IGNORE_TRAFFIC '{' ignore_traffic_options '}' CT_FILTER_ADDRESS, CT_FILTER_NEGATIVE); - fprintf(stderr, "WARNING: The clause `IgnoreTrafficFor' is obsolete. " - "Use `Filter' instead.\n"); + print_err(CTD_CFG_WARN, "the clause `IgnoreTrafficFor' is obsolete. " + "Use `Filter' instead"); }; ignore_traffic_options : @@ -215,16 +222,18 @@ ignore_traffic_option : T_IPV4_ADDR T_IP memset(&ip, 0, sizeof(union inet_address)); if (!inet_aton($2, &ip.ipv4)) { - fprintf(stderr, "%s is not a valid IPv4, ignoring", $2); + print_err(CTD_CFG_WARN, "%s is not a valid IPv4, " + "ignoring", $2); break; } if (!ct_filter_add_ip(STATE(us_filter), &ip, AF_INET)) { if (errno == EEXIST) - fprintf(stderr, "IP %s is repeated " - "in the ignore pool\n", $2); + print_err(CTD_CFG_WARN, "IP %s is repeated " + "in the ignore pool", $2); if (errno == ENOSPC) - fprintf(stderr, "Too many IP in the ignore pool!\n"); + print_err(CTD_CFG_WARN, "too many IP in the " + "ignore pool!"); } }; @@ -236,20 +245,20 @@ ignore_traffic_option : T_IPV6_ADDR T_IP #ifdef HAVE_INET_PTON_IPV6 if (inet_pton(AF_INET6, $2, &ip.ipv6) <= 0) { - fprintf(stderr, "%s is not a valid IPv6, ignoring", $2); + print_err(CTD_CFG_WARN, "%s is not a valid IPv6, ignoring", $2); break; } #else - fprintf(stderr, "Cannot find inet_pton(), IPv6 unsupported!"); - break; + print_err(CTD_CFG_WARN, "cannot find inet_pton(), IPv6 unsupported!"); #endif if (!ct_filter_add_ip(STATE(us_filter), &ip, AF_INET6)) { if (errno == EEXIST) - fprintf(stderr, "IP %s is repeated " - "in the ignore pool\n", $2); + print_err(CTD_CFG_WARN, "IP %s is repeated " + "in the ignore pool", $2); if (errno == ENOSPC) - fprintf(stderr, "Too many IP in the ignore pool!\n"); + print_err(CTD_CFG_WARN, "too many IP in the " + "ignore pool!"); } }; @@ -258,8 +267,8 @@ multicast_line : T_MULTICAST '{' multicast_options '}' { if (conf.channel_type_global != CHANNEL_NONE && conf.channel_type_global != CHANNEL_MCAST) { - fprintf(stderr, "ERROR: Cannot use `Multicast' with other " - "dedicated link protocols!\n"); + print_err(CTD_CFG_ERROR, "cannot use `Multicast' with other " + "dedicated link protocols!"); exit(EXIT_FAILURE); } conf.channel_type_global = CHANNEL_MCAST; @@ -272,8 +281,8 @@ multicast_line : T_MULTICAST T_DEFAULT '{' multicast_options '}' { if (conf.channel_type_global != CHANNEL_NONE && conf.channel_type_global != CHANNEL_MCAST) { - fprintf(stderr, "ERROR: Cannot use `Multicast' with other " - "dedicated link protocols!\n"); + print_err(CTD_CFG_ERROR, "cannot use `Multicast' with other " + "dedicated link protocols!"); exit(EXIT_FAILURE); } conf.channel_type_global = CHANNEL_MCAST; @@ -292,14 +301,14 @@ multicast_option : T_IPV4_ADDR T_IP __max_dedicated_links_reached(); if (!inet_aton($2, &conf.channel[conf.channel_num].u.mcast.in)) { - fprintf(stderr, "%s is not a valid IPv4 address\n", $2); + print_err(CTD_CFG_WARN, "%s is not a valid IPv4 address", $2); break; } if (conf.channel[conf.channel_num].u.mcast.ipproto == AF_INET6) { - fprintf(stderr, "Your multicast address is IPv4 but " - "is binded to an IPv6 interface? Surely " - "this is not what you want\n"); + print_err(CTD_CFG_WARN, "your multicast address is IPv4 but " + "is binded to an IPv6 interface? " + "Surely, this is not what you want"); break; } @@ -313,18 +322,18 @@ multicast_option : T_IPV6_ADDR T_IP #ifdef HAVE_INET_PTON_IPV6 if (inet_pton(AF_INET6, $2, &conf.channel[conf.channel_num].u.mcast.in) <= 0) { - fprintf(stderr, "%s is not a valid IPv6 address\n", $2); + print_err(CTD_CFG_WARN, "%s is not a valid IPv6 address", $2); break; } #else - fprintf(stderr, "Cannot find inet_pton(), IPv6 unsupported!"); + print_err(CTD_CFG_WARN, "cannot find inet_pton(), IPv6 unsupported!"); break; #endif if (conf.channel[conf.channel_num].u.mcast.ipproto == AF_INET) { - fprintf(stderr, "Your multicast address is IPv6 but " - "is binded to an IPv4 interface? Surely " - "this is not what you want\n"); + print_err(CTD_CFG_WARN, "your multicast address is IPv6 but " + "is binded to an IPv4 interface? " + "Surely this is not what you want"); break; } @@ -336,7 +345,8 @@ multicast_option : T_IPV6_ADDR T_IP idx = if_nametoindex($2); if (!idx) { - fprintf(stderr, "%s is an invalid interface.\n", $2); + print_err(CTD_CFG_WARN, + "%s is an invalid interface", $2); break; } @@ -350,14 +360,14 @@ multicast_option : T_IPV4_IFACE T_IP __max_dedicated_links_reached(); if (!inet_aton($2, &conf.channel[conf.channel_num].u.mcast.ifa)) { - fprintf(stderr, "%s is not a valid IPv4 address\n", $2); + print_err(CTD_CFG_WARN, "%s is not a valid IPv4 address", $2); break; } if (conf.channel[conf.channel_num].u.mcast.ipproto == AF_INET6) { - fprintf(stderr, "Your multicast interface is IPv4 but " - "is binded to an IPv6 interface? Surely " - "this is not what you want\n"); + print_err(CTD_CFG_WARN, "your multicast interface is IPv4 but " + "is binded to an IPv6 interface? " + "Surely, this is not what you want"); break; } @@ -366,7 +376,7 @@ multicast_option : T_IPV4_IFACE T_IP multicast_option : T_IPV6_IFACE T_IP { - fprintf(stderr, "IPv6_interface not required for IPv6, ignoring.\n"); + print_err(CTD_CFG_WARN, "`IPv6_interface' not required, ignoring"); } multicast_option : T_IFACE T_STRING @@ -379,7 +389,7 @@ multicast_option : T_IFACE T_STRING idx = if_nametoindex($2); if (!idx) { - fprintf(stderr, "%s is an invalid interface.\n", $2); + print_err(CTD_CFG_WARN, "%s is an invalid interface", $2); break; } @@ -391,8 +401,9 @@ multicast_option : T_IFACE T_STRING multicast_option : T_BACKLOG T_NUMBER { - fprintf(stderr, "Notice: Backlog option inside Multicast clause is " - "obsolete. Please, remove it from conntrackd.conf.\n"); + print_err(CTD_CFG_WARN, "`Backlog' option inside Multicast clause is " + "obsolete. Please, remove it from " + "conntrackd.conf"); }; multicast_option : T_GROUP T_NUMBER @@ -429,8 +440,8 @@ udp_line : T_UDP '{' udp_options '}' { if (conf.channel_type_global != CHANNEL_NONE && conf.channel_type_global != CHANNEL_UDP) { - fprintf(stderr, "ERROR: Cannot use `UDP' with other " - "dedicated link protocols!\n"); + print_err(CTD_CFG_ERROR, "cannot use `UDP' with other " + "dedicated link protocols!"); exit(EXIT_FAILURE); } conf.channel_type_global = CHANNEL_UDP; @@ -443,8 +454,8 @@ udp_line : T_UDP T_DEFAULT '{' udp_options '}' { if (conf.channel_type_global != CHANNEL_NONE && conf.channel_type_global != CHANNEL_UDP) { - fprintf(stderr, "ERROR: Cannot use `UDP' with other " - "dedicated link protocols!\n"); + print_err(CTD_CFG_ERROR, "cannot use `UDP' with other " + "dedicated link protocols!"); exit(EXIT_FAILURE); } conf.channel_type_global = CHANNEL_UDP; @@ -463,7 +474,7 @@ udp_option : T_IPV4_ADDR T_IP __max_dedicated_links_reached(); if (!inet_aton($2, &conf.channel[conf.channel_num].u.udp.server.ipv4)) { - fprintf(stderr, "%s is not a valid IPv4 address\n", $2); + print_err(CTD_CFG_WARN, "%s is not a valid IPv4 address", $2); break; } conf.channel[conf.channel_num].u.udp.ipproto = AF_INET; @@ -476,11 +487,11 @@ udp_option : T_IPV6_ADDR T_IP #ifdef HAVE_INET_PTON_IPV6 if (inet_pton(AF_INET6, $2, &conf.channel[conf.channel_num].u.udp.server.ipv6) <= 0) { - fprintf(stderr, "%s is not a valid IPv6 address\n", $2); + print_err(CTD_CFG_WARN, "%s is not a valid IPv6 address", $2); break; } #else - fprintf(stderr, "Cannot find inet_pton(), IPv6 unsupported!"); + print_err(CTD_CFG_WARN, "cannot find inet_pton(), IPv6 unsupported!"); break; #endif conf.channel[conf.channel_num].u.udp.ipproto = AF_INET6; @@ -491,7 +502,7 @@ udp_option : T_IPV4_DEST_ADDR T_IP __max_dedicated_links_reached(); if (!inet_aton($2, &conf.channel[conf.channel_num].u.udp.client)) { - fprintf(stderr, "%s is not a valid IPv4 address\n", $2); + print_err(CTD_CFG_WARN, "%s is not a valid IPv4 address", $2); break; } conf.channel[conf.channel_num].u.udp.ipproto = AF_INET; @@ -504,11 +515,11 @@ udp_option : T_IPV6_DEST_ADDR T_IP #ifdef HAVE_INET_PTON_IPV6 if (inet_pton(AF_INET6, $2, &conf.channel[conf.channel_num].u.udp.client) <= 0) { - fprintf(stderr, "%s is not a valid IPv6 address\n", $2); + print_err(CTD_CFG_WARN, "%s is not a valid IPv6 address", $2); break; } #else - fprintf(stderr, "Cannot find inet_pton(), IPv6 unsupported!"); + print_err(CTD_CFG_WARN, "cannot find inet_pton(), IPv6 unsupported!"); break; #endif conf.channel[conf.channel_num].u.udp.ipproto = AF_INET6; @@ -523,7 +534,7 @@ udp_option : T_IFACE T_STRING idx = if_nametoindex($2); if (!idx) { - fprintf(stderr, "%s is an invalid interface.\n", $2); + print_err(CTD_CFG_WARN, "%s is an invalid interface", $2); break; } conf.channel[conf.channel_num].u.udp.server.ipv6.scope_id = idx; @@ -591,8 +602,8 @@ ignore_protocol: T_IGNORE_PROTOCOL '{' ignore_proto_list '}' CT_FILTER_L4PROTO, CT_FILTER_NEGATIVE); - fprintf(stderr, "WARNING: The clause `IgnoreProtocol' is obsolete. " - "Use `Filter' instead.\n"); + print_err(CTD_CFG_WARN, "the clause `IgnoreProtocol' is " + "obsolete. Use `Filter' instead"); }; ignore_proto_list: @@ -604,7 +615,7 @@ ignore_proto: T_NUMBER if ($1 < IPPROTO_MAX) ct_filter_add_proto(STATE(us_filter), $1); else - fprintf(stderr, "Protocol number `%d' is freak\n", $1); + print_err(CTD_CFG_WARN, "protocol number `%d' is freak", $1); }; ignore_proto: T_STRING @@ -613,8 +624,8 @@ ignore_proto: T_STRING pent = getprotobyname($1); if (pent == NULL) { - fprintf(stderr, "getprotobyname() cannot find " - "protocol `%s' in /etc/protocols.\n", $1); + print_err(CTD_CFG_WARN, "getprotobyname() cannot find " + "protocol `%s' in /etc/protocols", $1); break; } ct_filter_add_proto(STATE(us_filter), pent->p_proto); @@ -623,8 +634,8 @@ ignore_proto: T_STRING sync: T_SYNC '{' sync_list '}' { if (conf.flags & CTD_STATS_MODE) { - fprintf(stderr, "ERROR: Cannot use both Stats and Sync " - "clauses in conntrackd.conf.\n"); + print_err(CTD_CFG_ERROR, "cannot use both `Stats' and `Sync' " + "clauses in conntrackd.conf"); exit(EXIT_FAILURE); } conf.flags |= CTD_SYNC_MODE; @@ -696,8 +707,8 @@ sync_mode_notrack_line: timeout resend_buffer_size: T_RESEND_BUFFER_SIZE T_NUMBER { - fprintf(stderr, "WARNING: `ResendBufferSize' is deprecated. " - "Use `ResendQueueSize' instead\n"); + print_err(CTD_CFG_WARN, "`ResendBufferSize' is deprecated. " + "Use `ResendQueueSize' instead"); }; resend_queue_size: T_RESEND_QUEUE_SIZE T_NUMBER @@ -712,26 +723,24 @@ window_size: T_WINDOWSIZE T_NUMBER destroy_timeout: T_DESTROY_TIMEOUT T_NUMBER { - fprintf(stderr, "WARNING: `DestroyTimeout' is deprecated. " - "Remove it.\n"); + print_err(CTD_CFG_WARN, "`DestroyTimeout' is deprecated. Remove it"); }; relax_transitions: T_RELAX_TRANSITIONS { - fprintf(stderr, "Notice: RelaxTransitions clause is obsolete. " - "Please, remove it from conntrackd.conf\n"); + print_err(CTD_CFG_WARN, "`RelaxTransitions' clause is obsolete. " + "Please, remove it from conntrackd.conf"); }; delay_destroy_msgs: T_DELAY { - fprintf(stderr, "Notice: DelayDestroyMessages clause is obsolete. " - "Please, remove it from conntrackd.conf\n"); + print_err(CTD_CFG_WARN, "`DelayDestroyMessages' clause is obsolete. " + "Please, remove it from conntrackd.conf"); }; listen_to: T_LISTEN_TO T_IP { - fprintf(stderr, "WARNING: The clause `ListenTo' is obsolete, " - "ignoring.\n"); + print_err(CTD_CFG_WARN, "the clause `ListenTo' is obsolete, ignoring"); }; state_replication: T_REPLICATE states T_FOR state_proto @@ -740,8 +749,8 @@ state_replication: T_REPLICATE states T_FOR state_proto CT_FILTER_STATE, CT_FILTER_POSITIVE); - fprintf(stderr, "WARNING: The clause `Replicate' is obsolete. " - "Use `Filter' instead.\n"); + print_err(CTD_CFG_WARN, "the clause `Replicate' is obsolete. " + "Use `Filter' instead"); }; states: @@ -750,8 +759,8 @@ states: state_proto: T_STRING { if (strncmp($1, "TCP", strlen("TCP")) != 0) { - fprintf(stderr, "Unsupported protocol `%s' in line %d.\n", - $1, yylineno); + print_err(CTD_CFG_WARN, "unsupported protocol `%s' in line %d", + $1, yylineno); } }; state: tcp_state; @@ -911,7 +920,7 @@ poll_secs: T_POLL_SECS T_NUMBER conf.flags |= CTD_POLL; conf.poll_kernel_secs = $2; if (conf.poll_kernel_secs == 0) { - fprintf(stderr, "ERROR: `PollSecs' clause must be > 0\n"); + print_err(CTD_CFG_ERROR, "`PollSecs' clause must be > 0"); exit(EXIT_FAILURE); } }; @@ -965,8 +974,8 @@ filter_protocol_item : T_STRING pent = getprotobyname($1); if (pent == NULL) { - fprintf(stderr, "getprotobyname() cannot find " - "protocol `%s' in /etc/protocols.\n", $1); + print_err(CTD_CFG_WARN, "getprotobyname() cannot find " + "protocol `%s' in /etc/protocols", $1); break; } ct_filter_add_proto(STATE(us_filter), pent->p_proto); @@ -1019,14 +1028,14 @@ filter_address_item : T_IPV4_ADDR T_IP *slash = '\0'; cidr = atoi(slash+1); if (cidr > 32) { - fprintf(stderr, "%s/%d is not a valid network, " - "ignoring\n", $2, cidr); + print_err(CTD_CFG_WARN, "%s/%d is not a valid network, " + "ignoring", $2, cidr); break; } } if (!inet_aton($2, &ip.ipv4)) { - fprintf(stderr, "%s is not a valid IPv4, ignoring", $2); + print_err(CTD_CFG_WARN, "%s is not a valid IPv4, ignoring", $2); break; } @@ -1039,17 +1048,18 @@ filter_address_item : T_IPV4_ADDR T_IP if (!ct_filter_add_netmask(STATE(us_filter), &tmp, AF_INET)) { if (errno == EEXIST) - fprintf(stderr, "Netmask %s is repeated " - "in the ignore pool\n", $2); + print_err(CTD_CFG_WARN, "netmask %s is " + "repeated in the " + "ignore pool", $2); } } else { if (!ct_filter_add_ip(STATE(us_filter), &ip, AF_INET)) { if (errno == EEXIST) - fprintf(stderr, "IP %s is repeated " - "in the ignore pool\n", $2); + print_err(CTD_CFG_WARN, "IP %s is repeated in " + "the ignore pool", $2); if (errno == ENOSPC) - fprintf(stderr, "Too many IP in the " - "ignore pool!\n"); + print_err(CTD_CFG_WARN, "too many IP in the " + "ignore pool!"); } } __kernel_filter_start(); @@ -1077,19 +1087,19 @@ filter_address_item : T_IPV6_ADDR T_IP *slash = '\0'; cidr = atoi(slash+1); if (cidr > 128) { - fprintf(stderr, "%s/%d is not a valid network, " - "ignoring\n", $2, cidr); + print_err(CTD_CFG_WARN, "%s/%d is not a valid network, " + "ignoring", $2, cidr); break; } } #ifdef HAVE_INET_PTON_IPV6 if (inet_pton(AF_INET6, $2, &ip.ipv6) <= 0) { - fprintf(stderr, "%s is not a valid IPv6, ignoring", $2); + print_err(CTD_CFG_WARN, "%s is not a valid IPv6, ignoring", $2); break; } #else - fprintf(stderr, "Cannot find inet_pton(), IPv6 unsupported!"); + print_err(CTD_CFG_WARN, "cannot find inet_pton(), IPv6 unsupported!"); break; #endif if (slash && cidr < 128) { @@ -1099,17 +1109,18 @@ filter_address_item : T_IPV6_ADDR T_IP ipv6_cidr2mask_net(cidr, tmp.mask); if (!ct_filter_add_netmask(STATE(us_filter), &tmp, AF_INET6)) { if (errno == EEXIST) - fprintf(stderr, "Netmask %s is repeated " - "in the ignore pool\n", $2); + print_err(CTD_CFG_WARN, "netmask %s is " + "repeated in the " + "ignore pool", $2); } } else { if (!ct_filter_add_ip(STATE(us_filter), &ip, AF_INET6)) { if (errno == EEXIST) - fprintf(stderr, "IP %s is repeated " - "in the ignore pool\n", $2); + print_err(CTD_CFG_WARN, "IP %s is repeated in " + "the ignore pool", $2); if (errno == ENOSPC) - fprintf(stderr, "Too many IP in the " - "ignore pool!\n"); + print_err(CTD_CFG_WARN, "too many IP in the " + "ignore pool!"); } } }; @@ -1145,8 +1156,8 @@ filter_state_item : states T_FOR state_proto ; stats: T_STATS '{' stats_list '}' { if (conf.flags & CTD_SYNC_MODE) { - fprintf(stderr, "ERROR: Cannot use both Stats and Sync " - "clauses in conntrackd.conf.\n"); + print_err(CTD_CFG_ERROR, "cannot use both `Stats' and `Sync' " + "clauses in conntrackd.conf"); exit(EXIT_FAILURE); } conf.flags |= CTD_STATS_MODE; @@ -1208,20 +1219,20 @@ stat_syslog_facility : T_SYSLOG T_STRING else if (!strcmp($2, "local7")) conf.stats.syslog_facility = LOG_LOCAL7; else { - fprintf(stderr, "'%s' is not a known syslog facility, " - "ignoring.\n", $2); + print_err(CTD_CFG_WARN, "'%s' is not a known syslog facility, " + "ignoring.", $2); break; } if (conf.syslog_facility != -1 && conf.stats.syslog_facility != conf.syslog_facility) - fprintf(stderr, "WARNING: Conflicting Syslog facility " - "values, defaulting to General.\n"); + print_err(CTD_CFG_WARN, "conflicting Syslog facility " + "values, defaulting to General"); }; buffer_size: T_STAT_BUFFER_SIZE T_NUMBER { - fprintf(stderr, "WARNING: LogFileBufferSize is deprecated.\n"); + print_err(CTD_CFG_WARN, "`LogFileBufferSize' is deprecated"); }; %% @@ -1229,17 +1240,38 @@ buffer_size: T_STAT_BUFFER_SIZE T_NUMBER int __attribute__((noreturn)) yyerror(char *msg) { - fprintf(stderr, "Error parsing config file: "); - fprintf(stderr, "line (%d), symbol '%s': %s\n", yylineno, yytext, msg); + print_err(CTD_CFG_ERROR, "parsing config file in " + "line (%d), symbol '%s': %s", + yylineno, yytext, msg); exit(EXIT_FAILURE); } +static void print_err(int type, const char *msg, ...) +{ + va_list args; + + va_start(args, msg); + switch(type) { + case CTD_CFG_ERROR: + fprintf(stderr, "ERROR: "); + break; + case CTD_CFG_WARN: + fprintf(stderr, "WARNING: "); + break; + default: + fprintf(stderr, "?: "); + } + vfprintf(stderr, msg, args); + va_end(args); + fprintf(stderr,"\n"); +} + static void __kernel_filter_start(void) { if (!STATE(filter)) { STATE(filter) = nfct_filter_create(); if (!STATE(filter)) { - fprintf(stderr, "Can't create ignore pool!\n"); + print_err(CTD_CFG_ERROR, "cannot create ignore pool!"); exit(EXIT_FAILURE); } } @@ -1261,9 +1293,9 @@ static void __kernel_filter_add_state(int value) static void __max_dedicated_links_reached(void) { if (conf.channel_num >= MULTICHANNEL_MAX) { - fprintf(stderr, "ERROR: too many dedicated links in " - "the configuration file (Maximum: %d).\n", - MULTICHANNEL_MAX); + print_err(CTD_CFG_ERROR, "too many dedicated links in " + "the configuration file " + "(Maximum: %d)", MULTICHANNEL_MAX); exit(EXIT_FAILURE); } } -- cgit v1.2.3 From d406e609f664a8151f9e372bbb8fd2ec2c724d35 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 11 Apr 2009 16:42:20 +0200 Subject: conntrack: fix coupled-options sanity checkings This patch extends the generic_opt_check() function to add extra information on the possible option combinations. Under some specific situations, like the creation and getting of a conntrack, you may specify the original or the reply tuple but at least one MUST be present. This handling has been always tricky, it still remains but we're more user friendly at least. Signed-off-by: Pablo Neira Ayuso --- extensions/libct_proto_icmp.c | 2 +- extensions/libct_proto_icmpv6.c | 7 ++-- extensions/libct_proto_tcp.c | 52 ++++++++++++++-------------- extensions/libct_proto_udp.c | 52 ++++++++++++++-------------- include/conntrack.h | 8 ++--- src/conntrack.c | 77 +++++++++++++++++++++++++++++++---------- 6 files changed, 119 insertions(+), 79 deletions(-) (limited to 'src') diff --git a/extensions/libct_proto_icmp.c b/extensions/libct_proto_icmp.c index 51366f1..3a346ed 100644 --- a/extensions/libct_proto_icmp.c +++ b/extensions/libct_proto_icmp.c @@ -103,7 +103,7 @@ static void final_check(unsigned int flags, generic_opt_check(flags, ICMP_NUMBER_OF_OPT, icmp_commands_v_options[cmd], - icmp_optflags); + icmp_optflags, NULL, 0, NULL); } static struct ctproto_handler icmp = { diff --git a/extensions/libct_proto_icmpv6.c b/extensions/libct_proto_icmpv6.c index cfc5979..070eb7f 100644 --- a/extensions/libct_proto_icmpv6.c +++ b/extensions/libct_proto_icmpv6.c @@ -103,10 +103,9 @@ static void final_check(unsigned int flags, unsigned int cmd, struct nf_conntrack *ct) { - generic_opt_check(flags, - ICMPV6_NUMBER_OF_OPT, - icmpv6_commands_v_options[cmd], - icmpv6_optflags); + generic_opt_check(flags, ICMPV6_NUMBER_OF_OPT, + icmpv6_commands_v_options[cmd], icmpv6_optflags, + NULL, 0, NULL); } static struct ctproto_handler icmpv6 = { diff --git a/extensions/libct_proto_tcp.c b/extensions/libct_proto_tcp.c index 30d7229..ac54ac7 100644 --- a/extensions/libct_proto_tcp.c +++ b/extensions/libct_proto_tcp.c @@ -56,10 +56,10 @@ static char tcp_commands_v_options[NUMBER_OF_CMD][TCP_NUMBER_OF_OPT] = { /* 1 2 3 4 5 6 7 8 9 */ /*CT_LIST*/ {2,2,2,2,0,0,2,0,0}, -/*CT_CREATE*/ {2,2,2,2,0,0,1,0,0}, +/*CT_CREATE*/ {3,3,3,3,0,0,1,0,0}, /*CT_UPDATE*/ {2,2,2,2,0,0,2,0,0}, /*CT_DELETE*/ {2,2,2,2,0,0,2,0,0}, -/*CT_GET*/ {2,2,2,2,0,0,2,0,0}, +/*CT_GET*/ {3,3,3,3,0,0,2,0,0}, /*CT_FLUSH*/ {0,0,0,0,0,0,0,0,0}, /*CT_EVENT*/ {2,2,2,2,0,0,2,0,0}, /*CT_VERSION*/ {0,0,0,0,0,0,0,0,0}, @@ -172,36 +172,36 @@ static int parse_options(char c, return 1; } +#define TCP_VALID_FLAGS_MAX 2 +static unsigned int tcp_valid_flags[TCP_VALID_FLAGS_MAX] = { + CT_TCP_ORIG_SPORT | CT_TCP_ORIG_DPORT, + CT_TCP_REPL_SPORT | CT_TCP_REPL_DPORT, +}; + static void final_check(unsigned int flags, unsigned int cmd, struct nf_conntrack *ct) { - if ((1 << cmd) & (CT_CREATE|CT_GET)) { - if (!(flags & CT_TCP_ORIG_SPORT) && - (flags & CT_TCP_ORIG_DPORT)) { - exit_error(PARAMETER_PROBLEM, - "missing `--sport'"); - } - if ((flags & CT_TCP_ORIG_SPORT) && - !(flags & CT_TCP_ORIG_DPORT)) { - exit_error(PARAMETER_PROBLEM, - "missing `--dport'"); - } - if (!(flags & CT_TCP_REPL_SPORT) && - (flags & CT_TCP_REPL_DPORT)) { - exit_error(PARAMETER_PROBLEM, - "missing `--reply-port-src'"); - } - if ((flags & CT_TCP_REPL_SPORT) && - !(flags & CT_TCP_REPL_DPORT)) { - exit_error(PARAMETER_PROBLEM, - "missing `--reply-port-dst'"); + int ret, partial; + + ret = generic_opt_check(flags, TCP_NUMBER_OF_OPT, + tcp_commands_v_options[cmd], tcp_optflags, + tcp_valid_flags, TCP_VALID_FLAGS_MAX, &partial); + if (!ret) { + switch(partial) { + case -1: + case 0: + exit_error(PARAMETER_PROBLEM, "you have to specify " + "`--sport' and " + "`--dport'"); + break; + case 1: + exit_error(PARAMETER_PROBLEM, "you have to specify " + "`--reply-src-port' and " + "`--reply-dst-port'"); + break; } } - generic_opt_check(flags, - TCP_NUMBER_OF_OPT, - tcp_commands_v_options[cmd], - tcp_optflags); } static struct ctproto_handler tcp = { diff --git a/extensions/libct_proto_udp.c b/extensions/libct_proto_udp.c index 4f34e3b..d7c4da1 100644 --- a/extensions/libct_proto_udp.c +++ b/extensions/libct_proto_udp.c @@ -64,10 +64,10 @@ static char udp_commands_v_options[NUMBER_OF_CMD][UDP_NUMBER_OF_OPT] = { /* 1 2 3 4 5 6 7 8 */ /*CT_LIST*/ {2,2,2,2,0,0,0,0}, -/*CT_CREATE*/ {2,2,2,2,0,0,0,0}, +/*CT_CREATE*/ {3,3,3,3,0,0,0,0}, /*CT_UPDATE*/ {2,2,2,2,0,0,0,0}, /*CT_DELETE*/ {2,2,2,2,0,0,0,0}, -/*CT_GET*/ {2,2,2,2,0,0,0,0}, +/*CT_GET*/ {3,3,3,3,0,0,0,0}, /*CT_FLUSH*/ {0,0,0,0,0,0,0,0}, /*CT_EVENT*/ {2,2,2,2,0,0,0,0}, /*CT_VERSION*/ {0,0,0,0,0,0,0,0}, @@ -144,36 +144,36 @@ static int parse_options(char c, return 1; } +#define UDP_VALID_FLAGS_MAX 2 +static unsigned int udp_valid_flags[UDP_VALID_FLAGS_MAX] = { + CT_UDP_ORIG_SPORT | CT_UDP_ORIG_DPORT, + CT_UDP_REPL_SPORT | CT_UDP_REPL_DPORT, +}; + static void final_check(unsigned int flags, unsigned int cmd, struct nf_conntrack *ct) { - if ((1 << cmd) & (CT_CREATE|CT_GET)) { - if (!(flags & CT_UDP_ORIG_SPORT) && - (flags & CT_UDP_ORIG_DPORT)) { - exit_error(PARAMETER_PROBLEM, - "missing `--sport'"); - } - if ((flags & CT_UDP_ORIG_SPORT) && - !(flags & CT_UDP_ORIG_DPORT)) { - exit_error(PARAMETER_PROBLEM, - "missing `--dport'"); - } - if (!(flags & CT_UDP_REPL_SPORT) && - (flags & CT_UDP_REPL_DPORT)) { - exit_error(PARAMETER_PROBLEM, - "missing `--reply-port-src'"); - } - if ((flags & CT_UDP_REPL_SPORT) && - !(flags & CT_UDP_REPL_DPORT)) { - exit_error(PARAMETER_PROBLEM, - "missing `--reply-port-dst'"); + int ret, partial; + + ret = generic_opt_check(flags, UDP_NUMBER_OF_OPT, + udp_commands_v_options[cmd], udp_optflags, + udp_valid_flags, UDP_VALID_FLAGS_MAX, &partial); + if (!ret) { + switch(partial) { + case -1: + case 0: + exit_error(PARAMETER_PROBLEM, "you have to specify " + "`--sport' and " + "`--dport'"); + break; + case 1: + exit_error(PARAMETER_PROBLEM, "you have to specify " + "`--reply-src-port' and " + "`--reply-dst-port'"); + break; } } - generic_opt_check(flags, - UDP_NUMBER_OF_OPT, - udp_commands_v_options[cmd], - udp_optflags); } static struct ctproto_handler udp = { diff --git a/include/conntrack.h b/include/conntrack.h index e1f8d0a..17c0121 100644 --- a/include/conntrack.h +++ b/include/conntrack.h @@ -188,10 +188,10 @@ enum exittype { VERSION_PROBLEM }; -void generic_opt_check(int options, - int nops, - char *optset, - const char *optflg[]); +int generic_opt_check(int options, int nops, + char *optset, const char *optflg[], + unsigned int *coupled_flags, int coupled_flags_size, + int *partial); void exit_error(enum exittype status, const char *msg, ...); extern void register_proto(struct ctproto_handler *h); diff --git a/src/conntrack.c b/src/conntrack.c index 0305408..e1c57e5 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -115,6 +115,7 @@ static unsigned int global_option_offset = 0; * 0 illegal * 1 compulsory * 2 optional + * 3 undecided, see flag combination checkings in generic_opt_check() */ static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = @@ -122,10 +123,10 @@ static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = { /* s d r q p t u z e [ ] { } a m i f n g o c b*/ /*CT_LIST*/ {2,2,2,2,2,0,2,2,0,0,0,0,0,0,2,0,2,2,2,2,2,0}, -/*CT_CREATE*/ {2,2,2,2,1,1,2,0,0,0,0,0,0,2,2,0,0,2,2,0,0,0}, +/*CT_CREATE*/ {3,3,3,3,1,1,2,0,0,0,0,0,0,2,2,0,0,2,2,0,0,0}, /*CT_UPDATE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0}, /*CT_DELETE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0}, -/*CT_GET*/ {2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,2,0,0,0,2,0,0}, +/*CT_GET*/ {3,3,3,3,1,0,0,0,0,0,0,0,0,0,0,2,0,0,0,2,0,0}, /*CT_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, /*CT_EVENT*/ {2,2,2,2,2,0,0,0,2,0,0,0,0,0,2,0,0,2,2,2,2,2}, /*VERSION*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, @@ -141,6 +142,12 @@ static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = /*X_STATS*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, }; +#define ADDR_VALID_FLAGS_MAX 2 +static unsigned int addr_valid_flags[ADDR_VALID_FLAGS_MAX] = { + CT_OPT_ORIG_SRC | CT_OPT_ORIG_DST, + CT_OPT_REPL_SRC | CT_OPT_REPL_DST, +}; + static LIST_HEAD(proto_list); static unsigned int options; @@ -260,12 +267,12 @@ static int bit2cmd(int command) return i; } -void generic_opt_check(int local_options, - int num_opts, - char *optset, - const char *optflg[]) +int generic_opt_check(int local_options, int num_opts, + char *optset, const char *optflg[], + unsigned int *coupled_flags, int coupled_flags_size, + int *partial) { - int i; + int i, matching = -1, special_case = 0; for (i = 0; i < num_opts; i++) { if (!(local_options & (1<= 0) + return 1; + + /* report a partial matching to suggest something */ + return 0; } static struct option * @@ -995,7 +1028,7 @@ int main(int argc, char *argv[]) { int c, cmd; unsigned int type = 0, event_mask = 0, l4flags = 0, status = 0; - int res = 0; + int res = 0, partial; size_t socketbuffersize = 0; int family = AF_UNSPEC; char __obj[nfct_maxsize()]; @@ -1197,16 +1230,24 @@ int main(int argc, char *argv[]) family = AF_INET; cmd = bit2cmd(command); - generic_opt_check(options, - NUMBER_OF_OPT, - commands_v_options[cmd], - optflags); - - if (command & (CT_CREATE|CT_GET) && - !((options & CT_OPT_ORIG_SRC && options & CT_OPT_ORIG_DST) || - (options & CT_OPT_REPL_SRC && options & CT_OPT_REPL_DST))) - exit_error(PARAMETER_PROBLEM, "missing IP address"); - + res = generic_opt_check(options, NUMBER_OF_OPT, + commands_v_options[cmd], optflags, + addr_valid_flags, ADDR_VALID_FLAGS_MAX, + &partial); + if (!res) { + switch(partial) { + case -1: + case 0: + exit_error(PARAMETER_PROBLEM, "you have to specify " + "`--src' and `--dst'"); + break; + case 1: + exit_error(PARAMETER_PROBLEM, "you have to specify " + "`--reply-src' and " + "`--reply-dst'"); + break; + } + } if (!(command & CT_HELP) && h && h->final_check) h->final_check(l4flags, cmd, obj); -- cgit v1.2.3 From ff8cf014f089f1dc36898188f962974091c71c7d Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 11 Apr 2009 16:42:20 +0200 Subject: conntrack: add UDPlite support This patch adds UDPlite support for the command line tool conntrack. Signed-off-by: Pablo Neira Ayuso --- conntrack.8 | 17 +++- extensions/Makefile.am | 3 +- extensions/libct_proto_udplite.c | 197 +++++++++++++++++++++++++++++++++++++++ include/conntrack.h | 1 + src/Makefile.am | 2 +- src/conntrack.c | 1 + 6 files changed, 218 insertions(+), 3 deletions(-) create mode 100644 extensions/libct_proto_udplite.c (limited to 'src') diff --git a/conntrack.8 b/conntrack.8 index 208f7a2..b797a1f 100644 --- a/conntrack.8 +++ b/conntrack.8 @@ -1,4 +1,4 @@ -.TH CONNTRACK 8 "Oct 22, 2008" "" "" +.TH CONNTRACK 8 "Apr 11, 2009" "" "" .\" Man page written by 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 /* For htons */ +#include + +#include "conntrack.h" + +#ifndef IPPROTO_UDPLITE +#define IPPROTO_UDPLITE 136 +#endif + +enum { + CT_UDPLITE_ORIG_SPORT = (1 << 0), + CT_UDPLITE_ORIG_DPORT = (1 << 1), + CT_UDPLITE_REPL_SPORT = (1 << 2), + CT_UDPLITE_REPL_DPORT = (1 << 3), + CT_UDPLITE_MASK_SPORT = (1 << 4), + CT_UDPLITE_MASK_DPORT = (1 << 5), + CT_UDPLITE_EXPTUPLE_SPORT = (1 << 6), + CT_UDPLITE_EXPTUPLE_DPORT = (1 << 7) +}; + +#define UDP_OPT_MAX 11 +static struct option opts[UDP_OPT_MAX] = { + { .name = "orig-port-src", .has_arg = 1, .val = '1' }, + { .name = "orig-port-dst", .has_arg = 1, .val = '2' }, + { .name = "reply-port-src", .has_arg = 1, .val = '3' }, + { .name = "reply-port-dst", .has_arg = 1, .val = '4' }, + { .name = "mask-port-src", .has_arg = 1, .val = '5' }, + { .name = "mask-port-dst", .has_arg = 1, .val = '6' }, + { .name = "tuple-port-src", .has_arg = 1, .val = '7' }, + { .name = "tuple-port-dst", .has_arg = 1, .val = '8' }, + { .name = "sport", .has_arg = 1, .val = '1' }, + { .name = "dport", .has_arg = 1, .val = '2' }, + {0, 0, 0, 0} +}; + +static const char *udplite_optflags[UDP_OPT_MAX] = { + [0] = "sport", + [1] = "dport", + [2] = "reply-port-src", + [3] = "reply-port-dst", + [4] = "mask-port-src", + [5] = "mask-port-dst", + [6] = "tuple-port-src", + [7] = "tuple-port-dst" +}; + +static void help(void) +{ + fprintf(stdout, " --orig-port-src\t\toriginal source port\n"); + fprintf(stdout, " --orig-port-dst\t\toriginal destination port\n"); + fprintf(stdout, " --reply-port-src\t\treply source port\n"); + fprintf(stdout, " --reply-port-dst\t\treply destination port\n"); + fprintf(stdout, " --mask-port-src\t\tmask source port\n"); + fprintf(stdout, " --mask-port-dst\t\tmask destination port\n"); + fprintf(stdout, " --tuple-port-src\t\texpectation tuple src port\n"); + fprintf(stdout, " --tuple-port-src\t\texpectation tuple dst port\n"); +} + +static char udplite_commands_v_options[NUMBER_OF_CMD][UDP_OPT_MAX] = +{ + /* 1 2 3 4 5 6 7 8 */ +/*CT_LIST*/ {2,2,2,2,0,0,0,0}, +/*CT_CREATE*/ {3,3,3,3,0,0,0,0}, +/*CT_UPDATE*/ {2,2,2,2,0,0,0,0}, +/*CT_DELETE*/ {2,2,2,2,0,0,0,0}, +/*CT_GET*/ {3,3,3,3,0,0,0,0}, +/*CT_FLUSH*/ {0,0,0,0,0,0,0,0}, +/*CT_EVENT*/ {2,2,2,2,0,0,0,0}, +/*CT_VERSION*/ {0,0,0,0,0,0,0,0}, +/*CT_HELP*/ {0,0,0,0,0,0,0,0}, +/*EXP_LIST*/ {0,0,0,0,0,0,0,0}, +/*EXP_CREATE*/ {1,1,1,1,1,1,1,1}, +/*EXP_DELETE*/ {1,1,1,1,0,0,0,0}, +/*EXP_GET*/ {1,1,1,1,0,0,0,0}, +/*EXP_FLUSH*/ {0,0,0,0,0,0,0,0}, +/*EXP_EVENT*/ {0,0,0,0,0,0,0,0}, +}; + +static int parse_options(char c, + struct nf_conntrack *ct, + struct nf_conntrack *exptuple, + struct nf_conntrack *mask, + unsigned int *flags) +{ + switch(c) { + u_int16_t port; + case '1': + port = htons(atoi(optarg)); + nfct_set_attr_u16(ct, ATTR_ORIG_PORT_SRC, port); + nfct_set_attr_u8(ct, ATTR_ORIG_L4PROTO, IPPROTO_UDPLITE); + *flags |= CT_UDPLITE_ORIG_SPORT; + break; + case '2': + port = htons(atoi(optarg)); + nfct_set_attr_u16(ct, ATTR_ORIG_PORT_DST, port); + nfct_set_attr_u8(ct, ATTR_ORIG_L4PROTO, IPPROTO_UDPLITE); + *flags |= CT_UDPLITE_ORIG_DPORT; + break; + case '3': + port = htons(atoi(optarg)); + nfct_set_attr_u16(ct, ATTR_REPL_PORT_SRC, port); + nfct_set_attr_u8(ct, ATTR_REPL_L4PROTO, IPPROTO_UDPLITE); + *flags |= CT_UDPLITE_REPL_SPORT; + break; + case '4': + port = htons(atoi(optarg)); + nfct_set_attr_u16(ct, ATTR_REPL_PORT_DST, port); + nfct_set_attr_u8(ct, ATTR_REPL_L4PROTO, IPPROTO_UDPLITE); + *flags |= CT_UDPLITE_REPL_DPORT; + break; + case '5': + port = htons(atoi(optarg)); + nfct_set_attr_u16(mask, ATTR_ORIG_PORT_SRC, port); + nfct_set_attr_u8(mask, ATTR_ORIG_L4PROTO, IPPROTO_UDPLITE); + *flags |= CT_UDPLITE_MASK_SPORT; + break; + case '6': + port = htons(atoi(optarg)); + nfct_set_attr_u16(mask, ATTR_ORIG_PORT_DST, port); + nfct_set_attr_u8(mask, ATTR_ORIG_L4PROTO, IPPROTO_UDPLITE); + *flags |= CT_UDPLITE_MASK_DPORT; + break; + case '7': + port = htons(atoi(optarg)); + nfct_set_attr_u16(exptuple, ATTR_ORIG_PORT_SRC, port); + nfct_set_attr_u8(exptuple, ATTR_ORIG_L4PROTO, IPPROTO_UDPLITE); + *flags |= CT_UDPLITE_EXPTUPLE_SPORT; + break; + case '8': + port = htons(atoi(optarg)); + nfct_set_attr_u16(exptuple, ATTR_ORIG_PORT_DST, port); + nfct_set_attr_u8(exptuple, ATTR_ORIG_L4PROTO, IPPROTO_UDPLITE); + *flags |= CT_UDPLITE_EXPTUPLE_DPORT; + break; + } + return 1; +} + +#define UDPLITE_VALID_FLAGS_MAX 2 +static unsigned int udplite_valid_flags[UDPLITE_VALID_FLAGS_MAX] = { + CT_UDPLITE_ORIG_SPORT | CT_UDPLITE_ORIG_DPORT, + CT_UDPLITE_REPL_SPORT | CT_UDPLITE_REPL_DPORT, +}; + +static void +final_check(unsigned int flags, unsigned int cmd, struct nf_conntrack *ct) +{ + int ret, partial; + + ret = generic_opt_check(flags, UDP_OPT_MAX, + udplite_commands_v_options[cmd], + udplite_optflags, + udplite_valid_flags, UDPLITE_VALID_FLAGS_MAX, + &partial); + if (!ret) { + switch(partial) { + case -1: + case 0: + exit_error(PARAMETER_PROBLEM, "you have to specify " + "`--sport' and " + "`--dport'"); + break; + case 1: + exit_error(PARAMETER_PROBLEM, "you have to specify " + "`--reply-src-port' and " + "`--reply-dst-port'"); + break; + } + } +} + +static struct ctproto_handler udplite = { + .name = "udplite", + .protonum = IPPROTO_UDPLITE, + .parse_opts = parse_options, + .final_check = final_check, + .help = help, + .opts = opts, + .version = VERSION, +}; + +void register_udplite(void) +{ + register_proto(&udplite); +} diff --git a/include/conntrack.h b/include/conntrack.h index 17c0121..2995d71 100644 --- a/include/conntrack.h +++ b/include/conntrack.h @@ -198,6 +198,7 @@ extern void register_proto(struct ctproto_handler *h); extern void register_tcp(void); extern void register_udp(void); +extern void register_udplite(void); extern void register_icmp(void); extern void register_icmpv6(void); extern void register_unknown(void); diff --git a/src/Makefile.am b/src/Makefile.am index 667040c..6c5b1a9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -7,7 +7,7 @@ CLEANFILES = read_config_yy.c read_config_lex.c sbin_PROGRAMS = conntrack conntrackd conntrack_SOURCES = conntrack.c -conntrack_LDADD = ../extensions/libct_proto_tcp.la ../extensions/libct_proto_udp.la ../extensions/libct_proto_icmp.la ../extensions/libct_proto_icmpv6.la ../extensions/libct_proto_unknown.la +conntrack_LDADD = ../extensions/libct_proto_tcp.la ../extensions/libct_proto_udp.la ../extensions/libct_proto_udplite.la ../extensions/libct_proto_icmp.la ../extensions/libct_proto_icmpv6.la ../extensions/libct_proto_unknown.la conntrack_LDFLAGS = $(all_libraries) @LIBNETFILTER_CONNTRACK_LIBS@ conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c rbtree.c \ diff --git a/src/conntrack.c b/src/conntrack.c index e1c57e5..bf3e8e0 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -1051,6 +1051,7 @@ int main(int argc, char *argv[]) register_tcp(); register_udp(); + register_udplite(); register_icmp(); register_icmpv6(); register_unknown(); -- cgit v1.2.3 From 19f183958c1ce9d8faf312c7e4009dee5a10e1ac Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 11 Apr 2009 16:42:20 +0200 Subject: conntrack: add SCTP support This patch adds SCTP support to the command line tool conntrack. Signed-off-by: Pablo Neira Ayuso --- conntrack.8 | 23 ++++ extensions/Makefile.am | 4 +- extensions/libct_proto_sctp.c | 246 ++++++++++++++++++++++++++++++++++++++++++ include/conntrack.h | 4 +- src/Makefile.am | 2 +- src/conntrack.c | 1 + 6 files changed, 275 insertions(+), 5 deletions(-) create mode 100644 extensions/libct_proto_sctp.c (limited to 'src') diff --git a/conntrack.8 b/conntrack.8 index b797a1f..490d299 100644 --- a/conntrack.8 +++ b/conntrack.8 @@ -214,6 +214,29 @@ Source port in reply direction .BI "--reply-port-dst " "PORT" Destination port in reply direction .TP +SCTP-specific fields: +.TP +.BI "--sport, --orig-port-src " "PORT" +Source port in original direction +.TP +.BI "--dport, --orig-port-dst " "PORT" +Destination port in original direction +.TP +.BI "--reply-port-src " "PORT" +Source port in reply direction +.TP +.BI "--reply-port-dst " "PORT" +Destination port in reply direction +.TP +.BI "--state " "[NONE | CLOSED | COOKIE_WAIT | COOKIE_ECHOED | ESTABLISHED | SHUTDOWN_SENT | SHUTDOWN_RECD | SHUTDOWN_ACK_SENT]" +SCTP state +.TP +.BI "--orig-vtag " "value" +Verification tag (32-bits value) in the original direction +.TP +.BI "--reply-vtag " "value" +Verification tag (32-bits value) in the reply direction +.TP .SH DIAGNOSTICS The exit code is 0 for correct function. Errors which appear to be caused by invalid command line parameters cause an exit code of 2. Any other errors diff --git a/extensions/Makefile.am b/extensions/Makefile.am index 70edf47..14293d0 100644 --- a/extensions/Makefile.am +++ b/extensions/Makefile.am @@ -2,7 +2,8 @@ include $(top_srcdir)/Make_global.am noinst_LTLIBRARIES = libct_proto_tcp.la libct_proto_udp.la \ libct_proto_icmp.la libct_proto_icmpv6.la \ - libct_proto_unknown.la libct_proto_udplite.la + libct_proto_unknown.la libct_proto_udplite.la \ + libct_proto_sctp.la libct_proto_tcp_la_SOURCES = libct_proto_tcp.c libct_proto_udp_la_SOURCES = libct_proto_udp.c @@ -10,3 +11,4 @@ libct_proto_udplite_la_SOURCES = libct_proto_udplite.c libct_proto_icmp_la_SOURCES = libct_proto_icmp.c libct_proto_icmpv6_la_SOURCES = libct_proto_icmpv6.c libct_proto_unknown_la_SOURCES = libct_proto_unknown.c +libct_proto_sctp_la_SOURCES = libct_proto_sctp.c diff --git a/extensions/libct_proto_sctp.c b/extensions/libct_proto_sctp.c new file mode 100644 index 0000000..f4c94df --- /dev/null +++ b/extensions/libct_proto_sctp.c @@ -0,0 +1,246 @@ +/* + * (C) 2009 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 +#include +#include +#include +#include /* For htons */ +#include +#include + +#include "conntrack.h" + +#ifndef IPPROTO_SCTP +#define IPPROTO_SCTP 132 +#endif + +enum { + CT_SCTP_ORIG_SPORT = (1 << 0), + CT_SCTP_ORIG_DPORT = (1 << 1), + CT_SCTP_REPL_SPORT = (1 << 2), + CT_SCTP_REPL_DPORT = (1 << 3), + CT_SCTP_MASK_SPORT = (1 << 4), + CT_SCTP_MASK_DPORT = (1 << 5), + CT_SCTP_STATE = (1 << 6), + CT_SCTP_EXPTUPLE_SPORT = (1 << 7), + CT_SCTP_EXPTUPLE_DPORT = (1 << 8), + CT_SCTP_ORIG_VTAG = (1 << 9), + CT_SCTP_REPL_VTAG = (1 << 10), +}; + +#define SCTP_OPT_MAX 14 +static struct option opts[SCTP_OPT_MAX] = { + { .name = "orig-port-src", .has_arg = 1, .val = 1 }, + { .name = "orig-port-dst", .has_arg = 1, .val = 2 }, + { .name = "reply-port-src", .has_arg = 1, .val = 3 }, + { .name = "reply-port-dst", .has_arg = 1, .val = 4 }, + { .name = "mask-port-src", .has_arg = 1, .val = 5 }, + { .name = "mask-port-dst", .has_arg = 1, .val = 6 }, + { .name = "state", .has_arg = 1, .val = 7 }, + { .name = "tuple-port-src", .has_arg = 1, .val = 8 }, + { .name = "tuple-port-dst", .has_arg = 1, .val = 9 }, + { .name = "orig-vtag", .has_arg = 1, .val = 10 }, + { .name = "reply-vtag", .has_arg = 1, .val = 11 }, + { .name = "sport", .has_arg = 1, .val = 1 }, /* alias */ + { .name = "dport", .has_arg = 1, .val = 2 }, /* alias */ + {0, 0, 0, 0} +}; + +static const char *sctp_optflags[SCTP_OPT_MAX] = { + [0] = "sport", + [1] = "dport", + [2] = "reply-port-src", + [3] = "reply-port-dst", + [4] = "mask-port-src", + [5] = "mask-port-dst", + [6] = "state", + [7] = "tuple-port-src", + [8] = "tuple-port-dst", + [9] = "orig-vtag", + [10] = "reply-vtag", +}; + +static char sctp_commands_v_options[NUMBER_OF_CMD][SCTP_OPT_MAX] = +/* Well, it's better than "Re: Sevilla vs Betis" */ +{ + /* 1 2 3 4 5 6 7 8 9 10 11*/ +/*CT_LIST*/ {2,2,2,2,0,0,2,0,0,0,0}, +/*CT_CREATE*/ {3,3,3,3,0,0,1,0,0,1,1}, +/*CT_UPDATE*/ {2,2,2,2,0,0,2,0,0,2,2}, +/*CT_DELETE*/ {2,2,2,2,0,0,2,0,0,0,0}, +/*CT_GET*/ {3,3,3,3,0,0,2,0,0,2,2}, +/*CT_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0}, +/*CT_EVENT*/ {2,2,2,2,0,0,2,0,0,0,0}, +/*CT_VERSION*/ {0,0,0,0,0,0,0,0,0,0,0}, +/*CT_HELP*/ {0,0,0,0,0,0,0,0,0,0,0}, +/*EXP_LIST*/ {0,0,0,0,0,0,0,0,0,0,0}, +/*EXP_CREATE*/ {1,1,1,1,1,1,0,1,1,1,1}, +/*EXP_DELETE*/ {1,1,1,1,0,0,0,0,0,0,0}, +/*EXP_GET*/ {1,1,1,1,0,0,0,0,0,0,0}, +/*EXP_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0}, +/*EXP_EVENT*/ {0,0,0,0,0,0,0,0,0,0,0}, +}; + +static const char *sctp_states[SCTP_CONNTRACK_MAX] = { + [SCTP_CONNTRACK_NONE] = "NONE", + [SCTP_CONNTRACK_CLOSED] = "CLOSED", + [SCTP_CONNTRACK_COOKIE_WAIT] = "COOKIE_WAIT", + [SCTP_CONNTRACK_COOKIE_ECHOED] = "COOKIE_ECHOED", + [SCTP_CONNTRACK_ESTABLISHED] = "ESTABLISHED", + [SCTP_CONNTRACK_SHUTDOWN_SENT] = "SHUTDOWN_SENT", + [SCTP_CONNTRACK_SHUTDOWN_RECD] = "SHUTDOWN_RECD", + [SCTP_CONNTRACK_SHUTDOWN_ACK_SENT] = "SHUTDOWN_ACK_SENT", +}; + +static void help(void) +{ + fprintf(stdout, " --orig-port-src\t\toriginal source port\n"); + fprintf(stdout, " --orig-port-dst\t\toriginal destination port\n"); + fprintf(stdout, " --reply-port-src\t\treply source port\n"); + fprintf(stdout, " --reply-port-dst\t\treply destination port\n"); + fprintf(stdout, " --mask-port-src\t\tmask source port\n"); + fprintf(stdout, " --mask-port-dst\t\tmask destination port\n"); + fprintf(stdout, " --tuple-port-src\t\texpectation tuple src port\n"); + fprintf(stdout, " --tuple-port-src\t\texpectation tuple dst port\n"); + fprintf(stdout, " --state\t\t\tSCTP state, fe. ESTABLISHED\n"); + fprintf(stdout, " --orig-vtag\t\toriginal verification tag\n"); + fprintf(stdout, " --reply-vtag\t\treply verification tag\n"); +} + +static int +parse_options(char c, struct nf_conntrack *ct, + struct nf_conntrack *exptuple, struct nf_conntrack *mask, + unsigned int *flags) +{ + int i; + u_int16_t port; + u_int32_t vtag; + + switch(c) { + case 1: + port = htons(atoi(optarg)); + nfct_set_attr_u16(ct, ATTR_ORIG_PORT_SRC, port); + nfct_set_attr_u8(ct, ATTR_ORIG_L4PROTO, IPPROTO_SCTP); + *flags |= CT_SCTP_ORIG_SPORT; + break; + case 2: + port = htons(atoi(optarg)); + nfct_set_attr_u16(ct, ATTR_ORIG_PORT_DST, port); + nfct_set_attr_u8(ct, ATTR_ORIG_L4PROTO, IPPROTO_SCTP); + *flags |= CT_SCTP_ORIG_DPORT; + break; + case 3: + port = htons(atoi(optarg)); + nfct_set_attr_u16(ct, ATTR_REPL_PORT_SRC, port); + nfct_set_attr_u8(ct, ATTR_REPL_L4PROTO, IPPROTO_SCTP); + *flags |= CT_SCTP_REPL_SPORT; + break; + case 4: + port = htons(atoi(optarg)); + nfct_set_attr_u16(ct, ATTR_REPL_PORT_DST, port); + nfct_set_attr_u8(ct, ATTR_REPL_L4PROTO, IPPROTO_SCTP); + *flags |= CT_SCTP_REPL_DPORT; + break; + case 5: + port = htons(atoi(optarg)); + nfct_set_attr_u16(mask, ATTR_ORIG_PORT_SRC, port); + nfct_set_attr_u8(mask, ATTR_ORIG_L4PROTO, IPPROTO_SCTP); + *flags |= CT_SCTP_MASK_SPORT; + break; + case 6: + port = htons(atoi(optarg)); + nfct_set_attr_u16(mask, ATTR_ORIG_PORT_DST, port); + nfct_set_attr_u8(mask, ATTR_ORIG_L4PROTO, IPPROTO_SCTP); + *flags |= CT_SCTP_MASK_DPORT; + break; + case 7: + for (i=0; i -#ifndef IPPROTO_SCTP -#define IPPROTO_SCTP 132 -#endif enum action { CT_NONE = 0, @@ -199,6 +196,7 @@ extern void register_proto(struct ctproto_handler *h); extern void register_tcp(void); extern void register_udp(void); extern void register_udplite(void); +extern void register_sctp(void); extern void register_icmp(void); extern void register_icmpv6(void); extern void register_unknown(void); diff --git a/src/Makefile.am b/src/Makefile.am index 6c5b1a9..3256666 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -7,7 +7,7 @@ CLEANFILES = read_config_yy.c read_config_lex.c sbin_PROGRAMS = conntrack conntrackd conntrack_SOURCES = conntrack.c -conntrack_LDADD = ../extensions/libct_proto_tcp.la ../extensions/libct_proto_udp.la ../extensions/libct_proto_udplite.la ../extensions/libct_proto_icmp.la ../extensions/libct_proto_icmpv6.la ../extensions/libct_proto_unknown.la +conntrack_LDADD = ../extensions/libct_proto_tcp.la ../extensions/libct_proto_udp.la ../extensions/libct_proto_udplite.la ../extensions/libct_proto_icmp.la ../extensions/libct_proto_icmpv6.la ../extensions/libct_proto_sctp.la ../extensions/libct_proto_unknown.la conntrack_LDFLAGS = $(all_libraries) @LIBNETFILTER_CONNTRACK_LIBS@ conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c rbtree.c \ diff --git a/src/conntrack.c b/src/conntrack.c index bf3e8e0..1adcef9 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -1052,6 +1052,7 @@ int main(int argc, char *argv[]) register_tcp(); register_udp(); register_udplite(); + register_sctp(); register_icmp(); register_icmpv6(); register_unknown(); -- cgit v1.2.3 From 549d78e74c1140b1a4dcd35e44e64d51a3c613e6 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 11 Apr 2009 16:42:20 +0200 Subject: conntrack: add DCCP support This patch adds DCCP support for the command line tool conntrack. Signed-off-by: Pablo Neira Ayuso --- conntrack.8 | 17 ++++ extensions/Makefile.am | 3 +- extensions/libct_proto_dccp.c | 230 ++++++++++++++++++++++++++++++++++++++++++ include/conntrack.h | 1 + src/Makefile.am | 2 +- src/conntrack.c | 1 + 6 files changed, 252 insertions(+), 2 deletions(-) create mode 100644 extensions/libct_proto_dccp.c (limited to 'src') diff --git a/conntrack.8 b/conntrack.8 index 490d299..e875940 100644 --- a/conntrack.8 +++ b/conntrack.8 @@ -237,6 +237,23 @@ Verification tag (32-bits value) in the original direction .BI "--reply-vtag " "value" Verification tag (32-bits value) in the reply direction .TP +DCCP-specific fields: +.TP +.BI "--sport, --orig-port-src " "PORT" +Source port in original direction +.TP +.BI "--dport, --orig-port-dst " "PORT" +Destination port in original direction +.TP +.BI "--reply-port-src " "PORT" +Source port in reply direction +.TP +.BI "--reply-port-dst " "PORT" +Destination port in reply direction +.TP +.BI "--state " "[NONE | REQUEST | RESPOND | PARTOPEN | OPEN | CLOSEREQ | CLOSING | TIMEWAIT]" +DCCP state +.TP .SH DIAGNOSTICS The exit code is 0 for correct function. Errors which appear to be caused by invalid command line parameters cause an exit code of 2. Any other errors diff --git a/extensions/Makefile.am b/extensions/Makefile.am index 14293d0..dc7bff5 100644 --- a/extensions/Makefile.am +++ b/extensions/Makefile.am @@ -3,7 +3,7 @@ include $(top_srcdir)/Make_global.am noinst_LTLIBRARIES = libct_proto_tcp.la libct_proto_udp.la \ libct_proto_icmp.la libct_proto_icmpv6.la \ libct_proto_unknown.la libct_proto_udplite.la \ - libct_proto_sctp.la + libct_proto_sctp.la libct_proto_dccp.la libct_proto_tcp_la_SOURCES = libct_proto_tcp.c libct_proto_udp_la_SOURCES = libct_proto_udp.c @@ -12,3 +12,4 @@ libct_proto_icmp_la_SOURCES = libct_proto_icmp.c libct_proto_icmpv6_la_SOURCES = libct_proto_icmpv6.c libct_proto_unknown_la_SOURCES = libct_proto_unknown.c libct_proto_sctp_la_SOURCES = libct_proto_sctp.c +libct_proto_dccp_la_SOURCES = libct_proto_dccp.c diff --git a/extensions/libct_proto_dccp.c b/extensions/libct_proto_dccp.c new file mode 100644 index 0000000..deb3e28 --- /dev/null +++ b/extensions/libct_proto_dccp.c @@ -0,0 +1,230 @@ +/* + * (C) 2009 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 +#include +#include +#include +#include /* For htons */ +#include +#include + +#include "conntrack.h" + +#ifndef IPPROTO_DCCP +#define IPPROTO_DCCP 33 +#endif + +enum { + CT_DCCP_ORIG_SPORT = (1 << 0), + CT_DCCP_ORIG_DPORT = (1 << 1), + CT_DCCP_REPL_SPORT = (1 << 2), + CT_DCCP_REPL_DPORT = (1 << 3), + CT_DCCP_MASK_SPORT = (1 << 4), + CT_DCCP_MASK_DPORT = (1 << 5), + CT_DCCP_STATE = (1 << 6), + CT_DCCP_EXPTUPLE_SPORT = (1 << 7), + CT_DCCP_EXPTUPLE_DPORT = (1 << 8) +}; + +#define DCCP_OPT_MAX 13 +static struct option opts[DCCP_OPT_MAX] = { + { .name = "orig-port-src", .has_arg = 1, .val = '1' }, + { .name = "orig-port-dst", .has_arg = 1, .val = '2' }, + { .name = "reply-port-src", .has_arg = 1, .val = '3' }, + { .name = "reply-port-dst", .has_arg = 1, .val = '4' }, + { .name = "mask-port-src", .has_arg = 1, .val = '5' }, + { .name = "mask-port-dst", .has_arg = 1, .val = '6' }, + { .name = "state", .has_arg = 1, .val = '7' }, + { .name = "tuple-port-src", .has_arg = 1, .val = '8' }, + { .name = "tuple-port-dst", .has_arg = 1, .val = '9' }, + { .name = "sport", .has_arg = 1, .val = '1' }, /* alias */ + { .name = "dport", .has_arg = 1, .val = '2' }, /* alias */ + { 0, 0, 0, 0}, +}; + +static const char *dccp_optflags[DCCP_OPT_MAX] = { + [0] = "sport", + [1] = "dport", + [2] = "reply-port-src", + [3] = "reply-port-dst", + [4] = "mask-port-src", + [5] = "mask-port-dst", + [6] = "state", + [7] = "tuple-port-src", + [8] = "tuple-port-dst" +}; + +static char dccp_commands_v_options[NUMBER_OF_CMD][DCCP_OPT_MAX] = +/* Well, it's better than "Re: Sevilla vs Betis" */ +{ + /* 1 2 3 4 5 6 7 8 9 */ +/*CT_LIST*/ {2,2,2,2,0,0,2,0,0}, +/*CT_CREATE*/ {3,3,3,3,0,0,1,0,0}, +/*CT_UPDATE*/ {2,2,2,2,0,0,2,0,0}, +/*CT_DELETE*/ {2,2,2,2,0,0,2,0,0}, +/*CT_GET*/ {3,3,3,3,0,0,2,0,0}, +/*CT_FLUSH*/ {0,0,0,0,0,0,0,0,0}, +/*CT_EVENT*/ {2,2,2,2,0,0,2,0,0}, +/*CT_VERSION*/ {0,0,0,0,0,0,0,0,0}, +/*CT_HELP*/ {0,0,0,0,0,0,0,0,0}, +/*EXP_LIST*/ {0,0,0,0,0,0,0,0,0}, +/*EXP_CREATE*/ {1,1,1,1,1,1,0,1,1}, +/*EXP_DELETE*/ {1,1,1,1,0,0,0,0,0}, +/*EXP_GET*/ {1,1,1,1,0,0,0,0,0}, +/*EXP_FLUSH*/ {0,0,0,0,0,0,0,0,0}, +/*EXP_EVENT*/ {0,0,0,0,0,0,0,0,0}, +}; + +static const char *dccp_states[DCCP_CONNTRACK_MAX] = { + [DCCP_CONNTRACK_NONE] = "NONE", + [DCCP_CONNTRACK_REQUEST] = "REQUEST", + [DCCP_CONNTRACK_RESPOND] = "RESPOND", + [DCCP_CONNTRACK_PARTOPEN] = "PARTOPEN", + [DCCP_CONNTRACK_OPEN] = "OPEN", + [DCCP_CONNTRACK_CLOSEREQ] = "CLOSEREQ", + [DCCP_CONNTRACK_CLOSING] = "CLOSING", + [DCCP_CONNTRACK_TIMEWAIT] = "TIMEWAIT", + [DCCP_CONNTRACK_IGNORE] = "IGNORE", + [DCCP_CONNTRACK_INVALID] = "INVALID", +}; + +static void help(void) +{ + fprintf(stdout, " --orig-port-src\t\toriginal source port\n"); + fprintf(stdout, " --orig-port-dst\t\toriginal destination port\n"); + fprintf(stdout, " --reply-port-src\t\treply source port\n"); + fprintf(stdout, " --reply-port-dst\t\treply destination port\n"); + fprintf(stdout, " --mask-port-src\t\tmask source port\n"); + fprintf(stdout, " --mask-port-dst\t\tmask destination port\n"); + fprintf(stdout, " --tuple-port-src\t\texpectation tuple src port\n"); + fprintf(stdout, " --tuple-port-src\t\texpectation tuple dst port\n"); + fprintf(stdout, " --state\t\t\tDCCP state, fe. RESPOND\n"); +} + +static int parse_options(char c, + struct nf_conntrack *ct, + struct nf_conntrack *exptuple, + struct nf_conntrack *mask, + unsigned int *flags) +{ + int i; + u_int16_t port; + + switch(c) { + case '1': + port = htons(atoi(optarg)); + nfct_set_attr_u16(ct, ATTR_ORIG_PORT_SRC, port); + nfct_set_attr_u8(ct, ATTR_ORIG_L4PROTO, IPPROTO_DCCP); + *flags |= CT_DCCP_ORIG_SPORT; + break; + case '2': + port = htons(atoi(optarg)); + nfct_set_attr_u16(ct, ATTR_ORIG_PORT_DST, port); + nfct_set_attr_u8(ct, ATTR_ORIG_L4PROTO, IPPROTO_DCCP); + *flags |= CT_DCCP_ORIG_DPORT; + break; + case '3': + port = htons(atoi(optarg)); + nfct_set_attr_u16(ct, ATTR_REPL_PORT_SRC, port); + nfct_set_attr_u8(ct, ATTR_REPL_L4PROTO, IPPROTO_DCCP); + *flags |= CT_DCCP_REPL_SPORT; + break; + case '4': + port = htons(atoi(optarg)); + nfct_set_attr_u16(ct, ATTR_REPL_PORT_DST, port); + nfct_set_attr_u8(ct, ATTR_REPL_L4PROTO, IPPROTO_DCCP); + *flags |= CT_DCCP_REPL_DPORT; + break; + case '5': + port = htons(atoi(optarg)); + nfct_set_attr_u16(mask, ATTR_ORIG_PORT_SRC, port); + nfct_set_attr_u8(mask, ATTR_ORIG_L4PROTO, IPPROTO_DCCP); + *flags |= CT_DCCP_MASK_SPORT; + break; + case '6': + port = htons(atoi(optarg)); + nfct_set_attr_u16(mask, ATTR_ORIG_PORT_DST, port); + nfct_set_attr_u8(mask, ATTR_ORIG_L4PROTO, IPPROTO_DCCP); + *flags |= CT_DCCP_MASK_DPORT; + break; + case '7': + for (i=0; i Date: Tue, 14 Apr 2009 10:43:16 +0200 Subject: conntrackd: change scheduler and priority via configuration file With this patch, you can change the scheduler policy and priority for conntrackd. Using a RT scheduler policy reduces the chances to hit ENOBUFS in Netlink. Signed-off-by: Pablo Neira Ayuso --- doc/stats/conntrackd.conf | 11 +++++++++++ doc/sync/alarm/conntrackd.conf | 11 +++++++++++ doc/sync/ftfw/conntrackd.conf | 11 +++++++++++ doc/sync/notrack/conntrackd.conf | 11 +++++++++++ include/conntrackd.h | 4 ++++ src/main.c | 19 ++++++++++++++++++- src/read_config_lex.l | 3 +++ src/read_config_yy.y | 30 ++++++++++++++++++++++++++++++ 8 files changed, 99 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/doc/stats/conntrackd.conf b/doc/stats/conntrackd.conf index 1f1a697..8945293 100644 --- a/doc/stats/conntrackd.conf +++ b/doc/stats/conntrackd.conf @@ -10,6 +10,17 @@ General { # Nice -1 + # + # Select a different scheduler for the daemon, you can select between + # RR and FIFO and the process priority (minimum is 0, maximum is 99). + # See man sched_setscheduler(2) for more information. Using a RT + # scheduler reduces the chances to overrun the Netlink buffer. + # + # Scheduler { + # Type FIFO + # Priority 99 + # } + # # Number of buckets in the caches: hash table # diff --git a/doc/sync/alarm/conntrackd.conf b/doc/sync/alarm/conntrackd.conf index ca6e661..793e953 100644 --- a/doc/sync/alarm/conntrackd.conf +++ b/doc/sync/alarm/conntrackd.conf @@ -196,6 +196,17 @@ General { # Nice -20 + # + # Select a different scheduler for the daemon, you can select between + # RR and FIFO and the process priority (minimum is 0, maximum is 99). + # See man sched_setscheduler(2) for more information. Using a RT + # scheduler reduces the chances to overrun the Netlink buffer. + # + # Scheduler { + # Type FIFO + # Priority 99 + # } + # # Number of buckets in the cache hashtable. The bigger it is, # the closer it gets to O(1) at the cost of consuming more memory. diff --git a/doc/sync/ftfw/conntrackd.conf b/doc/sync/ftfw/conntrackd.conf index 33c6fce..6eb4475 100644 --- a/doc/sync/ftfw/conntrackd.conf +++ b/doc/sync/ftfw/conntrackd.conf @@ -205,6 +205,17 @@ General { # Nice -20 + # + # Select a different scheduler for the daemon, you can select between + # RR and FIFO and the process priority (minimum is 0, maximum is 99). + # See man sched_setscheduler(2) for more information. Using a RT + # scheduler reduces the chances to overrun the Netlink buffer. + # + # Scheduler { + # Type FIFO + # Priority 99 + # } + # # Number of buckets in the cache hashtable. The bigger it is, # the closer it gets to O(1) at the cost of consuming more memory. diff --git a/doc/sync/notrack/conntrackd.conf b/doc/sync/notrack/conntrackd.conf index 6175284..e2085f7 100644 --- a/doc/sync/notrack/conntrackd.conf +++ b/doc/sync/notrack/conntrackd.conf @@ -186,6 +186,17 @@ General { # Nice -20 + # + # Select a different scheduler for the daemon, you can select between + # RR and FIFO and the process priority (minimum is 0, maximum is 99). + # See man sched_setscheduler(2) for more information. Using a RT + # scheduler reduces the chances to overrun the Netlink buffer. + # + # Scheduler { + # Type FIFO + # Priority 99 + # } + # # Number of buckets in the cache hashtable. The bigger it is, # the closer it gets to O(1) at the cost of consuming more memory. diff --git a/include/conntrackd.h b/include/conntrackd.h index 737c7fd..013ec4f 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -94,6 +94,10 @@ struct ct_conf { int cache_write_through; int filter_from_kernelspace; int event_iterations_limit; + struct { + int type; + int prio; + } sched; struct { char logfile[FILENAME_MAXLEN]; int syslog_facility; diff --git a/src/main.c b/src/main.c index 62ae599..7507ae5 100644 --- a/src/main.c +++ b/src/main.c @@ -26,6 +26,7 @@ #include #include #include +#include #include struct ct_general_state st; @@ -295,6 +296,23 @@ int main(int argc, char *argv[]) } close(ret); + /* + * Setting process priority and scheduler + */ + nice(CONFIG(nice)); + + if (CONFIG(sched).type != SCHED_OTHER) { + struct sched_param schedparam = { + .sched_priority = CONFIG(sched).prio, + }; + + ret = sched_setscheduler(0, CONFIG(sched).type, &schedparam); + if (ret == -1) { + perror("sched"); + exit(EXIT_FAILURE); + } + } + /* * initialization process */ @@ -309,7 +327,6 @@ int main(int argc, char *argv[]) chdir("/"); close(STDIN_FILENO); - nice(CONFIG(nice)); /* Daemonize conntrackd */ if (type == DAEMON) { diff --git a/src/read_config_lex.l b/src/read_config_lex.l index 44ccf0b..3d5913e 100644 --- a/src/read_config_lex.l +++ b/src/read_config_lex.l @@ -132,6 +132,9 @@ notrack [N|n][O|o][T|t][R|r][A|a][C|c][K|k] "PollSecs" { return T_POLL_SECS; } "NetlinkOverrunResync" { return T_NETLINK_OVERRUN_RESYNC; } "Nice" { return T_NICE; } +"Scheduler" { return T_SCHEDULER; } +"Type" { return T_TYPE; } +"Priority" { return T_PRIO; } {is_on} { return T_ON; } {is_off} { return T_OFF; } diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 152f33e..56fd2f8 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -29,6 +29,7 @@ #include "bitops.h" #include "cidr.h" #include +#include #include #include @@ -70,6 +71,7 @@ static void __max_dedicated_links_reached(void); %token T_FILTER T_ADDRESS T_PROTOCOL T_STATE T_ACCEPT T_IGNORE %token T_FROM T_USERSPACE T_KERNELSPACE T_EVENT_ITER_LIMIT T_DEFAULT %token T_NETLINK_OVERRUN_RESYNC T_NICE T_IPV4_DEST_ADDR T_IPV6_DEST_ADDR +%token T_SCHEDULER T_TYPE T_PRIO %token T_IP T_PATH_VAL %token T_NUMBER @@ -870,6 +872,7 @@ general_line: hashsize | filter | netlink_overrun_resync | nice + | scheduler ; netlink_buffer_size: T_BUFFER_SIZE T_NUMBER @@ -902,6 +905,33 @@ nice : T_NICE T_SIGNED_NUMBER conf.nice = $2; }; +scheduler : T_SCHEDULER '{' scheduler_options '}'; + +scheduler_options : + | scheduler_options scheduler_line + ; + +scheduler_line : T_TYPE T_STRING +{ + if (strcasecmp($2, "rr") == 0) { + conf.sched.type = SCHED_RR; + } else if (strcasecmp($2, "fifo") == 0) { + conf.sched.type = SCHED_FIFO; + } else { + print_err(CTD_CFG_ERROR, "unknown scheduler `%s'", $2); + exit(EXIT_FAILURE); + } +}; + +scheduler_line : T_PRIO T_NUMBER +{ + conf.sched.prio = $2; + if (conf.sched.prio < 0 || conf.sched.prio > 99) { + print_err(CTD_CFG_ERROR, "`Priority' must be [0, 99]\n", $2); + exit(EXIT_FAILURE); + } +}; + family : T_FAMILY T_STRING { if (strncmp($2, "IPv6", strlen("IPv6")) == 0) -- cgit v1.2.3 From 575fc906a302599cb9afeb136096dfd96bb57b17 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 14 Apr 2009 10:43:21 +0200 Subject: conntrack: fix English typo in output message This patch fixes an English typo in an output message. Signed-off-by: Pablo Neira Ayuso --- src/conntrack.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index 53089c7..8e28d86 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -670,7 +670,7 @@ event_sighandler(int s) } fprintf(stderr, "%s v%s (conntrack-tools): ", PROGNAME, VERSION); - fprintf(stderr, "%d flow events has been shown.\n", counter); + fprintf(stderr, "%d flow events have been shown.\n", counter); nfct_close(cth); exit(0); } @@ -1014,14 +1014,14 @@ static const int opt2attr[] = { }; static char exit_msg[NUMBER_OF_CMD][64] = { - [CT_LIST_BIT] = "%d flow entries has been shown.\n", - [CT_CREATE_BIT] = "%d flow entries has been created.\n", - [CT_UPDATE_BIT] = "%d flow entries has been updated.\n", - [CT_DELETE_BIT] = "%d flow entries has been deleted.\n", - [CT_GET_BIT] = "%d flow entries has been shown.\n", - [CT_EVENT_BIT] = "%d flow events has been shown.\n", - [EXP_LIST_BIT] = "%d expectations has been shown.\n", - [EXP_DELETE_BIT] = "%d expectations has been shown.\n", + [CT_LIST_BIT] = "%d flow entries have been shown.\n", + [CT_CREATE_BIT] = "%d flow entries have been created.\n", + [CT_UPDATE_BIT] = "%d flow entries have been updated.\n", + [CT_DELETE_BIT] = "%d flow entries have been deleted.\n", + [CT_GET_BIT] = "%d flow entries have been shown.\n", + [CT_EVENT_BIT] = "%d flow events have been shown.\n", + [EXP_LIST_BIT] = "%d expectations have been shown.\n", + [EXP_DELETE_BIT] = "%d expectations have been shown.\n", }; int main(int argc, char *argv[]) -- cgit v1.2.3 From a9554339451a0698e33b0964d0e8113f714470a4 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 18 Apr 2009 17:05:13 +0200 Subject: conntrack: add GRE support This patch adds GRE support for the command line tool conntrack. With this patch, we support all protocols available in the kernel. Signed-off-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 +#include +#include +#include /* For htons */ +#include + +#include "conntrack.h" + +enum { + CT_GRE_ORIG_SKEY = (1 << 0), + CT_GRE_ORIG_DKEY = (1 << 1), + CT_GRE_REPL_SKEY = (1 << 2), + CT_GRE_REPL_DKEY = (1 << 3), + CT_GRE_MASK_SKEY = (1 << 4), + CT_GRE_MASK_DKEY = (1 << 5), + CT_GRE_EXPTUPLE_SKEY = (1 << 6), + CT_GRE_EXPTUPLE_DKEY = (1 << 7) +}; + +#define GRE_OPT_MAX 11 +static struct option opts[GRE_OPT_MAX] = { + { "orig-key-src", .has_arg = 1, .val = '1' }, + { "srckey", .has_arg = 1, .val = '1' }, + { "orig-key-dst", .has_arg = 1, .val = '2' }, + { "dstkey", .has_arg = 1, .val = '2' }, + { "reply-key-src", .has_arg = 1, .val = '3' }, + { "reply-key-dst", .has_arg = 1, .val = '4' }, + { "mask-key-src", .has_arg = 1, .val = '5' }, + { "mask-key-dst", .has_arg = 1, .val = '6' }, + { "tuple-key-src", .has_arg = 1, .val = '7' }, + { "tuple-key-dst", .has_arg = 1, .val = '8' }, + {0, 0, 0, 0} +}; + +static const char *gre_optflags[GRE_OPT_MAX] = { + [0] = "srckey", + [1] = "dstkey", + [2] = "reply-key-src", + [3] = "reply-key-dst", + [4] = "mask-key-src", + [5] = "mask-key-dst", + [6] = "tuple-key-src", + [7] = "tuple-key-dst" +}; + +static void help(void) +{ + fprintf(stdout, " --orig-key-src\t\toriginal source key\n"); + fprintf(stdout, " --orig-key-dst\t\toriginal destination key\n"); + fprintf(stdout, " --reply-key-src\t\treply source key\n"); + fprintf(stdout, " --reply-key-dst\t\treply destination key\n"); + fprintf(stdout, " --mask-key-src\t\tmask source key\n"); + fprintf(stdout, " --mask-key-dst\t\tmask destination key\n"); + fprintf(stdout, " --tuple-key-src\t\texpectation tuple src key\n"); + fprintf(stdout, " --tuple-key-src\t\texpectation tuple dst key\n"); +} + +static char gre_commands_v_options[NUMBER_OF_CMD][GRE_OPT_MAX] = +{ + /* 1 2 3 4 5 6 7 8 */ +/*CT_LIST*/ {2,2,2,2,0,0,0,0}, +/*CT_CREATE*/ {3,3,3,3,0,0,0,0}, +/*CT_UPDATE*/ {2,2,2,2,0,0,0,0}, +/*CT_DELETE*/ {2,2,2,2,0,0,0,0}, +/*CT_GET*/ {3,3,3,3,0,0,0,0}, +/*CT_FLUSH*/ {0,0,0,0,0,0,0,0}, +/*CT_EVENT*/ {2,2,2,2,0,0,0,0}, +/*CT_VERSION*/ {0,0,0,0,0,0,0,0}, +/*CT_HELP*/ {0,0,0,0,0,0,0,0}, +/*EXP_LIST*/ {0,0,0,0,0,0,0,0}, +/*EXP_CREATE*/ {1,1,1,1,1,1,1,1}, +/*EXP_DELETE*/ {1,1,1,1,0,0,0,0}, +/*EXP_GET*/ {1,1,1,1,0,0,0,0}, +/*EXP_FLUSH*/ {0,0,0,0,0,0,0,0}, +/*EXP_EVENT*/ {0,0,0,0,0,0,0,0}, +}; + +static int parse_options(char c, + struct nf_conntrack *ct, + struct nf_conntrack *exptuple, + struct nf_conntrack *mask, + unsigned int *flags) +{ + switch(c) { + u_int16_t port; + case '1': + port = htons(strtoul(optarg, NULL, 0)); + nfct_set_attr_u16(ct, ATTR_ORIG_PORT_SRC, port); + nfct_set_attr_u8(ct, ATTR_ORIG_L4PROTO, IPPROTO_GRE); + *flags |= CT_GRE_ORIG_SKEY; + break; + case '2': + port = htons(strtoul(optarg, NULL, 0)); + nfct_set_attr_u16(ct, ATTR_ORIG_PORT_DST, port); + nfct_set_attr_u8(ct, ATTR_ORIG_L4PROTO, IPPROTO_GRE); + *flags |= CT_GRE_ORIG_DKEY; + break; + case '3': + port = htons(strtoul(optarg, NULL, 0)); + nfct_set_attr_u16(ct, ATTR_REPL_PORT_SRC, port); + nfct_set_attr_u8(ct, ATTR_REPL_L4PROTO, IPPROTO_GRE); + *flags |= CT_GRE_REPL_SKEY; + break; + case '4': + port = htons(strtoul(optarg, NULL, 0)); + nfct_set_attr_u16(ct, ATTR_REPL_PORT_DST, port); + nfct_set_attr_u8(ct, ATTR_REPL_L4PROTO, IPPROTO_GRE); + *flags |= CT_GRE_REPL_DKEY; + break; + case '5': + port = htons(strtoul(optarg, NULL, 0)); + nfct_set_attr_u16(mask, ATTR_ORIG_PORT_SRC, port); + nfct_set_attr_u8(mask, ATTR_ORIG_L4PROTO, IPPROTO_GRE); + *flags |= CT_GRE_MASK_SKEY; + break; + case '6': + port = htons(strtoul(optarg, NULL, 0)); + nfct_set_attr_u16(mask, ATTR_ORIG_PORT_DST, port); + nfct_set_attr_u8(mask, ATTR_ORIG_L4PROTO, IPPROTO_GRE); + *flags |= CT_GRE_MASK_DKEY; + break; + case '7': + port = htons(strtoul(optarg, NULL, 0)); + nfct_set_attr_u16(exptuple, ATTR_ORIG_PORT_SRC, port); + nfct_set_attr_u8(exptuple, ATTR_ORIG_L4PROTO, IPPROTO_GRE); + *flags |= CT_GRE_EXPTUPLE_SKEY; + break; + case '8': + port = htons(strtoul(optarg, NULL, 0)); + nfct_set_attr_u16(exptuple, ATTR_ORIG_PORT_DST, port); + nfct_set_attr_u8(exptuple, ATTR_ORIG_L4PROTO, IPPROTO_GRE); + *flags |= CT_GRE_EXPTUPLE_DKEY; + break; + } + return 1; +} + +#define GRE_VALID_FLAGS_MAX 2 +static unsigned int gre_valid_flags[GRE_VALID_FLAGS_MAX] = { + CT_GRE_ORIG_SKEY | CT_GRE_ORIG_DKEY, + CT_GRE_REPL_SKEY | CT_GRE_REPL_DKEY, +}; + +static void final_check(unsigned int flags, + unsigned int cmd, + struct nf_conntrack *ct) +{ + int ret, partial; + + ret = generic_opt_check(flags, GRE_OPT_MAX, + gre_commands_v_options[cmd], gre_optflags, + gre_valid_flags, GRE_VALID_FLAGS_MAX, &partial); + if (!ret) { + switch(partial) { + case -1: + case 0: + exit_error(PARAMETER_PROBLEM, "you have to specify " + "`--srckey' and " + "`--dstkey'"); + break; + case 1: + exit_error(PARAMETER_PROBLEM, "you have to specify " + "`--reply-src-key' and " + "`--reply-dst-key'"); + break; + } + } +} + +static struct ctproto_handler gre = { + .name = "gre", + .protonum = IPPROTO_GRE, + .parse_opts = parse_options, + .final_check = final_check, + .help = help, + .opts = opts, + .version = VERSION, +}; + +void register_gre(void) +{ + register_proto(&gre); +} diff --git a/include/conntrack.h b/include/conntrack.h index 30a5fb4..61e7581 100644 --- a/include/conntrack.h +++ b/include/conntrack.h @@ -200,6 +200,7 @@ extern void register_sctp(void); extern void register_dccp(void); extern void register_icmp(void); extern void register_icmpv6(void); +extern void register_gre(void); extern void register_unknown(void); #endif diff --git a/src/Makefile.am b/src/Makefile.am index 8a0c548..8a45bf9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -7,7 +7,7 @@ CLEANFILES = read_config_yy.c read_config_lex.c sbin_PROGRAMS = conntrack conntrackd conntrack_SOURCES = conntrack.c -conntrack_LDADD = ../extensions/libct_proto_tcp.la ../extensions/libct_proto_udp.la ../extensions/libct_proto_udplite.la ../extensions/libct_proto_icmp.la ../extensions/libct_proto_icmpv6.la ../extensions/libct_proto_sctp.la ../extensions/libct_proto_dccp.la ../extensions/libct_proto_unknown.la +conntrack_LDADD = ../extensions/libct_proto_tcp.la ../extensions/libct_proto_udp.la ../extensions/libct_proto_udplite.la ../extensions/libct_proto_icmp.la ../extensions/libct_proto_icmpv6.la ../extensions/libct_proto_sctp.la ../extensions/libct_proto_dccp.la ../extensions/libct_proto_gre.la ../extensions/libct_proto_unknown.la conntrack_LDFLAGS = $(all_libraries) @LIBNETFILTER_CONNTRACK_LIBS@ conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c rbtree.c \ diff --git a/src/conntrack.c b/src/conntrack.c index 8e28d86..42b5133 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -1056,6 +1056,7 @@ int main(int argc, char *argv[]) register_dccp(); register_icmp(); register_icmpv6(); + register_gre(); register_unknown(); /* disable explicit missing arguments error output from getopt_long */ -- cgit v1.2.3 From 400ae54438c4b85126f9fab0ae1dc067823b70f7 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 18 Apr 2009 19:36:38 +0200 Subject: sync: add support for SCTP state replication This patch adds initial support for SCTP state replication. Signed-off-by: Pablo Neira Ayuso --- doc/sync/alarm/conntrackd.conf | 1 + doc/sync/ftfw/conntrackd.conf | 1 + doc/sync/notrack/conntrackd.conf | 1 + include/network.h | 8 +++++++- src/build.c | 16 +++++++++++++++- src/parse.c | 16 +++++++++++++++- 6 files changed, 40 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/doc/sync/alarm/conntrackd.conf b/doc/sync/alarm/conntrackd.conf index 793e953..4607ad1 100644 --- a/doc/sync/alarm/conntrackd.conf +++ b/doc/sync/alarm/conntrackd.conf @@ -323,6 +323,7 @@ General { # Protocol Accept { TCP + SCTP } # diff --git a/doc/sync/ftfw/conntrackd.conf b/doc/sync/ftfw/conntrackd.conf index 6eb4475..3135c6c 100644 --- a/doc/sync/ftfw/conntrackd.conf +++ b/doc/sync/ftfw/conntrackd.conf @@ -332,6 +332,7 @@ General { # Protocol Accept { TCP + SCTP } # diff --git a/doc/sync/notrack/conntrackd.conf b/doc/sync/notrack/conntrackd.conf index e2085f7..ff8a8a2 100644 --- a/doc/sync/notrack/conntrackd.conf +++ b/doc/sync/notrack/conntrackd.conf @@ -313,6 +313,7 @@ General { # Protocol Accept { TCP + SCTP } # diff --git a/include/network.h b/include/network.h index b182339..06c0463 100644 --- a/include/network.h +++ b/include/network.h @@ -199,7 +199,7 @@ enum nta_attr { NTA_IPV6, /* struct nfct_attr_grp_ipv6 */ NTA_L4PROTO, /* uint8_t */ NTA_PORT, /* struct nfct_attr_grp_port */ - NTA_STATE = 4, /* uint8_t */ + NTA_STATE_TCP = 4, /* uint8_t */ NTA_STATUS, /* uint32_t */ NTA_TIMEOUT, /* uint32_t */ NTA_MARK, /* uint32_t */ @@ -212,6 +212,7 @@ enum nta_attr { NTA_SPAT_PORT, /* uint16_t */ NTA_DPAT_PORT, /* uint16_t */ NTA_NAT_SEQ_ADJ = 16, /* struct nta_attr_natseqadj */ + NTA_STATE_SCTP, /* struct nta_attr_sctp */ NTA_MAX }; @@ -224,6 +225,11 @@ struct nta_attr_natseqadj { uint32_t repl_seq_offset_after; }; +struct nta_attr_sctp { + uint8_t state; + uint32_t vtag_orig, vtag_repl; +}; + void build_payload(const struct nf_conntrack *ct, struct nethdr *n); int parse_payload(struct nf_conntrack *ct, struct nethdr *n, size_t remain); diff --git a/src/build.c b/src/build.c index 63a85db..6b0fad7 100644 --- a/src/build.c +++ b/src/build.c @@ -92,6 +92,17 @@ __build_natseqadj(const struct nf_conntrack *ct, struct nethdr *n) addattr(n, NTA_NAT_SEQ_ADJ, &data, sizeof(struct nta_attr_natseqadj)); } +static inline void +__build_sctp(const struct nf_conntrack *ct, struct nethdr *n) +{ + struct nta_attr_sctp data = { + .state = nfct_get_attr_u8(ct, ATTR_SCTP_STATE), + .vtag_orig = htonl(nfct_get_attr_u32(ct, ATTR_SCTP_VTAG_ORIG)), + .vtag_repl = htonl(nfct_get_attr_u32(ct, ATTR_SCTP_VTAG_REPL)), + }; + addattr(n, NTA_STATE_SCTP, &data, sizeof(struct nta_attr_sctp)); +} + static enum nf_conntrack_attr nat_type[] = { ATTR_ORIG_NAT_SEQ_CORRECTION_POS, ATTR_ORIG_NAT_SEQ_OFFSET_BEFORE, ATTR_ORIG_NAT_SEQ_OFFSET_AFTER, ATTR_REPL_NAT_SEQ_CORRECTION_POS, @@ -117,7 +128,10 @@ void build_payload(const struct nf_conntrack *ct, struct nethdr *n) __build_u32(ct, ATTR_STATUS, n, NTA_STATUS); if (nfct_attr_is_set(ct, ATTR_TCP_STATE)) - __build_u8(ct, ATTR_TCP_STATE, n, NTA_STATE); + __build_u8(ct, ATTR_TCP_STATE, n, NTA_STATE_TCP); + else if (nfct_attr_is_set(ct, ATTR_SCTP_STATE)) + __build_sctp(ct, n); + if (!CONFIG(commit_timeout) && nfct_attr_is_set(ct, ATTR_TIMEOUT)) __build_u32(ct, ATTR_TIMEOUT, n, NTA_TIMEOUT); if (nfct_attr_is_set(ct, ATTR_MARK)) diff --git a/src/parse.c b/src/parse.c index 76287fd..d14910a 100644 --- a/src/parse.c +++ b/src/parse.c @@ -29,6 +29,7 @@ static void parse_u16(struct nf_conntrack *ct, int attr, void *data); static void parse_u32(struct nf_conntrack *ct, int attr, void *data); static void parse_group(struct nf_conntrack *ct, int attr, void *data); static void parse_nat_seq_adj(struct nf_conntrack *ct, int attr, void *data); +static void parse_sctp(struct nf_conntrack *ct, int attr, void *data); struct parser { void (*parse)(struct nf_conntrack *ct, int attr, void *data); @@ -57,7 +58,7 @@ static struct parser h[NTA_MAX] = { .attr = ATTR_L4PROTO, .size = NTA_SIZE(sizeof(uint8_t)), }, - [NTA_STATE] = { + [NTA_STATE_TCP] = { .parse = parse_u8, .attr = ATTR_TCP_STATE, .size = NTA_SIZE(sizeof(uint8_t)), @@ -121,6 +122,10 @@ static struct parser h[NTA_MAX] = { .parse = parse_nat_seq_adj, .size = NTA_SIZE(sizeof(struct nta_attr_natseqadj)), }, + [NTA_STATE_SCTP] = { + .parse = parse_sctp, + .size = NTA_SIZE(sizeof(struct nta_attr_sctp)), + }, }; static void @@ -168,6 +173,15 @@ parse_nat_seq_adj(struct nf_conntrack *ct, int attr, void *data) ntohl(this->orig_seq_correction_pos)); } +static void +parse_sctp(struct nf_conntrack *ct, int attr, void *data) +{ + struct nta_attr_sctp *this = data; + nfct_set_attr_u8(ct, ATTR_SCTP_STATE, this->state); + nfct_set_attr_u32(ct, ATTR_SCTP_VTAG_ORIG, ntohl(this->vtag_orig)); + nfct_set_attr_u32(ct, ATTR_SCTP_VTAG_REPL, ntohl(this->vtag_repl)); +} + int parse_payload(struct nf_conntrack *ct, struct nethdr *net, size_t remain) { int len; -- cgit v1.2.3 From b808645ec71b7cc22cf5106b3d79625d07e6077c Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 24 Apr 2009 12:23:03 +0200 Subject: sync: add support for DCCP state replication This patch adds initial support for DCCP state replication. Signed-off-by: Pablo Neira Ayuso --- doc/sync/alarm/conntrackd.conf | 1 + doc/sync/ftfw/conntrackd.conf | 1 + doc/sync/notrack/conntrackd.conf | 1 + include/network.h | 5 +++++ src/build.c | 12 ++++++++++++ src/parse.c | 13 +++++++++++++ 6 files changed, 33 insertions(+) (limited to 'src') diff --git a/doc/sync/alarm/conntrackd.conf b/doc/sync/alarm/conntrackd.conf index 4607ad1..a108569 100644 --- a/doc/sync/alarm/conntrackd.conf +++ b/doc/sync/alarm/conntrackd.conf @@ -324,6 +324,7 @@ General { Protocol Accept { TCP SCTP + DCCP } # diff --git a/doc/sync/ftfw/conntrackd.conf b/doc/sync/ftfw/conntrackd.conf index 3135c6c..c1208f9 100644 --- a/doc/sync/ftfw/conntrackd.conf +++ b/doc/sync/ftfw/conntrackd.conf @@ -333,6 +333,7 @@ General { Protocol Accept { TCP SCTP + DCCP } # diff --git a/doc/sync/notrack/conntrackd.conf b/doc/sync/notrack/conntrackd.conf index ff8a8a2..b528fab 100644 --- a/doc/sync/notrack/conntrackd.conf +++ b/doc/sync/notrack/conntrackd.conf @@ -314,6 +314,7 @@ General { Protocol Accept { TCP SCTP + DCCP } # diff --git a/include/network.h b/include/network.h index 06c0463..2786585 100644 --- a/include/network.h +++ b/include/network.h @@ -213,6 +213,7 @@ enum nta_attr { NTA_DPAT_PORT, /* uint16_t */ NTA_NAT_SEQ_ADJ = 16, /* struct nta_attr_natseqadj */ NTA_STATE_SCTP, /* struct nta_attr_sctp */ + NTA_STATE_DCCP, /* struct nta_attr_dccp */ NTA_MAX }; @@ -230,6 +231,10 @@ struct nta_attr_sctp { uint32_t vtag_orig, vtag_repl; }; +struct nta_attr_dccp { + uint8_t state, role; +}; + void build_payload(const struct nf_conntrack *ct, struct nethdr *n); int parse_payload(struct nf_conntrack *ct, struct nethdr *n, size_t remain); diff --git a/src/build.c b/src/build.c index 6b0fad7..a02a912 100644 --- a/src/build.c +++ b/src/build.c @@ -103,6 +103,16 @@ __build_sctp(const struct nf_conntrack *ct, struct nethdr *n) addattr(n, NTA_STATE_SCTP, &data, sizeof(struct nta_attr_sctp)); } +static inline void +__build_dccp(const struct nf_conntrack *ct, struct nethdr *n) +{ + struct nta_attr_dccp data = { + .state = nfct_get_attr_u8(ct, ATTR_DCCP_STATE), + .role = nfct_get_attr_u8(ct, ATTR_DCCP_ROLE), + }; + addattr(n, NTA_STATE_DCCP, &data, sizeof(struct nta_attr_dccp)); +} + static enum nf_conntrack_attr nat_type[] = { ATTR_ORIG_NAT_SEQ_CORRECTION_POS, ATTR_ORIG_NAT_SEQ_OFFSET_BEFORE, ATTR_ORIG_NAT_SEQ_OFFSET_AFTER, ATTR_REPL_NAT_SEQ_CORRECTION_POS, @@ -131,6 +141,8 @@ void build_payload(const struct nf_conntrack *ct, struct nethdr *n) __build_u8(ct, ATTR_TCP_STATE, n, NTA_STATE_TCP); else if (nfct_attr_is_set(ct, ATTR_SCTP_STATE)) __build_sctp(ct, n); + else if (nfct_attr_is_set(ct, ATTR_DCCP_STATE)) + __build_dccp(ct, n); if (!CONFIG(commit_timeout) && nfct_attr_is_set(ct, ATTR_TIMEOUT)) __build_u32(ct, ATTR_TIMEOUT, n, NTA_TIMEOUT); diff --git a/src/parse.c b/src/parse.c index d14910a..100177b 100644 --- a/src/parse.c +++ b/src/parse.c @@ -30,6 +30,7 @@ static void parse_u32(struct nf_conntrack *ct, int attr, void *data); static void parse_group(struct nf_conntrack *ct, int attr, void *data); static void parse_nat_seq_adj(struct nf_conntrack *ct, int attr, void *data); static void parse_sctp(struct nf_conntrack *ct, int attr, void *data); +static void parse_dccp(struct nf_conntrack *ct, int attr, void *data); struct parser { void (*parse)(struct nf_conntrack *ct, int attr, void *data); @@ -126,6 +127,10 @@ static struct parser h[NTA_MAX] = { .parse = parse_sctp, .size = NTA_SIZE(sizeof(struct nta_attr_sctp)), }, + [NTA_STATE_DCCP] = { + .parse = parse_dccp, + .size = NTA_SIZE(sizeof(struct nta_attr_dccp)), + }, }; static void @@ -182,6 +187,14 @@ parse_sctp(struct nf_conntrack *ct, int attr, void *data) nfct_set_attr_u32(ct, ATTR_SCTP_VTAG_REPL, ntohl(this->vtag_repl)); } +static void +parse_dccp(struct nf_conntrack *ct, int attr, void *data) +{ + struct nta_attr_dccp *this = data; + nfct_set_attr_u8(ct, ATTR_DCCP_STATE, this->state); + nfct_set_attr_u8(ct, ATTR_DCCP_ROLE, this->role); +} + int parse_payload(struct nf_conntrack *ct, struct nethdr *net, size_t remain) { int len; -- cgit v1.2.3 From 91bf01ee31b754bb17f612ee13685ef0ffe9baa8 Mon Sep 17 00:00:00 2001 From: Samuel Gauthier Date: Tue, 12 May 2009 23:09:29 +0200 Subject: build: use uint16_t instead of uint32_t for uint16_t attributes Signed-off-by: Samuel Gauthier Signed-off-by: Pablo Neira Ayuso --- src/build.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/build.c b/src/build.c index a02a912..b2eeeee 100644 --- a/src/build.c +++ b/src/build.c @@ -51,7 +51,7 @@ __build_u8(const struct nf_conntrack *ct, int a, struct nethdr *n, int b) static inline void __build_u16(const struct nf_conntrack *ct, int a, struct nethdr *n, int b) { - uint32_t data = nfct_get_attr_u16(ct, a); + uint16_t data = nfct_get_attr_u16(ct, a); data = htons(data); addattr(n, b, &data, sizeof(uint16_t)); } -- cgit v1.2.3 From 0374398fd14bf587d80d9d31e361e266e69387c8 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 23 May 2009 12:09:06 +0200 Subject: conntrackd: add child process infrastructure This patch adds a simple infrastructure that allows to account the child processes that have been forked. This also includes a callback handler that can be registered that is called once the child process finishes. We can extended this later to include an alarm to limit the maximum lifetime of a forked child process. This is good to ensure that child processes behave timely. Signed-off-by: Pablo Neira Ayuso --- include/Makefile.am | 3 ++- include/process.h | 14 ++++++++++++++ src/Makefile.am | 2 +- src/process.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/run.c | 4 ++++ src/sync-mode.c | 11 ++++++----- 6 files changed, 82 insertions(+), 7 deletions(-) create mode 100644 include/process.h create mode 100644 src/process.c (limited to 'src') diff --git a/include/Makefile.am b/include/Makefile.am index f02ce89..0ea056c 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -3,5 +3,6 @@ noinst_HEADERS = alarm.h jhash.h cache.h linux_list.h linux_rbtree.h \ sync.h conntrackd.h local.h udp.h \ debug.h log.h hash.h mcast.h conntrack.h \ network.h filter.h queue.h vector.h cidr.h \ - traffic_stats.h netlink.h fds.h event.h bitops.h channel.h + traffic_stats.h netlink.h fds.h event.h bitops.h channel.h \ + process.h diff --git a/include/process.h b/include/process.h new file mode 100644 index 0000000..a7f07ea --- /dev/null +++ b/include/process.h @@ -0,0 +1,14 @@ +#ifndef _PROCESS_H_ +#define _PROCESS_H_ + +struct child_process { + struct list_head head; + int pid; + void (*cb)(void *data); + void *data; +}; + +int fork_process_new(void (*cb)(void *data), void *data); +int fork_process_delete(int pid); + +#endif diff --git a/src/Makefile.am b/src/Makefile.am index 8a45bf9..decc545 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -12,7 +12,7 @@ conntrack_LDFLAGS = $(all_libraries) @LIBNETFILTER_CONNTRACK_LIBS@ conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c rbtree.c \ local.c log.c mcast.c udp.c netlink.c vector.c \ - filter.c fds.c event.c \ + filter.c fds.c event.c process.c \ cache.c cache_iterators.c \ cache_timer.c cache_wt.c \ sync-mode.c sync-alarm.c sync-ftfw.c sync-notrack.c \ diff --git a/src/process.c b/src/process.c new file mode 100644 index 0000000..a89f388 --- /dev/null +++ b/src/process.c @@ -0,0 +1,55 @@ +/* + * (C) 2009 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "conntrackd.h" +#include "process.h" + +static LIST_HEAD(process_list); + +int fork_process_new(void (*cb)(void *data), void *data) +{ + struct child_process *c; + + c = calloc(sizeof(struct child_process), 1); + if (c == NULL) + return -1; + + c->cb = cb; + c->data = data; + + list_add(&c->head, &process_list); + + return fork(); +} + +int fork_process_delete(int pid) +{ + struct child_process *this, *tmp; + + list_for_each_entry_safe(this, tmp, &process_list, head) { + if (this->pid == pid) { + list_del(&this->head); + if (this->cb) { + this->cb(this->data); + } + free(this); + return 1; + } + } + return 0; +} diff --git a/src/run.c b/src/run.c index 6465699..09e2ae9 100644 --- a/src/run.c +++ b/src/run.c @@ -25,6 +25,7 @@ #include "alarm.h" #include "fds.h" #include "traffic_stats.h" +#include "process.h" #include #include @@ -77,6 +78,9 @@ static void child(int foo) STATE(stats).wait_failed++; break; } + /* delete process from list and run the callback */ + fork_process_delete(ret); + if (!WIFSIGNALED(status)) continue; diff --git a/src/sync-mode.c b/src/sync-mode.c index 298fcd2..0d35923 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -26,6 +26,7 @@ #include "fds.h" #include "event.h" #include "queue.h" +#include "process.h" #include #include @@ -391,28 +392,28 @@ static int local_handler_sync(int fd, int type, void *data) switch(type) { case DUMP_INTERNAL: - ret = fork(); + ret = fork_process_new(NULL, NULL); if (ret == 0) { cache_dump(STATE_SYNC(internal), fd, NFCT_O_PLAIN); exit(EXIT_SUCCESS); } break; case DUMP_EXTERNAL: - ret = fork(); + ret = fork_process_new(NULL, NULL); if (ret == 0) { cache_dump(STATE_SYNC(external), fd, NFCT_O_PLAIN); exit(EXIT_SUCCESS); } break; case DUMP_INT_XML: - ret = fork(); + ret = fork_process_new(NULL, NULL); if (ret == 0) { cache_dump(STATE_SYNC(internal), fd, NFCT_O_XML); exit(EXIT_SUCCESS); } break; case DUMP_EXT_XML: - ret = fork(); + ret = fork_process_new(NULL, NULL); if (ret == 0) { cache_dump(STATE_SYNC(external), fd, NFCT_O_XML); exit(EXIT_SUCCESS); @@ -421,7 +422,7 @@ static int local_handler_sync(int fd, int type, void *data) case COMMIT: /* delete the reset alarm if any before committing */ del_alarm(&STATE_SYNC(reset_cache_alarm)); - ret = fork(); + ret = fork_process_new(NULL, NULL); if (ret == 0) { dlog(LOG_NOTICE, "committing external cache"); cache_commit(STATE_SYNC(external)); -- cgit v1.2.3 From ef047d03613bf9fa105db009773136817e2ec4c6 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 23 May 2009 12:54:51 +0200 Subject: conntrackd: detect where the events comes from Since Linux kernel 2.6.29, ctnetlink reports the changes that have been done using ctnetlink. With this patch, conntrackd can recognize who is the origin of the event messages. For example, this is interesting to avoid a messy implicit bulk send during the commit of entries. Signed-off-by: Pablo Neira Ayuso --- include/Makefile.am | 2 +- include/cache.h | 4 ++- include/conntrackd.h | 6 ++--- include/origin.h | 14 +++++++++++ src/Makefile.am | 2 +- src/cache_iterators.c | 15 ++++------- src/origin.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/run.c | 18 ++++++++----- src/stats-mode.c | 9 ++++--- src/sync-mode.c | 51 ++++++++++++++++++++++++++++++------- 10 files changed, 157 insertions(+), 34 deletions(-) create mode 100644 include/origin.h create mode 100644 src/origin.c (limited to 'src') diff --git a/include/Makefile.am b/include/Makefile.am index 0ea056c..b72fb36 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -4,5 +4,5 @@ noinst_HEADERS = alarm.h jhash.h cache.h linux_list.h linux_rbtree.h \ debug.h log.h hash.h mcast.h conntrack.h \ network.h filter.h queue.h vector.h cidr.h \ traffic_stats.h netlink.h fds.h event.h bitops.h channel.h \ - process.h + process.h origin.h diff --git a/include/cache.h b/include/cache.h index 371170d..b6facdc 100644 --- a/include/cache.h +++ b/include/cache.h @@ -121,8 +121,10 @@ void *cache_get_extra(struct cache *, void *); void cache_iterate(struct cache *c, void *data, int (*iterate)(void *data1, void *data2)); /* iterators */ +struct nfct_handle; + void cache_dump(struct cache *c, int fd, int type); -void cache_commit(struct cache *c); +void cache_commit(struct cache *c, struct nfct_handle *h); void cache_flush(struct cache *c); void cache_bulk(struct cache *c); diff --git a/include/conntrackd.h b/include/conntrackd.h index 013ec4f..81cfd51 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -218,9 +218,9 @@ struct ct_mode { struct nf_conntrack *ct, void *data); int (*purge)(void); - void (*event_new)(struct nf_conntrack *ct); - void (*event_upd)(struct nf_conntrack *ct); - int (*event_dst)(struct nf_conntrack *ct); + void (*event_new)(struct nf_conntrack *ct, int origin); + void (*event_upd)(struct nf_conntrack *ct, int origin); + int (*event_dst)(struct nf_conntrack *ct, int origin); }; /* conntrackd modes */ diff --git a/include/origin.h b/include/origin.h new file mode 100644 index 0000000..b2d1823 --- /dev/null +++ b/include/origin.h @@ -0,0 +1,14 @@ +#ifndef _ORIGIN_H_ +#define _ORIGIN_H_ + +enum { + CTD_ORIGIN_NOT_ME = 0, /* this event comes from the kernel or + any process, but not conntrackd */ + CTD_ORIGIN_COMMIT, /* event comes from committer */ +}; + +int origin_register(struct nfct_handle *h, int origin_type); +int origin_find(const struct nlmsghdr *nlh); +int origin_unregister(struct nfct_handle *h); + +#endif diff --git a/src/Makefile.am b/src/Makefile.am index decc545..c338fee 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -12,7 +12,7 @@ conntrack_LDFLAGS = $(all_libraries) @LIBNETFILTER_CONNTRACK_LIBS@ conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c rbtree.c \ local.c log.c mcast.c udp.c netlink.c vector.c \ - filter.c fds.c event.c process.c \ + filter.c fds.c event.c process.c origin.c \ cache.c cache_iterators.c \ cache_timer.c cache_wt.c \ sync-mode.c sync-alarm.c sync-ftfw.c sync-notrack.c \ diff --git a/src/cache_iterators.c b/src/cache_iterators.c index dfccc68..542ab91 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -175,20 +175,16 @@ static int do_commit_master(void *data, struct hashtable_node *n) } /* no need to clone, called from child process */ -void cache_commit(struct cache *c) +void cache_commit(struct cache *c, struct nfct_handle *h) { unsigned int commit_ok = c->stats.commit_ok; unsigned int commit_fail = c->stats.commit_fail; - struct __commit_container tmp; + struct __commit_container tmp = { + .h = h, + .c = c, + }; struct timeval commit_start, commit_stop, res; - tmp.h = nfct_open(CONNTRACK, 0); - if (tmp.h == NULL) { - dlog(LOG_ERR, "can't create handler to commit entries"); - return; - } - tmp.c = c; - gettimeofday(&commit_start, NULL); /* commit master conntrack first, then related ones */ hashtable_iterate(c->h, &tmp, do_commit_master); @@ -206,7 +202,6 @@ void cache_commit(struct cache *c) if (commit_fail) dlog(LOG_NOTICE, "%u entries can't be " "committed", commit_fail); - nfct_close(tmp.h); dlog(LOG_NOTICE, "commit has taken %lu.%06lu seconds", res.tv_sec, res.tv_usec); diff --git a/src/origin.c b/src/origin.c new file mode 100644 index 0000000..3c65f3d --- /dev/null +++ b/src/origin.c @@ -0,0 +1,70 @@ +/* + * (C) 2009 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "conntrackd.h" +#include "origin.h" + +static LIST_HEAD(origin_list); + +struct origin { + struct list_head head; + unsigned int nl_portid; + int type; +}; + +/* register a Netlink socket as origin of possible events */ +int origin_register(struct nfct_handle *h, int origin_type) +{ + struct origin *nlp; + + nlp = calloc(sizeof(struct origin), 1); + if (nlp == NULL) + return -1; + + nlp->nl_portid = nfnl_portid(nfct_nfnlh(h)); + nlp->type = origin_type; + + list_add(&nlp->head, &origin_list); + return 0; +} + +/* look up for the origin of this Netlink event */ +int origin_find(const struct nlmsghdr *nlh) +{ + struct origin *this; + + list_for_each_entry(this, &origin_list, head) { + if (this->nl_portid == nlh->nlmsg_pid) { + return this->type; + } + } + return CTD_ORIGIN_NOT_ME; +} + +int origin_unregister(struct nfct_handle *h) +{ + struct origin *this, *tmp; + + list_for_each_entry_safe(this, tmp, &origin_list, head) { + if (this->nl_portid == nfnl_portid(nfct_nfnlh(h))) { + list_del(&this->head); + free(this); + return 1; + } + } + return 0; +} diff --git a/src/run.c b/src/run.c index 09e2ae9..e54764c 100644 --- a/src/run.c +++ b/src/run.c @@ -26,6 +26,7 @@ #include "fds.h" #include "traffic_stats.h" #include "process.h" +#include "origin.h" #include #include @@ -228,10 +229,13 @@ static void do_polling_alarm(struct alarm_block *a, void *data) add_alarm(&STATE(polling_alarm), CONFIG(poll_kernel_secs), 0); } -static int event_handler(enum nf_conntrack_msg_type type, +static int event_handler(const struct nlmsghdr *nlh, + enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data) { + int origin_type; + STATE(stats).nl_events_received++; /* skip user-space filtering if already do it in the kernel */ @@ -240,15 +244,17 @@ static int event_handler(enum nf_conntrack_msg_type type, goto out; } + origin_type = origin_find(nlh); + switch(type) { case NFCT_T_NEW: - STATE(mode)->event_new(ct); + STATE(mode)->event_new(ct, origin_type); break; case NFCT_T_UPDATE: - STATE(mode)->event_upd(ct); + STATE(mode)->event_upd(ct, origin_type); break; case NFCT_T_DESTROY: - if (STATE(mode)->event_dst(ct)) + if (STATE(mode)->event_dst(ct, origin_type)) update_traffic_stats(ct); break; default: @@ -334,8 +340,8 @@ init(void) dlog(LOG_ERR, "no ctnetlink kernel support?"); return -1; } - nfct_callback_register(STATE(event), NFCT_T_ALL, - event_handler, NULL); + nfct_callback_register2(STATE(event), NFCT_T_ALL, + event_handler, NULL); register_fd(nfct_fd(STATE(event)), STATE(fds)); } diff --git a/src/stats-mode.c b/src/stats-mode.c index af1c136..b84c7a1 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -141,7 +141,8 @@ static int purge_stats(void) return 0; } -static void event_new_stats(struct nf_conntrack *ct) +static void +event_new_stats(struct nf_conntrack *ct, int origin) { int id; struct cache_object *obj; @@ -162,13 +163,15 @@ static void event_new_stats(struct nf_conntrack *ct) return; } -static void event_update_stats(struct nf_conntrack *ct) +static void +event_update_stats(struct nf_conntrack *ct, int origin) { nfct_attr_unset(ct, ATTR_TIMEOUT); cache_update_force(STATE_STATS(cache), ct); } -static int event_destroy_stats(struct nf_conntrack *ct) +static int +event_destroy_stats(struct nf_conntrack *ct, int origin) { int id; struct cache_object *obj; diff --git a/src/sync-mode.c b/src/sync-mode.c index 0d35923..91e028e 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -27,6 +27,7 @@ #include "event.h" #include "queue.h" #include "process.h" +#include "origin.h" #include #include @@ -385,6 +386,14 @@ static void dump_stats_sync_extended(int fd) send(fd, buf, size, 0); } +/* this is called once the committer process has finished */ +static void commit_done_cb(void *data) +{ + struct nfct_handle *h = data; + origin_unregister(h); + nfct_close(h); +} + /* handler for requests coming via UNIX socket */ static int local_handler_sync(int fd, int type, void *data) { @@ -419,16 +428,29 @@ static int local_handler_sync(int fd, int type, void *data) exit(EXIT_SUCCESS); } break; - case COMMIT: + case COMMIT: { + struct nfct_handle *h; + /* delete the reset alarm if any before committing */ del_alarm(&STATE_SYNC(reset_cache_alarm)); - ret = fork_process_new(NULL, NULL); + + /* disposable handler for commit operations */ + h = nfct_open(CONNTRACK, 0); + if (h == NULL) { + dlog(LOG_ERR, "can't create handler to commit"); + break; + } + origin_register(h, CTD_ORIGIN_COMMIT); + + /* fork new process and insert it the process list */ + ret = fork_process_new(commit_done_cb, h); if (ret == 0) { dlog(LOG_NOTICE, "committing external cache"); - cache_commit(STATE_SYNC(external)); + cache_commit(STATE_SYNC(external), h); exit(EXIT_SUCCESS); } break; + } case RESET_TIMERS: if (!alarm_pending(&STATE_SYNC(reset_cache_alarm))) { dlog(LOG_NOTICE, "flushing conntrack table in %d secs", @@ -557,7 +579,8 @@ static int resync_sync(enum nf_conntrack_msg_type type, return NFCT_CB_CONTINUE; } -static void event_new_sync(struct nf_conntrack *ct) +static void +event_new_sync(struct nf_conntrack *ct, int origin) { struct cache_object *obj; int id; @@ -578,7 +601,11 @@ retry: cache_object_free(obj); return; } - sync_send(obj, NET_T_STATE_NEW); + /* only synchronize events that have been triggered by other + * processes or the kernel, but don't propagate events that + * have been triggered by conntrackd itself, eg. commits. */ + if (origin == CTD_ORIGIN_NOT_ME) + sync_send(obj, NET_T_STATE_NEW); } else { cache_del(STATE_SYNC(internal), obj); cache_object_free(obj); @@ -586,7 +613,8 @@ retry: } } -static void event_update_sync(struct nf_conntrack *ct) +static void +event_update_sync(struct nf_conntrack *ct, int origin) { struct cache_object *obj; @@ -594,21 +622,26 @@ static void event_update_sync(struct nf_conntrack *ct) if (obj == NULL) return; - sync_send(obj, NET_T_STATE_UPD); + if (origin == CTD_ORIGIN_NOT_ME) + sync_send(obj, NET_T_STATE_UPD); } -static int event_destroy_sync(struct nf_conntrack *ct) +static int +event_destroy_sync(struct nf_conntrack *ct, int origin) { struct cache_object *obj; int id; + /* we don't synchronize events for objects that are not in the cache */ obj = cache_find(STATE_SYNC(internal), ct, &id); if (obj == NULL) return 0; if (obj->status != C_OBJ_DEAD) { cache_object_set_status(obj, C_OBJ_DEAD); - sync_send(obj, NET_T_STATE_DEL); + if (origin == CTD_ORIGIN_NOT_ME) { + sync_send(obj, NET_T_STATE_DEL); + } cache_object_put(obj); } return 1; -- cgit v1.2.3 From 6f5666a29cb7cbff08ce926ee1edb84a311ff6ee Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 23 May 2009 20:34:41 +0200 Subject: conntrackd: flush operation use the child process and origin infrastructure With this patch, the flush operation is performed by a child process. Thus, the parent process digests destroy events that ctnetlink reports back and, thanks to the origin infrastructure, we skip the messy implicit synchronization that are triggered by such events. This patch requires a Linux kernel >= 2.6.29 to benefit from this change, otherwise it has no effect. Signed-off-by: Pablo Neira Ayuso --- include/origin.h | 1 + src/run.c | 29 +++++++++++++++++++++++++++-- src/sync-mode.c | 28 +++++++++++++++++++++++++++- 3 files changed, 55 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/include/origin.h b/include/origin.h index b2d1823..89308f3 100644 --- a/include/origin.h +++ b/include/origin.h @@ -5,6 +5,7 @@ enum { CTD_ORIGIN_NOT_ME = 0, /* this event comes from the kernel or any process, but not conntrackd */ CTD_ORIGIN_COMMIT, /* event comes from committer */ + CTD_ORIGIN_FLUSH, /* event comes from flush */ }; int origin_register(struct nfct_handle *h, int origin_type); diff --git a/src/run.c b/src/run.c index e54764c..990b202 100644 --- a/src/run.c +++ b/src/run.c @@ -181,6 +181,13 @@ static void dump_stats_runtime(int fd) send(fd, buf, size, 0); } +static void flush_done_cb(void *data) +{ + struct nfct_handle *h = data; + origin_unregister(h); + nfct_close(h); +} + void local_handler(int fd, void *data) { int ret; @@ -195,11 +202,29 @@ void local_handler(int fd, void *data) return; switch(type) { - case FLUSH_MASTER: + case FLUSH_MASTER: { + struct nfct_handle *h; + + /* disposable flusher handler */ + h = nfct_open(CONNTRACK, 0); + if (h == NULL) { + dlog(LOG_ERR, "cannot open flusher handler"); + return; + } + /* register this handler as the origin of a flush operation */ + origin_register(h, CTD_ORIGIN_FLUSH); + STATE(stats).nl_kernel_table_flush++; dlog(LOG_NOTICE, "flushing kernel conntrack table"); - nl_flush_conntrack_table(STATE(request)); + + /* fork a child process that performs the flush operation, + * meanwhile the parent process handles events. */ + if (fork_process_new(flush_done_cb, h) == 0) { + nl_flush_conntrack_table(h); + exit(EXIT_SUCCESS); + } return; + } case RESYNC_MASTER: STATE(stats).nl_kernel_table_resync++; dlog(LOG_NOTICE, "resync with master table"); diff --git a/src/sync-mode.c b/src/sync-mode.c index 91e028e..a0ba830 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -203,11 +203,37 @@ static void interface_handler(void) interface_candidate(); } +/* this is called once the flusher process has finished */ +static void flush_done_cb(void *data) +{ + struct nfct_handle *h = data; + origin_unregister(h); + nfct_close(h); +} + static void do_reset_cache_alarm(struct alarm_block *a, void *data) { + struct nfct_handle *h; + + /* disposable flusher handler */ + h = nfct_open(CONNTRACK, 0); + if (h == NULL) { + dlog(LOG_ERR, "cannot open flusher handler"); + return; + } + /* register this handler as the origin of a flush operation */ + origin_register(h, CTD_ORIGIN_FLUSH); + STATE(stats).nl_kernel_table_flush++; dlog(LOG_NOTICE, "flushing kernel conntrack table (scheduled)"); - nl_flush_conntrack_table(STATE(request)); + + /* fork a child process that performs the flush operation, + * meanwhile the parent process handles events. */ + if (fork_process_new(flush_done_cb, h) == 0) { + nl_flush_conntrack_table(h); + exit(EXIT_SUCCESS); + } + /* this is not required if events don't get lost */ cache_flush(STATE_SYNC(internal)); } -- cgit v1.2.3 From 95c587ae01373ded13d696b155c7f277030a03d3 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 23 May 2009 20:58:55 +0200 Subject: conntrackd: remove the cache write-through policy This patch removes the cache write-through clause. This feature remained undocumented although some has found it looking at the source code. This feature has remained in the tree for quite some time although it has several limitations. Moreover, it is specifically broken and dangerous for Linux kernels >= 2.6.29 since it generates loops in the synchronization. We do this removal first to prepare the introduction of a feature to bypass the external cache. Signed-off-by: Pablo Neira Ayuso --- include/cache.h | 4 --- include/conntrackd.h | 1 - src/Makefile.am | 2 +- src/cache.c | 1 - src/cache_wt.c | 79 ---------------------------------------------------- src/read_config_yy.y | 6 ++-- src/sync-mode.c | 4 --- 7 files changed, 5 insertions(+), 92 deletions(-) delete mode 100644 src/cache_wt.c (limited to 'src') diff --git a/include/cache.h b/include/cache.h index b6facdc..5df7aa9 100644 --- a/include/cache.h +++ b/include/cache.h @@ -12,9 +12,6 @@ enum { TIMER_FEATURE = 0, TIMER = (1 << TIMER_FEATURE), - WRITE_THROUGH_FEATURE = 1, - WRITE_THROUGH = (1 << WRITE_THROUGH_FEATURE), - __CACHE_MAX_FEATURE }; #define CACHE_MAX_FEATURE __CACHE_MAX_FEATURE @@ -48,7 +45,6 @@ struct cache_feature { extern struct cache_feature lifetime_feature; extern struct cache_feature timer_feature; -extern struct cache_feature writethrough_feature; #define CACHE_MAX_NAMELEN 32 diff --git a/include/conntrackd.h b/include/conntrackd.h index 81cfd51..5a9e385 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -91,7 +91,6 @@ struct ct_conf { unsigned int resend_queue_size; /* FTFW protocol */ unsigned int window_size; int poll_kernel_secs; - int cache_write_through; int filter_from_kernelspace; int event_iterations_limit; struct { diff --git a/src/Makefile.am b/src/Makefile.am index c338fee..1c8b34f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -14,7 +14,7 @@ conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c rbtree.c \ local.c log.c mcast.c udp.c netlink.c vector.c \ filter.c fds.c event.c process.c origin.c \ cache.c cache_iterators.c \ - cache_timer.c cache_wt.c \ + cache_timer.c \ sync-mode.c sync-alarm.c sync-ftfw.c sync-notrack.c \ traffic_stats.c stats-mode.c \ network.c cidr.c \ diff --git a/src/cache.c b/src/cache.c index 318b8ec..e4a024b 100644 --- a/src/cache.c +++ b/src/cache.c @@ -95,7 +95,6 @@ static int compare(const void *data1, const void *data2) struct cache_feature *cache_feature[CACHE_MAX_FEATURE] = { [TIMER_FEATURE] = &timer_feature, - [WRITE_THROUGH_FEATURE] = &writethrough_feature, }; struct cache *cache_create(const char *name, diff --git a/src/cache_wt.c b/src/cache_wt.c deleted file mode 100644 index 34fe82e..0000000 --- a/src/cache_wt.c +++ /dev/null @@ -1,79 +0,0 @@ -/* - * (C) 2007 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "conntrackd.h" -#include "cache.h" -#include "netlink.h" -#include "log.h" - -#include -#include - -static void add_wt(struct cache_object *obj) -{ - int ret; - - ret = nl_get_conntrack(STATE(request), obj->ct); - switch (ret) { - case -1: - dlog(LOG_ERR, "cache_wt problem: %s", strerror(errno)); - dlog_ct(STATE(log), obj->ct, NFCT_O_PLAIN); - break; - case 0: - if (nl_create_conntrack(STATE(dump), obj->ct, 0) == -1) { - dlog(LOG_ERR, "cache_wt create: %s", strerror(errno)); - dlog_ct(STATE(log), obj->ct, NFCT_O_PLAIN); - } - break; - case 1: - if (nl_update_conntrack(STATE(dump), obj->ct, 0) == -1) { - dlog(LOG_ERR, "cache_wt crt-upd: %s", strerror(errno)); - dlog_ct(STATE(log), obj->ct, NFCT_O_PLAIN); - } - break; - } -} - -static void upd_wt(struct cache_object *obj) -{ - if (nl_update_conntrack(STATE(dump), obj->ct, 0) == -1) { - dlog(LOG_ERR, "cache_wt update:%s", strerror(errno)); - dlog_ct(STATE(log), obj->ct, NFCT_O_PLAIN); - } -} - -static void writethrough_add(struct cache_object *obj, void *data) -{ - add_wt(obj); -} - -static void writethrough_update(struct cache_object *obj, void *data) -{ - upd_wt(obj); -} - -static void writethrough_destroy(struct cache_object *obj, void *data) -{ - nl_destroy_conntrack(STATE(dump), obj->ct); -} - -struct cache_feature writethrough_feature = { - .add = writethrough_add, - .update = writethrough_update, - .destroy = writethrough_destroy, -}; diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 56fd2f8..cab7799 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -842,12 +842,14 @@ tcp_state: T_LISTEN cache_writethrough: T_WRITE_THROUGH T_ON { - conf.cache_write_through = 1; + print_err(CTD_CFG_WARN, "`CacheWriteThrough' clause is obsolete, " + "ignoring"); }; cache_writethrough: T_WRITE_THROUGH T_OFF { - conf.cache_write_through = 0; + print_err(CTD_CFG_WARN, "`CacheWriteThrough' clause is obsolete, " + "ignoring"); }; general: T_GENERAL '{' general_list '}'; diff --git a/src/sync-mode.c b/src/sync-mode.c index a0ba830..699a585 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -274,10 +274,6 @@ static int init_sync(void) return -1; } - /* straight forward commit of conntrack to kernel space */ - if (CONFIG(cache_write_through)) - STATE_SYNC(sync)->external_cache_flags |= WRITE_THROUGH; - STATE_SYNC(external) = cache_create("external", STATE_SYNC(sync)->external_cache_flags, -- cgit v1.2.3 From 989509af8783c38406a2cda4ce047828f2553833 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 24 May 2009 21:10:17 +0200 Subject: conntrackd: remove redudant declaration of Port in the parser This patch is a cleanup, it removes a redudant declaration in the parser. Signed-off-by: Pablo Neira Ayuso --- src/read_config_lex.l | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/read_config_lex.l b/src/read_config_lex.l index 3d5913e..cd03ad4 100644 --- a/src/read_config_lex.l +++ b/src/read_config_lex.l @@ -63,7 +63,6 @@ notrack [N|n][O|o][T|t][R|r][A|a][C|c][K|k] "IPv4_interface" { return T_IPV4_IFACE; } "IPv6_interface" { return T_IPV6_IFACE; } "Interface" { return T_IFACE; } -"Port" { return T_PORT; } "Multicast" { return T_MULTICAST; } "UDP" { return T_UDP; } "HashSize" { return T_HASHSIZE; } -- cgit v1.2.3 From c72da10b9b1193f7ecb84a5db7dbf943891b9e96 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 10 Jun 2009 01:45:43 +0200 Subject: conntrackd: remove unused request nfct handler This patch is a cleanup, it removes an unused nfct handler. This removal is due to recent commits that has obsolete it. Signed-off-by: Pablo Neira Ayuso --- include/conntrackd.h | 1 - src/run.c | 10 ---------- 2 files changed, 11 deletions(-) (limited to 'src') diff --git a/include/conntrackd.h b/include/conntrackd.h index 5a9e385..0546855 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -119,7 +119,6 @@ struct ct_general_state { int event_iterations_limit; struct nfct_handle *dump; /* dump handler */ - struct nfct_handle *request; /* request handler */ struct nfct_handle *resync; /* resync handler */ struct nfct_handle *get; /* get handler */ int get_retval; /* hackish */ diff --git a/src/run.c b/src/run.c index 990b202..21ff715 100644 --- a/src/run.c +++ b/src/run.c @@ -47,7 +47,6 @@ void killer(int foo) nfct_close(STATE(resync)); nfct_close(STATE(get)); - nfct_close(STATE(request)); if (STATE(us_filter)) ct_filter_destroy(STATE(us_filter)); @@ -408,15 +407,6 @@ init(void) } nfct_callback_register(STATE(get), NFCT_T_ALL, get_handler, NULL); - /* no callback, it does not do anything with the output */ - STATE(request) = nfct_open(CONNTRACK, 0); - if (STATE(request) == NULL) { - dlog(LOG_ERR, "can't open netlink handler: %s", - strerror(errno)); - dlog(LOG_ERR, "no ctnetlink kernel support?"); - return -1; - } - if (CONFIG(flags) & CTD_POLL) { init_alarm(&STATE(polling_alarm), NULL, do_polling_alarm); add_alarm(&STATE(polling_alarm), CONFIG(poll_kernel_secs), 0); -- cgit v1.2.3 From 6cd381e590bf28c180c089b47667defe4b6ff3eb Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 11 Jun 2009 19:26:49 +0200 Subject: conntrackd: add missing initialization of PID in process infrastructure In 0374398fd14bf587d80d9d31e361e266e69387c8, I introduced the process infrastructure. However, that patch missed the PID initialization. Without this patch, the process structures are never released. Signed-off-by: Pablo Neira Ayuso --- src/process.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/process.c b/src/process.c index a89f388..70972fe 100644 --- a/src/process.c +++ b/src/process.c @@ -24,6 +24,7 @@ static LIST_HEAD(process_list); int fork_process_new(void (*cb)(void *data), void *data) { struct child_process *c; + int pid; c = calloc(sizeof(struct child_process), 1); if (c == NULL) @@ -31,10 +32,12 @@ int fork_process_new(void (*cb)(void *data), void *data) c->cb = cb; c->data = data; + c->pid = pid = fork(); - list_add(&c->head, &process_list); + if (c->pid > 0) + list_add(&c->head, &process_list); - return fork(); + return pid; } int fork_process_delete(int pid) -- cgit v1.2.3 From 0121fd74b805a6490f005c835b3994fa06487395 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 11 Jun 2009 19:27:44 +0200 Subject: conntrackd: block signals during the access to the process list A child process may finish while we are walking on the process list. This fixes possible concurrency problems. Signed-off-by: Pablo Neira Ayuso --- src/process.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/process.c b/src/process.c index 70972fe..31e6e6f 100644 --- a/src/process.c +++ b/src/process.c @@ -16,6 +16,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include #include "conntrackd.h" #include "process.h" @@ -26,9 +27,14 @@ int fork_process_new(void (*cb)(void *data), void *data) struct child_process *c; int pid; + /* block SIGCHLD to avoid the access of the list concurrently */ + sigprocmask(SIG_BLOCK, &STATE(block), NULL); + c = calloc(sizeof(struct child_process), 1); - if (c == NULL) + if (c == NULL) { + sigprocmask(SIG_UNBLOCK, &STATE(block), NULL); return -1; + } c->cb = cb; c->data = data; @@ -37,6 +43,8 @@ int fork_process_new(void (*cb)(void *data), void *data) if (c->pid > 0) list_add(&c->head, &process_list); + sigprocmask(SIG_UNBLOCK, &STATE(block), NULL); + return pid; } -- cgit v1.2.3 From 5e696e022d8383bc7abe6e6ba37c2664679fe81f Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 11 Jun 2009 19:34:50 +0200 Subject: conntrackd: allow to limit the number of simultaneous child processes This patch allows to limit the number of simultaneous child processes. This is required by the next patch that replaces disposable handlers to commit and flush with permanent handlers. Signed-off-by: Pablo Neira Ayuso --- include/process.h | 11 ++++++++++- src/process.c | 16 ++++++++++++++-- src/run.c | 3 ++- src/sync-mode.c | 14 ++++++++------ 4 files changed, 34 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/include/process.h b/include/process.h index a7f07ea..9d29f22 100644 --- a/include/process.h +++ b/include/process.h @@ -1,14 +1,23 @@ #ifndef _PROCESS_H_ #define _PROCESS_H_ +enum process_type { + CTD_PROC_ANY, /* any type */ + CTD_PROC_FLUSH, /* flush process */ + CTD_PROC_COMMIT, /* commit process */ +}; + +#define CTD_PROC_F_EXCL (1 << 0) /* only one process at a time */ + struct child_process { struct list_head head; int pid; + int type; void (*cb)(void *data); void *data; }; -int fork_process_new(void (*cb)(void *data), void *data); +int fork_process_new(int type, int flags, void (*cb)(void *data), void *data); int fork_process_delete(int pid); #endif diff --git a/src/process.c b/src/process.c index 31e6e6f..c378f7a 100644 --- a/src/process.c +++ b/src/process.c @@ -22,20 +22,32 @@ static LIST_HEAD(process_list); -int fork_process_new(void (*cb)(void *data), void *data) +int fork_process_new(int type, int flags, void (*cb)(void *data), void *data) { - struct child_process *c; + struct child_process *c, *this; int pid; /* block SIGCHLD to avoid the access of the list concurrently */ sigprocmask(SIG_BLOCK, &STATE(block), NULL); + /* We only want one process of this type at the same time. This is + * useful if you want to prevent two child processes from accessing + * a shared descriptor at the same time. */ + if (flags & CTD_PROC_F_EXCL) { + list_for_each_entry(this, &process_list, head) { + if (this->type == type) { + sigprocmask(SIG_UNBLOCK, &STATE(block), NULL); + return -1; + } + } + } c = calloc(sizeof(struct child_process), 1); if (c == NULL) { sigprocmask(SIG_UNBLOCK, &STATE(block), NULL); return -1; } + c->type = type; c->cb = cb; c->data = data; c->pid = pid = fork(); diff --git a/src/run.c b/src/run.c index 21ff715..a0aea4f 100644 --- a/src/run.c +++ b/src/run.c @@ -218,7 +218,8 @@ void local_handler(int fd, void *data) /* fork a child process that performs the flush operation, * meanwhile the parent process handles events. */ - if (fork_process_new(flush_done_cb, h) == 0) { + if (fork_process_new(CTD_PROC_FLUSH, CTD_PROC_F_EXCL, + flush_done_cb, h) == 0) { nl_flush_conntrack_table(h); exit(EXIT_SUCCESS); } diff --git a/src/sync-mode.c b/src/sync-mode.c index 699a585..2da3604 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -229,7 +229,8 @@ static void do_reset_cache_alarm(struct alarm_block *a, void *data) /* fork a child process that performs the flush operation, * meanwhile the parent process handles events. */ - if (fork_process_new(flush_done_cb, h) == 0) { + if (fork_process_new(CTD_PROC_FLUSH, CTD_PROC_F_EXCL, + flush_done_cb, h) == 0) { nl_flush_conntrack_table(h); exit(EXIT_SUCCESS); } @@ -423,28 +424,28 @@ static int local_handler_sync(int fd, int type, void *data) switch(type) { case DUMP_INTERNAL: - ret = fork_process_new(NULL, NULL); + ret = fork_process_new(CTD_PROC_ANY, 0, NULL, NULL); if (ret == 0) { cache_dump(STATE_SYNC(internal), fd, NFCT_O_PLAIN); exit(EXIT_SUCCESS); } break; case DUMP_EXTERNAL: - ret = fork_process_new(NULL, NULL); + ret = fork_process_new(CTD_PROC_ANY, 0, NULL, NULL); if (ret == 0) { cache_dump(STATE_SYNC(external), fd, NFCT_O_PLAIN); exit(EXIT_SUCCESS); } break; case DUMP_INT_XML: - ret = fork_process_new(NULL, NULL); + ret = fork_process_new(CTD_PROC_ANY, 0, NULL, NULL); if (ret == 0) { cache_dump(STATE_SYNC(internal), fd, NFCT_O_XML); exit(EXIT_SUCCESS); } break; case DUMP_EXT_XML: - ret = fork_process_new(NULL, NULL); + ret = fork_process_new(CTD_PROC_ANY, 0, NULL, NULL); if (ret == 0) { cache_dump(STATE_SYNC(external), fd, NFCT_O_XML); exit(EXIT_SUCCESS); @@ -465,7 +466,8 @@ static int local_handler_sync(int fd, int type, void *data) origin_register(h, CTD_ORIGIN_COMMIT); /* fork new process and insert it the process list */ - ret = fork_process_new(commit_done_cb, h); + ret = fork_process_new(CTD_PROC_COMMIT, CTD_PROC_F_EXCL, + commit_done_cb, h); if (ret == 0) { dlog(LOG_NOTICE, "committing external cache"); cache_commit(STATE_SYNC(external), h); -- cgit v1.2.3 From 6dad06ec56eeb942a1785246bf91fe7100a21c7e Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 11 Jun 2009 19:34:54 +0200 Subject: conntrackd: use a permanent handler for flush operations In 6f5666a29cb7cbff08ce926ee1edb84a311ff6ee, I moved the flush operation into a child process and to use a disposable handler to perform flush requests. This patch adds a dedicated flush handler since there is a possible race condition that can happen if the child process ends before we have received all the event messages that the flush request has triggered. Signed-off-by: Pablo Neira Ayuso --- include/conntrackd.h | 1 + src/run.c | 35 +++++++++++++---------------------- src/sync-mode.c | 23 ++--------------------- 3 files changed, 16 insertions(+), 43 deletions(-) (limited to 'src') diff --git a/include/conntrackd.h b/include/conntrackd.h index 0546855..c5f6659 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -122,6 +122,7 @@ struct ct_general_state { struct nfct_handle *resync; /* resync handler */ struct nfct_handle *get; /* get handler */ int get_retval; /* hackish */ + struct nfct_handle *flush; /* flusher */ struct alarm_block resync_alarm; struct alarm_block polling_alarm; diff --git a/src/run.c b/src/run.c index a0aea4f..fe81d54 100644 --- a/src/run.c +++ b/src/run.c @@ -47,6 +47,8 @@ void killer(int foo) nfct_close(STATE(resync)); nfct_close(STATE(get)); + origin_unregister(STATE(flush)); + nfct_close(STATE(flush)); if (STATE(us_filter)) ct_filter_destroy(STATE(us_filter)); @@ -180,13 +182,6 @@ static void dump_stats_runtime(int fd) send(fd, buf, size, 0); } -static void flush_done_cb(void *data) -{ - struct nfct_handle *h = data; - origin_unregister(h); - nfct_close(h); -} - void local_handler(int fd, void *data) { int ret; @@ -201,30 +196,18 @@ void local_handler(int fd, void *data) return; switch(type) { - case FLUSH_MASTER: { - struct nfct_handle *h; - - /* disposable flusher handler */ - h = nfct_open(CONNTRACK, 0); - if (h == NULL) { - dlog(LOG_ERR, "cannot open flusher handler"); - return; - } - /* register this handler as the origin of a flush operation */ - origin_register(h, CTD_ORIGIN_FLUSH); - + case FLUSH_MASTER: STATE(stats).nl_kernel_table_flush++; dlog(LOG_NOTICE, "flushing kernel conntrack table"); /* fork a child process that performs the flush operation, * meanwhile the parent process handles events. */ if (fork_process_new(CTD_PROC_FLUSH, CTD_PROC_F_EXCL, - flush_done_cb, h) == 0) { - nl_flush_conntrack_table(h); + NULL, NULL) == 0) { + nl_flush_conntrack_table(STATE(flush)); exit(EXIT_SUCCESS); } return; - } case RESYNC_MASTER: STATE(stats).nl_kernel_table_resync++; dlog(LOG_NOTICE, "resync with master table"); @@ -408,6 +391,14 @@ init(void) } nfct_callback_register(STATE(get), NFCT_T_ALL, get_handler, NULL); + STATE(flush) = nfct_open(CONNTRACK, 0); + if (STATE(flush) == NULL) { + dlog(LOG_ERR, "cannot open flusher handler"); + return -1; + } + /* register this handler as the origin of a flush operation */ + origin_register(STATE(flush), CTD_ORIGIN_FLUSH); + if (CONFIG(flags) & CTD_POLL) { init_alarm(&STATE(polling_alarm), NULL, do_polling_alarm); add_alarm(&STATE(polling_alarm), CONFIG(poll_kernel_secs), 0); diff --git a/src/sync-mode.c b/src/sync-mode.c index 2da3604..102ecac 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -203,35 +203,16 @@ static void interface_handler(void) interface_candidate(); } -/* this is called once the flusher process has finished */ -static void flush_done_cb(void *data) -{ - struct nfct_handle *h = data; - origin_unregister(h); - nfct_close(h); -} - static void do_reset_cache_alarm(struct alarm_block *a, void *data) { - struct nfct_handle *h; - - /* disposable flusher handler */ - h = nfct_open(CONNTRACK, 0); - if (h == NULL) { - dlog(LOG_ERR, "cannot open flusher handler"); - return; - } - /* register this handler as the origin of a flush operation */ - origin_register(h, CTD_ORIGIN_FLUSH); - STATE(stats).nl_kernel_table_flush++; dlog(LOG_NOTICE, "flushing kernel conntrack table (scheduled)"); /* fork a child process that performs the flush operation, * meanwhile the parent process handles events. */ if (fork_process_new(CTD_PROC_FLUSH, CTD_PROC_F_EXCL, - flush_done_cb, h) == 0) { - nl_flush_conntrack_table(h); + NULL, NULL) == 0) { + nl_flush_conntrack_table(STATE(flush)); exit(EXIT_SUCCESS); } /* this is not required if events don't get lost */ -- cgit v1.2.3 From 9163f4673d919658c94f9de4ca32a2e9dacce2fd Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 11 Jun 2009 19:34:54 +0200 Subject: conntrackd: use a permanent handler for commit operations This patch adds a dedicated commit handler since there is a possible race condition that can happen if the child process ends before we have received all the event messages that the commit request has triggered. Signed-off-by: Pablo Neira Ayuso --- include/conntrackd.h | 2 ++ src/sync-mode.c | 35 +++++++++++++---------------------- 2 files changed, 15 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/include/conntrackd.h b/include/conntrackd.h index c5f6659..7a63f97 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -166,6 +166,8 @@ struct ct_sync_state { struct cache *internal; /* internal events cache (netlink) */ struct cache *external; /* external events cache (mcast) */ + struct nfct_handle *commit; + struct multichannel *channel; struct nlif_handle *interface; struct queue *tx_queue; diff --git a/src/sync-mode.c b/src/sync-mode.c index 102ecac..dca6eee 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -298,6 +298,13 @@ static int init_sync(void) STATE(fds)) == -1) return -1; + STATE_SYNC(commit) = nfct_open(CONNTRACK, 0); + if (STATE_SYNC(commit) == NULL) { + dlog(LOG_ERR, "can't create handler to commit"); + return -1; + } + origin_register(STATE_SYNC(commit), CTD_ORIGIN_COMMIT); + init_alarm(&STATE_SYNC(reset_cache_alarm), NULL, do_reset_cache_alarm); /* initialization of message sequence generation */ @@ -337,6 +344,9 @@ static void kill_sync(void) queue_destroy(STATE_SYNC(tx_queue)); + origin_unregister(STATE_SYNC(commit)); + nfct_close(STATE_SYNC(commit)); + if (STATE_SYNC(sync)->kill) STATE_SYNC(sync)->kill(); } @@ -390,14 +400,6 @@ static void dump_stats_sync_extended(int fd) send(fd, buf, size, 0); } -/* this is called once the committer process has finished */ -static void commit_done_cb(void *data) -{ - struct nfct_handle *h = data; - origin_unregister(h); - nfct_close(h); -} - /* handler for requests coming via UNIX socket */ static int local_handler_sync(int fd, int type, void *data) { @@ -432,30 +434,19 @@ static int local_handler_sync(int fd, int type, void *data) exit(EXIT_SUCCESS); } break; - case COMMIT: { - struct nfct_handle *h; - + case COMMIT: /* delete the reset alarm if any before committing */ del_alarm(&STATE_SYNC(reset_cache_alarm)); - /* disposable handler for commit operations */ - h = nfct_open(CONNTRACK, 0); - if (h == NULL) { - dlog(LOG_ERR, "can't create handler to commit"); - break; - } - origin_register(h, CTD_ORIGIN_COMMIT); - /* fork new process and insert it the process list */ ret = fork_process_new(CTD_PROC_COMMIT, CTD_PROC_F_EXCL, - commit_done_cb, h); + NULL, NULL); if (ret == 0) { dlog(LOG_NOTICE, "committing external cache"); - cache_commit(STATE_SYNC(external), h); + cache_commit(STATE_SYNC(external), STATE_SYNC(commit)); exit(EXIT_SUCCESS); } break; - } case RESET_TIMERS: if (!alarm_pending(&STATE_SYNC(reset_cache_alarm))) { dlog(LOG_NOTICE, "flushing conntrack table in %d secs", -- cgit v1.2.3 From 8fc9066ee62d17cdb76bc064c945da3bb0d2e2a3 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 11 Jun 2009 20:33:14 +0200 Subject: conntrackd: add support to display statistics on existing child processes This patch adds the ability to dump the list of existing child processes. In general, it would be hard to display one since child processes are generally forked for very specific tasks, like commit and flush operations, and they have very limited lifetime. However, this can be handy for debugging problems. Signed-off-by: Pablo Neira Ayuso --- conntrackd.8 | 3 ++- include/conntrackd.h | 1 + include/process.h | 2 ++ src/main.c | 4 ++++ src/process.c | 25 +++++++++++++++++++++++++ src/run.c | 3 +++ 6 files changed, 37 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/conntrackd.8 b/conntrackd.8 index cf15044..1342c22 100644 --- a/conntrackd.8 +++ b/conntrackd.8 @@ -44,11 +44,12 @@ option will not flush your internal and external cache). .BI "-k " Kill the daemon .TP -.BI "-s " "[|network|cache|runtime|link|queue]" +.BI "-s " "[|network|cache|runtime|link|queue|process]" Dump statistics. If no parameter is passed, it displays the general statistics. If "network" is passed as parameter it displays the networking statistics. If "cache" is passed as parameter, it shows the extended cache statistics. If "runtime" is passed as parameter, it shows the run-time statistics. +If "process" is passed as parameter, it shows existing child processes (if any). .TP .BI "-R " Force a resync against the kernel connection tracking table diff --git a/include/conntrackd.h b/include/conntrackd.h index 7a63f97..04dc611 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -34,6 +34,7 @@ #define STATS_QUEUE 32 /* queue stats */ #define FLUSH_INT_CACHE 33 /* flush internal cache */ #define FLUSH_EXT_CACHE 34 /* flush external cache */ +#define STATS_PROCESS 35 /* child process stats */ #define DEFAULT_CONFIGFILE "/etc/conntrackd/conntrackd.conf" #define DEFAULT_LOCKFILE "/var/lock/conntrackd.lock" diff --git a/include/process.h b/include/process.h index 9d29f22..41c7c10 100644 --- a/include/process.h +++ b/include/process.h @@ -5,6 +5,7 @@ enum process_type { CTD_PROC_ANY, /* any type */ CTD_PROC_FLUSH, /* flush process */ CTD_PROC_COMMIT, /* commit process */ + CTD_PROC_MAX }; #define CTD_PROC_F_EXCL (1 << 0) /* only one process at a time */ @@ -19,5 +20,6 @@ struct child_process { int fork_process_new(int type, int flags, void (*cb)(void *data), void *data); int fork_process_delete(int pid); +void fork_process_dump(int fd); #endif diff --git a/src/main.c b/src/main.c index 7507ae5..6b320d1 100644 --- a/src/main.c +++ b/src/main.c @@ -214,6 +214,10 @@ int main(int argc, char *argv[]) strlen(argv[i+1])) == 0) { action = STATS_QUEUE; i++; + } else if (strncmp(argv[i+1], "process", + strlen(argv[i+1])) == 0) { + action = STATS_PROCESS; + i++; } else { fprintf(stderr, "ERROR: unknown " "parameter `%s' for " diff --git a/src/process.c b/src/process.c index c378f7a..9b9734c 100644 --- a/src/process.c +++ b/src/process.c @@ -76,3 +76,28 @@ int fork_process_delete(int pid) } return 0; } + +static const char *process_type_to_name[CTD_PROC_MAX] = { + [CTD_PROC_ANY] = "any", + [CTD_PROC_FLUSH] = "flush", + [CTD_PROC_COMMIT] = "commit", +}; + +void fork_process_dump(int fd) +{ + struct child_process *this; + char buf[4096]; + int size = 0; + + sigprocmask(SIG_BLOCK, &STATE(block), NULL); + list_for_each_entry(this, &process_list, head) { + size += snprintf(buf+size, sizeof(buf), + "PID=%u type=%s\n", + this->pid, + this->type < CTD_PROC_MAX ? + process_type_to_name[this->type] : "unknown"); + } + sigprocmask(SIG_UNBLOCK, &STATE(block), NULL); + + send(fd, buf, size, 0); +} diff --git a/src/run.c b/src/run.c index fe81d54..95d51a2 100644 --- a/src/run.c +++ b/src/run.c @@ -216,6 +216,9 @@ void local_handler(int fd, void *data) case STATS_RUNTIME: dump_stats_runtime(fd); return; + case STATS_PROCESS: + fork_process_dump(fd); + return; } if (!STATE(mode)->local(fd, type, data)) -- cgit v1.2.3 From d9c0564db6b3f3ecb196508458a91b03d45fadb2 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 12 Jun 2009 18:35:11 +0200 Subject: build: use TLV format for SCTP/DCCP protocol information In 400ae54438c4b85126f9fab0ae1dc067823b70f7, we added the SCTP support by means of a structure that was encapsulated in an TLV attribute. However, this structure didn't handle alignment and endianess issues appropriately. Similar problem was introduced in b808645ec71b7cc22cf5106b3d79625d07e6077c along with the DCCP support. This patch moves every field of this structure to independent attributes. I decided not to use nesting to make building and parsing more simple. Using TLV is a good idea, specially for DCCP and SCTP that are under development and that may include new fields and obsolete them in the future. Signed-off-by: Pablo Neira Ayuso --- include/network.h | 18 ++++++------------ src/build.c | 35 +++++++++-------------------------- src/parse.c | 50 ++++++++++++++++++++++++-------------------------- 3 files changed, 39 insertions(+), 64 deletions(-) (limited to 'src') diff --git a/include/network.h b/include/network.h index 2786585..3248245 100644 --- a/include/network.h +++ b/include/network.h @@ -199,7 +199,7 @@ enum nta_attr { NTA_IPV6, /* struct nfct_attr_grp_ipv6 */ NTA_L4PROTO, /* uint8_t */ NTA_PORT, /* struct nfct_attr_grp_port */ - NTA_STATE_TCP = 4, /* uint8_t */ + NTA_TCP_STATE = 4, /* uint8_t */ NTA_STATUS, /* uint32_t */ NTA_TIMEOUT, /* uint32_t */ NTA_MARK, /* uint32_t */ @@ -212,8 +212,11 @@ enum nta_attr { NTA_SPAT_PORT, /* uint16_t */ NTA_DPAT_PORT, /* uint16_t */ NTA_NAT_SEQ_ADJ = 16, /* struct nta_attr_natseqadj */ - NTA_STATE_SCTP, /* struct nta_attr_sctp */ - NTA_STATE_DCCP, /* struct nta_attr_dccp */ + NTA_SCTP_STATE, /* uint8_t */ + NTA_SCTP_VTAG_ORIG, /* uint32_t */ + NTA_SCTP_VTAG_REPL, /* uint32_t */ + NTA_DCCP_STATE = 20, /* uint8_t */ + NTA_DCCP_ROLE, /* uint8_t */ NTA_MAX }; @@ -226,15 +229,6 @@ struct nta_attr_natseqadj { uint32_t repl_seq_offset_after; }; -struct nta_attr_sctp { - uint8_t state; - uint32_t vtag_orig, vtag_repl; -}; - -struct nta_attr_dccp { - uint8_t state, role; -}; - void build_payload(const struct nf_conntrack *ct, struct nethdr *n); int parse_payload(struct nf_conntrack *ct, struct nethdr *n, size_t remain); diff --git a/src/build.c b/src/build.c index b2eeeee..92760f2 100644 --- a/src/build.c +++ b/src/build.c @@ -92,27 +92,6 @@ __build_natseqadj(const struct nf_conntrack *ct, struct nethdr *n) addattr(n, NTA_NAT_SEQ_ADJ, &data, sizeof(struct nta_attr_natseqadj)); } -static inline void -__build_sctp(const struct nf_conntrack *ct, struct nethdr *n) -{ - struct nta_attr_sctp data = { - .state = nfct_get_attr_u8(ct, ATTR_SCTP_STATE), - .vtag_orig = htonl(nfct_get_attr_u32(ct, ATTR_SCTP_VTAG_ORIG)), - .vtag_repl = htonl(nfct_get_attr_u32(ct, ATTR_SCTP_VTAG_REPL)), - }; - addattr(n, NTA_STATE_SCTP, &data, sizeof(struct nta_attr_sctp)); -} - -static inline void -__build_dccp(const struct nf_conntrack *ct, struct nethdr *n) -{ - struct nta_attr_dccp data = { - .state = nfct_get_attr_u8(ct, ATTR_DCCP_STATE), - .role = nfct_get_attr_u8(ct, ATTR_DCCP_ROLE), - }; - addattr(n, NTA_STATE_DCCP, &data, sizeof(struct nta_attr_dccp)); -} - static enum nf_conntrack_attr nat_type[] = { ATTR_ORIG_NAT_SEQ_CORRECTION_POS, ATTR_ORIG_NAT_SEQ_OFFSET_BEFORE, ATTR_ORIG_NAT_SEQ_OFFSET_AFTER, ATTR_REPL_NAT_SEQ_CORRECTION_POS, @@ -138,11 +117,15 @@ void build_payload(const struct nf_conntrack *ct, struct nethdr *n) __build_u32(ct, ATTR_STATUS, n, NTA_STATUS); if (nfct_attr_is_set(ct, ATTR_TCP_STATE)) - __build_u8(ct, ATTR_TCP_STATE, n, NTA_STATE_TCP); - else if (nfct_attr_is_set(ct, ATTR_SCTP_STATE)) - __build_sctp(ct, n); - else if (nfct_attr_is_set(ct, ATTR_DCCP_STATE)) - __build_dccp(ct, n); + __build_u8(ct, ATTR_TCP_STATE, n, NTA_TCP_STATE); + else if (nfct_attr_is_set(ct, ATTR_SCTP_STATE)) { + __build_u8(ct, ATTR_SCTP_STATE, n, NTA_SCTP_STATE); + __build_u32(ct, ATTR_SCTP_VTAG_ORIG, n, NTA_SCTP_VTAG_ORIG); + __build_u32(ct, ATTR_SCTP_VTAG_REPL, n, NTA_SCTP_VTAG_REPL); + } else if (nfct_attr_is_set(ct, ATTR_DCCP_STATE)) { + __build_u8(ct, ATTR_DCCP_STATE, n, NTA_DCCP_STATE); + __build_u8(ct, ATTR_DCCP_ROLE, n, NTA_DCCP_ROLE); + } if (!CONFIG(commit_timeout) && nfct_attr_is_set(ct, ATTR_TIMEOUT)) __build_u32(ct, ATTR_TIMEOUT, n, NTA_TIMEOUT); diff --git a/src/parse.c b/src/parse.c index 100177b..1bdfcc7 100644 --- a/src/parse.c +++ b/src/parse.c @@ -29,8 +29,6 @@ static void parse_u16(struct nf_conntrack *ct, int attr, void *data); static void parse_u32(struct nf_conntrack *ct, int attr, void *data); static void parse_group(struct nf_conntrack *ct, int attr, void *data); static void parse_nat_seq_adj(struct nf_conntrack *ct, int attr, void *data); -static void parse_sctp(struct nf_conntrack *ct, int attr, void *data); -static void parse_dccp(struct nf_conntrack *ct, int attr, void *data); struct parser { void (*parse)(struct nf_conntrack *ct, int attr, void *data); @@ -59,7 +57,7 @@ static struct parser h[NTA_MAX] = { .attr = ATTR_L4PROTO, .size = NTA_SIZE(sizeof(uint8_t)), }, - [NTA_STATE_TCP] = { + [NTA_TCP_STATE] = { .parse = parse_u8, .attr = ATTR_TCP_STATE, .size = NTA_SIZE(sizeof(uint8_t)), @@ -123,13 +121,30 @@ static struct parser h[NTA_MAX] = { .parse = parse_nat_seq_adj, .size = NTA_SIZE(sizeof(struct nta_attr_natseqadj)), }, - [NTA_STATE_SCTP] = { - .parse = parse_sctp, - .size = NTA_SIZE(sizeof(struct nta_attr_sctp)), + [NTA_SCTP_STATE] = { + .parse = parse_u8, + .attr = ATTR_SCTP_STATE, + .size = NTA_SIZE(sizeof(uint8_t)), }, - [NTA_STATE_DCCP] = { - .parse = parse_dccp, - .size = NTA_SIZE(sizeof(struct nta_attr_dccp)), + [NTA_SCTP_VTAG_ORIG] = { + .parse = parse_u32, + .attr = ATTR_SCTP_VTAG_ORIG, + .size = NTA_SIZE(sizeof(uint32_t)), + }, + [NTA_SCTP_VTAG_REPL] = { + .parse = parse_u32, + .attr = ATTR_SCTP_VTAG_REPL, + .size = NTA_SIZE(sizeof(uint32_t)), + }, + [NTA_DCCP_STATE] = { + .parse = parse_u8, + .attr = ATTR_DCCP_STATE, + .size = NTA_SIZE(sizeof(uint8_t)), + }, + [NTA_DCCP_ROLE] = { + .parse = parse_u8, + .attr = ATTR_DCCP_ROLE, + .size = NTA_SIZE(sizeof(uint8_t)), }, }; @@ -178,23 +193,6 @@ parse_nat_seq_adj(struct nf_conntrack *ct, int attr, void *data) ntohl(this->orig_seq_correction_pos)); } -static void -parse_sctp(struct nf_conntrack *ct, int attr, void *data) -{ - struct nta_attr_sctp *this = data; - nfct_set_attr_u8(ct, ATTR_SCTP_STATE, this->state); - nfct_set_attr_u32(ct, ATTR_SCTP_VTAG_ORIG, ntohl(this->vtag_orig)); - nfct_set_attr_u32(ct, ATTR_SCTP_VTAG_REPL, ntohl(this->vtag_repl)); -} - -static void -parse_dccp(struct nf_conntrack *ct, int attr, void *data) -{ - struct nta_attr_dccp *this = data; - nfct_set_attr_u8(ct, ATTR_DCCP_STATE, this->state); - nfct_set_attr_u8(ct, ATTR_DCCP_ROLE, this->role); -} - int parse_payload(struct nf_conntrack *ct, struct nethdr *net, size_t remain) { int len; -- cgit v1.2.3 From faea76e8bc626549f4d338a3bf22e466336264ca Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 20 Jun 2009 20:07:33 +0200 Subject: conntrackd: rename `-s queue' option by `-s rsqueue' This patch renames the statistics option that displays the content of the resend queue which is used by the ftfw mode. Signed-off-by: Pablo Neira Ayuso --- conntrackd.8 | 2 +- include/conntrackd.h | 2 +- src/main.c | 6 +++--- src/sync-ftfw.c | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/conntrackd.8 b/conntrackd.8 index 1342c22..61a3e0e 100644 --- a/conntrackd.8 +++ b/conntrackd.8 @@ -44,7 +44,7 @@ option will not flush your internal and external cache). .BI "-k " Kill the daemon .TP -.BI "-s " "[|network|cache|runtime|link|queue|process]" +.BI "-s " "[|network|cache|runtime|link|rsqueue|process]" Dump statistics. If no parameter is passed, it displays the general statistics. If "network" is passed as parameter it displays the networking statistics. If "cache" is passed as parameter, it shows the extended cache statistics. diff --git a/include/conntrackd.h b/include/conntrackd.h index 04dc611..40566bd 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -31,7 +31,7 @@ #define STATS_CACHE 29 /* extended cache stats */ #define STATS_RUNTIME 30 /* extended runtime stats */ #define STATS_LINK 31 /* dedicated link stats */ -#define STATS_QUEUE 32 /* queue stats */ +#define STATS_RSQUEUE 32 /* resend queue stats */ #define FLUSH_INT_CACHE 33 /* flush internal cache */ #define FLUSH_EXT_CACHE 34 /* flush external cache */ #define STATS_PROCESS 35 /* child process stats */ diff --git a/src/main.c b/src/main.c index 6b320d1..ca491f2 100644 --- a/src/main.c +++ b/src/main.c @@ -44,7 +44,7 @@ static const char usage_client_commands[] = " -i, display content of the internal cache\n" " -e, display the content of the external cache\n" " -k, kill conntrack daemon\n" - " -s [|network|cache|runtime|link|queue], dump statistics\n" + " -s [|network|cache|runtime|link|rsqueue], dump statistics\n" " -R, resync with kernel conntrack table\n" " -n, request resync with other node (only FT-FW and NOTRACK modes)\n" " -x, dump cache in XML format (requires -i or -e)\n" @@ -210,9 +210,9 @@ int main(int argc, char *argv[]) strlen(argv[i+1])) == 0) { action = STATS_LINK; i++; - } else if (strncmp(argv[i+1], "queue", + } else if (strncmp(argv[i+1], "rsqueue", strlen(argv[i+1])) == 0) { - action = STATS_QUEUE; + action = STATS_RSQUEUE; i++; } else if (strncmp(argv[i+1], "process", strlen(argv[i+1])) == 0) { diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index e026b1c..e7c9af2 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -226,7 +226,7 @@ static int ftfw_local(int fd, int type, void *data) dlog(LOG_NOTICE, "sending bulk update"); cache_iterate(STATE_SYNC(internal), NULL, do_cache_to_tx); break; - case STATS_QUEUE: + case STATS_RSQUEUE: ftfw_local_queue(fd); break; default: -- cgit v1.2.3 From 4cfc8533743a766db0b2c8ae27b7bba312eb3ec0 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 20 Jun 2009 21:11:06 +0200 Subject: conntrackd: add the name field to queues This patch adds the name field to identify the queue by means of a string. This patch is used by the next one that introduces per-queue statistics. Signed-off-by: Pablo Neira Ayuso --- include/queue.h | 6 +++++- src/queue.c | 5 ++++- src/sync-ftfw.c | 2 +- src/sync-mode.c | 2 +- 4 files changed, 11 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/include/queue.h b/include/queue.h index 9213b3d..89b00a8 100644 --- a/include/queue.h +++ b/include/queue.h @@ -29,17 +29,21 @@ void queue_object_free(struct queue_object *obj); struct evfd; +#define QUEUE_NAMELEN 16 + struct queue { unsigned int max_elems; unsigned int num_elems; uint32_t flags; struct list_head head; struct evfd *evfd; + char name[QUEUE_NAMELEN]; }; #define QUEUE_F_EVFD (1U << 0) -struct queue *queue_create(int max_objects, unsigned int flags); +struct queue *queue_create(const char *name, + int max_objects, unsigned int flags); void queue_destroy(struct queue *b); unsigned int queue_len(const struct queue *b); int queue_add(struct queue *b, struct queue_node *n); diff --git a/src/queue.c b/src/queue.c index 7b36dc6..e5dc307 100644 --- a/src/queue.c +++ b/src/queue.c @@ -23,7 +23,8 @@ #include #include -struct queue *queue_create(int max_objects, unsigned int flags) +struct queue * +queue_create(const char *name, int max_objects, unsigned int flags) { struct queue *b; @@ -42,6 +43,8 @@ struct queue *queue_create(int max_objects, unsigned int flags) return NULL; } } + strncpy(b->name, name, QUEUE_NAMELEN); + b->name[QUEUE_NAMELEN-1]='\0'; return b; } diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index e7c9af2..bf9f4f7 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -143,7 +143,7 @@ static void do_alive_alarm(struct alarm_block *a, void *data) static int ftfw_init(void) { - rs_queue = queue_create(CONFIG(resend_queue_size), 0); + rs_queue = queue_create("rsqueue", CONFIG(resend_queue_size), 0); if (rs_queue == NULL) { dlog(LOG_ERR, "cannot create rs queue"); return -1; diff --git a/src/sync-mode.c b/src/sync-mode.c index dca6eee..308c08b 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -289,7 +289,7 @@ static int init_sync(void) if (register_fd(nlif_fd(STATE_SYNC(interface)), STATE(fds)) == -1) return -1; - STATE_SYNC(tx_queue) = queue_create(INT_MAX, QUEUE_F_EVFD); + STATE_SYNC(tx_queue) = queue_create("txqueue", INT_MAX, QUEUE_F_EVFD); if (STATE_SYNC(tx_queue) == NULL) { dlog(LOG_ERR, "cannot create tx queue"); return -1; -- cgit v1.2.3 From b524c764aba149018fa83dec742c21dc8116838e Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 20 Jun 2009 21:17:43 +0200 Subject: conntrackd: add `-s queue' to display queue statistics This patch re-introduces `-s queue' but now it displays generic queue statistics. # conntrackd -s queue active queue objects: 0 queue txqueue: current elements: 0 maximum elements: 2147483647 not enough space errors: 0 queue rsqueue: current elements: 72 maximum elements: 128 not enough space errors: 0 Signed-off-by: Pablo Neira Ayuso --- conntrackd.8 | 3 ++- include/conntrackd.h | 1 + include/queue.h | 2 ++ src/main.c | 6 +++++- src/queue.c | 24 ++++++++++++++++++++++++ src/sync-mode.c | 3 +++ 6 files changed, 37 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/conntrackd.8 b/conntrackd.8 index 61a3e0e..f741bc9 100644 --- a/conntrackd.8 +++ b/conntrackd.8 @@ -44,12 +44,13 @@ option will not flush your internal and external cache). .BI "-k " Kill the daemon .TP -.BI "-s " "[|network|cache|runtime|link|rsqueue|process]" +.BI "-s " "[|network|cache|runtime|link|rsqueue|process|queue]" Dump statistics. If no parameter is passed, it displays the general statistics. If "network" is passed as parameter it displays the networking statistics. If "cache" is passed as parameter, it shows the extended cache statistics. If "runtime" is passed as parameter, it shows the run-time statistics. If "process" is passed as parameter, it shows existing child processes (if any). +If "queue" is passed as parameter, it shows queue statistics. .TP .BI "-R " Force a resync against the kernel connection tracking table diff --git a/include/conntrackd.h b/include/conntrackd.h index 40566bd..040c252 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -35,6 +35,7 @@ #define FLUSH_INT_CACHE 33 /* flush internal cache */ #define FLUSH_EXT_CACHE 34 /* flush external cache */ #define STATS_PROCESS 35 /* child process stats */ +#define STATS_QUEUE 36 /* queue stats */ #define DEFAULT_CONFIGFILE "/etc/conntrackd/conntrackd.conf" #define DEFAULT_LOCKFILE "/var/lock/conntrackd.lock" diff --git a/include/queue.h b/include/queue.h index 89b00a8..d989402 100644 --- a/include/queue.h +++ b/include/queue.h @@ -32,6 +32,7 @@ struct evfd; #define QUEUE_NAMELEN 16 struct queue { + struct list_head list; unsigned int max_elems; unsigned int num_elems; uint32_t flags; @@ -45,6 +46,7 @@ struct queue { struct queue *queue_create(const char *name, int max_objects, unsigned int flags); void queue_destroy(struct queue *b); +void queue_stats_show(int fd); unsigned int queue_len(const struct queue *b); int queue_add(struct queue *b, struct queue_node *n); int queue_del(struct queue_node *n); diff --git a/src/main.c b/src/main.c index ca491f2..4ead2ea 100644 --- a/src/main.c +++ b/src/main.c @@ -44,7 +44,7 @@ static const char usage_client_commands[] = " -i, display content of the internal cache\n" " -e, display the content of the external cache\n" " -k, kill conntrack daemon\n" - " -s [|network|cache|runtime|link|rsqueue], dump statistics\n" + " -s [|network|cache|runtime|link|rsqueue|queue], dump statistics\n" " -R, resync with kernel conntrack table\n" " -n, request resync with other node (only FT-FW and NOTRACK modes)\n" " -x, dump cache in XML format (requires -i or -e)\n" @@ -218,6 +218,10 @@ int main(int argc, char *argv[]) strlen(argv[i+1])) == 0) { action = STATS_PROCESS; i++; + } else if (strncmp(argv[i+1], "queue", + strlen(argv[i+1])) == 0) { + action = STATS_QUEUE; + i++; } else { fprintf(stderr, "ERROR: unknown " "parameter `%s' for " diff --git a/src/queue.c b/src/queue.c index e5dc307..6f5707f 100644 --- a/src/queue.c +++ b/src/queue.c @@ -20,8 +20,12 @@ #include "event.h" #include +#include #include #include +#include + +static LIST_HEAD(queue_list); /* list of existing queues */ struct queue * queue_create(const char *name, int max_objects, unsigned int flags) @@ -45,17 +49,37 @@ queue_create(const char *name, int max_objects, unsigned int flags) } strncpy(b->name, name, QUEUE_NAMELEN); b->name[QUEUE_NAMELEN-1]='\0'; + list_add(&b->list, &queue_list); return b; } void queue_destroy(struct queue *b) { + list_del(&b->list); if (b->flags & QUEUE_F_EVFD) destroy_evfd(b->evfd); free(b); } +void queue_stats_show(int fd) +{ + struct queue *this; + int size = 0; + char buf[512]; + + list_for_each_entry(this, &queue_list, list) { + size += snprintf(buf+size, sizeof(buf), + "queue %s:\n" + "current elements:\t\t%12u\n" + "maximum elements:\t\t%12u\n\n", + this->name, + this->num_elems, + this->max_elems); + } + send(fd, buf, size, 0); +} + void queue_node_init(struct queue_node *n, int type) { INIT_LIST_HEAD(&n->head); diff --git a/src/sync-mode.c b/src/sync-mode.c index 308c08b..4d6956e 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -494,6 +494,9 @@ static int local_handler_sync(int fd, int type, void *data) multichannel_stats_extended(STATE_SYNC(channel), STATE_SYNC(interface), fd); break; + case STATS_QUEUE: + queue_stats_show(fd); + break; default: if (STATE_SYNC(sync)->local) ret = STATE_SYNC(sync)->local(fd, type, data); -- cgit v1.2.3 From e30be653e677f618e1d6a43edd45392a29c3e92e Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 20 Jun 2009 21:23:19 +0200 Subject: conntrackd: add statistics about queue node objects This patch adds the statistics for queue node objects. Signed-off-by: Pablo Neira Ayuso --- src/queue.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src') diff --git a/src/queue.c b/src/queue.c index 6f5707f..465f47c 100644 --- a/src/queue.c +++ b/src/queue.c @@ -26,6 +26,7 @@ #include static LIST_HEAD(queue_list); /* list of existing queues */ +static uint32_t qobjects_num; /* number of active queue objects */ struct queue * queue_create(const char *name, int max_objects, unsigned int flags) @@ -68,6 +69,10 @@ void queue_stats_show(int fd) int size = 0; char buf[512]; + size += snprintf(buf+size, sizeof(buf), + "allocated queue nodes:\t\t%12u\n\n", + qobjects_num); + list_for_each_entry(this, &queue_list, list) { size += snprintf(buf+size, sizeof(buf), "queue %s:\n" @@ -101,6 +106,7 @@ struct queue_object *queue_object_new(int type, size_t size) obj->qnode.size = size; queue_node_init(&obj->qnode, type); + qobjects_num++; return obj; } @@ -108,6 +114,7 @@ struct queue_object *queue_object_new(int type, size_t size) void queue_object_free(struct queue_object *obj) { free(obj); + qobjects_num--; } int queue_add(struct queue *b, struct queue_node *n) -- cgit v1.2.3 From 90bb19b9eb7d97887883ce480bb4eb12c60d3505 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 20 Jun 2009 21:24:04 +0200 Subject: conntrackd: add statistics for enospc errors in queues This patch adds a new statistic field to count the number of enospc errors while adding new nodes to some queue. Signed-off-by: Pablo Neira Ayuso --- include/queue.h | 1 + src/queue.c | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/include/queue.h b/include/queue.h index d989402..cca9cba 100644 --- a/include/queue.h +++ b/include/queue.h @@ -35,6 +35,7 @@ struct queue { struct list_head list; unsigned int max_elems; unsigned int num_elems; + uint32_t enospc_err; uint32_t flags; struct list_head head; struct evfd *evfd; diff --git a/src/queue.c b/src/queue.c index 465f47c..76425b1 100644 --- a/src/queue.c +++ b/src/queue.c @@ -77,10 +77,12 @@ void queue_stats_show(int fd) size += snprintf(buf+size, sizeof(buf), "queue %s:\n" "current elements:\t\t%12u\n" - "maximum elements:\t\t%12u\n\n", + "maximum elements:\t\t%12u\n" + "not enough space errors:\t%12u\n\n", this->name, this->num_elems, - this->max_elems); + this->max_elems, + this->enospc_err); } send(fd, buf, size, 0); } @@ -123,6 +125,7 @@ int queue_add(struct queue *b, struct queue_node *n) return 0; if (b->num_elems >= b->max_elems) { + b->enospc_err++; errno = ENOSPC; return -1; } -- cgit v1.2.3 From bcb91373d0641c1999d48526411fd857d2baee28 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 21 Jun 2009 00:27:37 +0200 Subject: conntrackd: fix memory leak in cache_update_force() This patch fixes a memory leak in cache_update_force(). The problem occurs if the object does not exists in the cache and we fail to add it. Signed-off-by: Pablo Neira Ayuso --- src/cache.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/cache.c b/src/cache.c index e4a024b..1e544a2 100644 --- a/src/cache.c +++ b/src/cache.c @@ -340,8 +340,10 @@ cache_update_force(struct cache *c, struct nf_conntrack *ct) if (obj == NULL) return NULL; - if (cache_add(c, obj, id) == -1) + if (cache_add(c, obj, id) == -1) { + cache_object_free(obj); return NULL; + } return obj; } -- cgit v1.2.3 From 9d57b20ca51ee4de21b938bc20f9e3345aa9b02b Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 21 Jun 2009 00:31:14 +0200 Subject: conntrackd: fix wrong TCP handling in unused nl_update_conntrack() This patch fixes an incorrect use of nfct_get_attr_u32() instead of nfct_get_attr_u8() to obtain the current TCP state. This patch also sets the IP_CT_TCP_FLAG_CLOSE_INIT for states >= TIME_WAIT. The function nl_update_conntrack() is currently unused so this fix does not resolve any pending issue. Signed-off-by: Pablo Neira Ayuso --- src/netlink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/netlink.c b/src/netlink.c index cca6f3a..5c07201 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -257,7 +257,7 @@ int nl_update_conntrack(struct nfct_handle *h, IP_CT_TCP_FLAG_SACK_PERM; /* FIXME: workaround, we should send TCP flags in updates */ - if (nfct_get_attr_u32(ct, ATTR_TCP_STATE) == + if (nfct_get_attr_u8(ct, ATTR_TCP_STATE) >= TCP_CONNTRACK_TIME_WAIT) { flags |= IP_CT_TCP_FLAG_CLOSE_INIT; } -- cgit v1.2.3 From 9406f29b89f6727c3db5485d109466701393b4d4 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 17 Jul 2009 13:33:36 +0200 Subject: local: add LOCAL_RET_* return values for UNIX sockets callbacks This patch adds the LOCAL_RET_* return values. The return value LOCAL_RET_STOLEN which allows to leave a client socket open while waiting for an operation to finish. Signed-off-by: Pablo Neira Ayuso --- include/conntrackd.h | 1 - include/local.h | 7 ++++++- src/local.c | 7 ++++--- src/run.c | 22 +++++++++++++--------- src/stats-mode.c | 2 +- src/sync-ftfw.c | 5 +---- src/sync-mode.c | 2 +- 7 files changed, 26 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/include/conntrackd.h b/include/conntrackd.h index 040c252..417bac6 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -234,7 +234,6 @@ extern struct ct_mode stats_mode; /* These live in run.c */ void killer(int foo); -void local_handler(int fd, void *data); int init(void); void run(void); diff --git a/include/local.h b/include/local.h index 6940755..f9121b1 100644 --- a/include/local.h +++ b/include/local.h @@ -16,11 +16,16 @@ struct local_server { char path[UNIX_PATH_MAX]; }; +/* callback return values */ +#define LOCAL_RET_ERROR -1 +#define LOCAL_RET_OK 0 +#define LOCAL_RET_STOLEN 1 + /* local server */ int local_server_create(struct local_server *server, struct local_conf *conf); void local_server_destroy(struct local_server *server); int do_local_server_step(struct local_server *server, void *data, - void (*process)(int fd, void *data)); + int (*process)(int fd, void *data)); /* local client */ int local_client_create(struct local_conf *conf); diff --git a/src/local.c b/src/local.c index 4739e56..feff608 100644 --- a/src/local.c +++ b/src/local.c @@ -72,7 +72,7 @@ void local_server_destroy(struct local_server *server) } int do_local_server_step(struct local_server *server, void *data, - void (*process)(int fd, void *data)) + int (*process)(int fd, void *data)) { int rfd; struct sockaddr_un local; @@ -82,8 +82,9 @@ int do_local_server_step(struct local_server *server, void *data, if (rfd == -1) return -1; - process(rfd, data); - close(rfd); + /* This descriptor will be closed later, we ignore OK and errors */ + if (process(rfd, data) != LOCAL_RET_STOLEN) + close(rfd); return 0; } diff --git a/src/run.c b/src/run.c index 95d51a2..87b6fb2 100644 --- a/src/run.c +++ b/src/run.c @@ -182,18 +182,18 @@ static void dump_stats_runtime(int fd) send(fd, buf, size, 0); } -void local_handler(int fd, void *data) +static int local_handler(int fd, void *data) { - int ret; + int ret = LOCAL_RET_OK; int type; ret = read(fd, &type, sizeof(type)); if (ret == -1) { STATE(stats).local_read_failed++; - return; + return LOCAL_RET_OK; } if (ret == 0) - return; + return LOCAL_RET_OK; switch(type) { case FLUSH_MASTER: @@ -207,22 +207,26 @@ void local_handler(int fd, void *data) nl_flush_conntrack_table(STATE(flush)); exit(EXIT_SUCCESS); } - return; + break; case RESYNC_MASTER: STATE(stats).nl_kernel_table_resync++; dlog(LOG_NOTICE, "resync with master table"); nl_dump_conntrack_table(STATE(dump)); - return; + break; case STATS_RUNTIME: dump_stats_runtime(fd); - return; + break; case STATS_PROCESS: fork_process_dump(fd); - return; + break; } - if (!STATE(mode)->local(fd, type, data)) + ret = STATE(mode)->local(fd, type, data); + if (ret == LOCAL_RET_ERROR) { STATE(stats).local_unknown_request++; + return LOCAL_RET_ERROR; + } + return ret; } static void do_overrun_resync_alarm(struct alarm_block *a, void *data) diff --git a/src/stats-mode.c b/src/stats-mode.c index b84c7a1..5cfb638 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -55,7 +55,7 @@ static void kill_stats(void) /* handler for requests coming via UNIX socket */ static int local_handler_stats(int fd, int type, void *data) { - int ret = 1; + int ret = LOCAL_RET_OK; switch(type) { case DUMP_INTERNAL: diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index bf9f4f7..0d31e17 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -215,7 +215,7 @@ static void ftfw_local_queue(int fd) static int ftfw_local(int fd, int type, void *data) { - int ret = 1; + int ret = LOCAL_RET_OK; switch(type) { case REQUEST_DUMP: @@ -229,9 +229,6 @@ static int ftfw_local(int fd, int type, void *data) case STATS_RSQUEUE: ftfw_local_queue(fd); break; - default: - ret = 0; - break; } return ret; diff --git a/src/sync-mode.c b/src/sync-mode.c index 4d6956e..b0e2b02 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -403,7 +403,7 @@ static void dump_stats_sync_extended(int fd) /* handler for requests coming via UNIX socket */ static int local_handler_sync(int fd, int type, void *data) { - int ret = 1; + int ret = LOCAL_RET_OK; switch(type) { case DUMP_INTERNAL: -- cgit v1.2.3 From a1d03b775376aa8545ec9a0e89381b659e4d28ed Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 17 Jul 2009 13:36:05 +0200 Subject: conntrackd: add iterators with limited steps in hash and cache types This patch adds cache_iterate_limit() and hashtable_iterate_limit() that allows to limit the iteration to given a number of states. Signed-off-by: Pablo Neira Ayuso --- include/cache.h | 1 + include/hash.h | 3 ++- src/cache.c | 7 +++++++ src/cache_iterators.c | 16 ++++++++-------- src/hash.c | 17 +++++++++++++---- 5 files changed, 31 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/include/cache.h b/include/cache.h index 0b2b18d..109e6aa 100644 --- a/include/cache.h +++ b/include/cache.h @@ -114,6 +114,7 @@ void cache_stats_extended(const struct cache *c, int fd); struct cache_object *cache_data_get_object(struct cache *c, void *data); void *cache_get_extra(struct cache *, void *); void cache_iterate(struct cache *c, void *data, int (*iterate)(void *data1, void *data2)); +void cache_iterate_limit(struct cache *c, void *data, uint32_t from, uint32_t steps, int (*iterate)(void *data1, void *data2)); /* iterators */ struct nfct_handle; diff --git a/include/hash.h b/include/hash.h index 68d618b..eaa9e96 100644 --- a/include/hash.h +++ b/include/hash.h @@ -37,7 +37,8 @@ int hashtable_add(struct hashtable *table, struct hashtable_node *n, int id); void hashtable_del(struct hashtable *table, struct hashtable_node *node); int hashtable_flush(struct hashtable *table); int hashtable_iterate(struct hashtable *table, void *data, - int (*iterate)(void *data, struct hashtable_node *n)); + int (*iterate)(void *data, void *n)); +int hashtable_iterate_limit(struct hashtable *table, void *data, uint32_t from, uint32_t steps, int (*iterate)(void *data1, void *n)); unsigned int hashtable_counter(const struct hashtable *table); #endif diff --git a/src/cache.c b/src/cache.c index 1e544a2..f95bef6 100644 --- a/src/cache.c +++ b/src/cache.c @@ -423,3 +423,10 @@ void cache_iterate(struct cache *c, { hashtable_iterate(c->h, data, iterate); } + +void cache_iterate_limit(struct cache *c, void *data, + uint32_t from, uint32_t steps, + int (*iterate)(void *data1, void *data2)) +{ + hashtable_iterate_limit(c->h, data, from, steps, iterate); +} diff --git a/src/cache_iterators.c b/src/cache_iterators.c index 542ab91..b6688e9 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -33,12 +33,12 @@ struct __dump_container { int type; }; -static int do_dump(void *data1, struct hashtable_node *n) +static int do_dump(void *data1, void *n) { char buf[1024]; int size; struct __dump_container *container = data1; - struct cache_object *obj = (struct cache_object *)n; + struct cache_object *obj = n; char *data = obj->data; unsigned i; @@ -152,9 +152,9 @@ retry: } } -static int do_commit_related(void *data, struct hashtable_node *n) +static int do_commit_related(void *data, void *n) { - struct cache_object *obj = (struct cache_object *)n; + struct cache_object *obj = n; if (ct_is_related(obj->ct)) __do_commit_step(data, obj); @@ -163,9 +163,9 @@ static int do_commit_related(void *data, struct hashtable_node *n) return 0; } -static int do_commit_master(void *data, struct hashtable_node *n) +static int do_commit_master(void *data, void *n) { - struct cache_object *obj = (struct cache_object *)n; + struct cache_object *obj = n; if (ct_is_related(obj->ct)) return 0; @@ -207,10 +207,10 @@ void cache_commit(struct cache *c, struct nfct_handle *h) res.tv_sec, res.tv_usec); } -static int do_flush(void *data, struct hashtable_node *n) +static int do_flush(void *data, void *n) { struct cache *c = data; - struct cache_object *obj = (struct cache_object *)n; + struct cache_object *obj = n; cache_del(c, obj); cache_object_free(obj); diff --git a/src/hash.c b/src/hash.c index 9c9ea5b..fe6a047 100644 --- a/src/hash.c +++ b/src/hash.c @@ -23,6 +23,7 @@ #include #include #include +#include struct hashtable * hashtable_create(int hashsize, int limit, @@ -111,21 +112,29 @@ int hashtable_flush(struct hashtable *table) return 0; } -int hashtable_iterate(struct hashtable *table, void *data, - int (*iterate)(void *data1, struct hashtable_node *n)) +int +hashtable_iterate_limit(struct hashtable *table, void *data, + uint32_t from, uint32_t steps, + int (*iterate)(void *data1, void *n)) { uint32_t i; struct list_head *e, *tmp; struct hashtable_node *n; - for (i=0; i < table->hashsize; i++) { + for (i=from; i < table->hashsize && i < from+steps; i++) { list_for_each_safe(e, tmp, &table->members[i]) { n = list_entry(e, struct hashtable_node, head); if (iterate(data, n) == -1) return -1; } } - return 0; + return i; +} + +int hashtable_iterate(struct hashtable *table, void *data, + int (*iterate)(void *data1, void *n)) +{ + return hashtable_iterate_limit(table, data, 0, UINT_MAX, iterate); } unsigned int hashtable_counter(const struct hashtable *table) -- cgit v1.2.3 From 651794575c844fe25a717d77bd088c51383067f0 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 19 Jul 2009 15:28:34 +0200 Subject: conntrackd: rework commit not to fork a child process This patch reworks the commit phase to avoid the forking. This is particularly useful in active-active setups in which one node has to commit the external cache while it is receiving new entries to be added in the external cache. This results in really high commit times due to the penalty of the copy-on-write that fork performs. The default number of steps in one run loop is limited to 64 by now. No option to tune this parameter is still available via the configuration file. Signed-off-by: Pablo Neira Ayuso --- include/cache.h | 2 +- include/conntrackd.h | 22 ++++++++++++-- src/cache_iterators.c | 79 +++++++++++++++++++++++++++++++++++++-------------- src/read_config_yy.y | 5 ++++ src/sync-mode.c | 38 ++++++++++++++++--------- 5 files changed, 109 insertions(+), 37 deletions(-) (limited to 'src') diff --git a/include/cache.h b/include/cache.h index 109e6aa..7e61085 100644 --- a/include/cache.h +++ b/include/cache.h @@ -120,7 +120,7 @@ void cache_iterate_limit(struct cache *c, void *data, uint32_t from, uint32_t st struct nfct_handle; void cache_dump(struct cache *c, int fd, int type); -void cache_commit(struct cache *c, struct nfct_handle *h); +void cache_commit(struct cache *c, struct nfct_handle *h, int clientfd); void cache_flush(struct cache *c); void cache_bulk(struct cache *c); diff --git a/include/conntrackd.h b/include/conntrackd.h index 417bac6..12fd17f 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -95,6 +95,9 @@ struct ct_conf { int poll_kernel_secs; int filter_from_kernelspace; int event_iterations_limit; + struct { + int commit_steps; + } general; struct { int type; int prio; @@ -168,12 +171,27 @@ struct ct_sync_state { struct cache *internal; /* internal events cache (netlink) */ struct cache *external; /* external events cache (mcast) */ - struct nfct_handle *commit; - struct multichannel *channel; struct nlif_handle *interface; struct queue *tx_queue; +#define COMMIT_STATE_INACTIVE 0 +#define COMMIT_STATE_MASTER 1 +#define COMMIT_STATE_RELATED 2 + + struct { + int state; + int clientfd; + struct nfct_handle *h; + struct evfd *evfd; + int current; + struct { + int ok; + int fail; + struct timeval start; + } stats; + } commit; + struct alarm_block reset_cache_alarm; struct sync_mode *sync; /* sync mode */ diff --git a/src/cache_iterators.c b/src/cache_iterators.c index b6688e9..c7183fd 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -21,6 +21,7 @@ #include "log.h" #include "conntrackd.h" #include "netlink.h" +#include "event.h" #include #include @@ -174,37 +175,73 @@ static int do_commit_master(void *data, void *n) return 0; } -/* no need to clone, called from child process */ -void cache_commit(struct cache *c, struct nfct_handle *h) +void cache_commit(struct cache *c, struct nfct_handle *h, int clientfd) { - unsigned int commit_ok = c->stats.commit_ok; - unsigned int commit_fail = c->stats.commit_fail; + unsigned int commit_ok, commit_fail; struct __commit_container tmp = { .h = h, .c = c, }; - struct timeval commit_start, commit_stop, res; + struct timeval commit_stop, res; - gettimeofday(&commit_start, NULL); - /* commit master conntrack first, then related ones */ - hashtable_iterate(c->h, &tmp, do_commit_master); - hashtable_iterate(c->h, &tmp, do_commit_related); - gettimeofday(&commit_stop, NULL); - timersub(&commit_stop, &commit_start, &res); + switch(STATE_SYNC(commit).state) { + case COMMIT_STATE_INACTIVE: + gettimeofday(&STATE_SYNC(commit).stats.start, NULL); + STATE_SYNC(commit).stats.ok = c->stats.commit_ok; + STATE_SYNC(commit).stats.fail = c->stats.commit_fail; + STATE_SYNC(commit).clientfd = clientfd; + case COMMIT_STATE_MASTER: + STATE_SYNC(commit).current = + hashtable_iterate_limit(c->h, &tmp, + STATE_SYNC(commit).current, + CONFIG(general).commit_steps, + do_commit_master); + if (STATE_SYNC(commit).current < CONFIG(hashsize)) { + STATE_SYNC(commit).state = COMMIT_STATE_MASTER; + /* give it another step as soon as possible */ + write_evfd(STATE_SYNC(commit).evfd); + return; + } + STATE_SYNC(commit).current = 0; + STATE_SYNC(commit).state = COMMIT_STATE_RELATED; + case COMMIT_STATE_RELATED: + STATE_SYNC(commit).current = + hashtable_iterate_limit(c->h, &tmp, + STATE_SYNC(commit).current, + CONFIG(general).commit_steps, + do_commit_related); + if (STATE_SYNC(commit).current < CONFIG(hashsize)) { + STATE_SYNC(commit).state = COMMIT_STATE_RELATED; + /* give it another step as soon as possible */ + write_evfd(STATE_SYNC(commit).evfd); + return; + } + /* calculate the time that commit has taken */ + gettimeofday(&commit_stop, NULL); + timersub(&commit_stop, &STATE_SYNC(commit).stats.start, &res); + + /* calculate new entries committed */ + commit_ok = c->stats.commit_ok - STATE_SYNC(commit).stats.ok; + commit_fail = + c->stats.commit_fail - STATE_SYNC(commit).stats.fail; - /* calculate new entries committed */ - commit_ok = c->stats.commit_ok - commit_ok; - commit_fail = c->stats.commit_fail - commit_fail; + /* log results */ + dlog(LOG_NOTICE, "Committed %u new entries", commit_ok); - /* log results */ - dlog(LOG_NOTICE, "Committed %u new entries", commit_ok); + if (commit_fail) + dlog(LOG_NOTICE, "%u entries can't be " + "committed", commit_fail); - if (commit_fail) - dlog(LOG_NOTICE, "%u entries can't be " - "committed", commit_fail); + dlog(LOG_NOTICE, "commit has taken %lu.%06lu seconds", + res.tv_sec, res.tv_usec); - dlog(LOG_NOTICE, "commit has taken %lu.%06lu seconds", - res.tv_sec, res.tv_usec); + /* prepare the state machine for new commits */ + STATE_SYNC(commit).current = 0; + STATE_SYNC(commit).state = COMMIT_STATE_INACTIVE; + + /* Close the client socket now that we're done. */ + close(STATE_SYNC(commit).clientfd); + } } static int do_flush(void *data, void *n) diff --git a/src/read_config_yy.y b/src/read_config_yy.y index cab7799..0e9b99b 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -1379,6 +1379,11 @@ init_config(char *filename) if (CONFIG(event_iterations_limit) == 0) CONFIG(event_iterations_limit) = 100; + /* default number of bucket of the hashtable that are committed in + one run loop. XXX: no option available to tune this value yet. */ + if (CONFIG(general).commit_steps == 0) + CONFIG(general).commit_steps = 64; + /* if overrun, automatically resync with kernel after 30 seconds */ if (CONFIG(nl_overrun_resync) == 0) CONFIG(nl_overrun_resync) = 30; diff --git a/src/sync-mode.c b/src/sync-mode.c index b0e2b02..7853d91 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -298,12 +298,22 @@ static int init_sync(void) STATE(fds)) == -1) return -1; - STATE_SYNC(commit) = nfct_open(CONNTRACK, 0); - if (STATE_SYNC(commit) == NULL) { + STATE_SYNC(commit).h = nfct_open(CONNTRACK, 0); + if (STATE_SYNC(commit).h == NULL) { dlog(LOG_ERR, "can't create handler to commit"); return -1; } - origin_register(STATE_SYNC(commit), CTD_ORIGIN_COMMIT); + origin_register(STATE_SYNC(commit).h, CTD_ORIGIN_COMMIT); + + STATE_SYNC(commit).evfd = create_evfd(); + if (STATE_SYNC(commit).evfd == NULL) { + dlog(LOG_ERR, "can't create eventfd to commit"); + return -1; + } + if (register_fd(get_read_evfd(STATE_SYNC(commit).evfd), + STATE(fds)) == -1) { + return -1; + } init_alarm(&STATE_SYNC(reset_cache_alarm), NULL, do_reset_cache_alarm); @@ -329,6 +339,11 @@ static void run_sync(fd_set *readfds) if (FD_ISSET(nlif_fd(STATE_SYNC(interface)), readfds)) interface_handler(); + if (FD_ISSET(get_read_evfd(STATE_SYNC(commit).evfd), readfds)) { + read_evfd(STATE_SYNC(commit).evfd); + cache_commit(STATE_SYNC(external), STATE_SYNC(commit).h, 0); + } + /* flush pending messages */ multichannel_send_flush(STATE_SYNC(channel)); } @@ -344,8 +359,9 @@ static void kill_sync(void) queue_destroy(STATE_SYNC(tx_queue)); - origin_unregister(STATE_SYNC(commit)); - nfct_close(STATE_SYNC(commit)); + origin_unregister(STATE_SYNC(commit).h); + nfct_close(STATE_SYNC(commit).h); + destroy_evfd(STATE_SYNC(commit).evfd); if (STATE_SYNC(sync)->kill) STATE_SYNC(sync)->kill(); @@ -438,14 +454,10 @@ static int local_handler_sync(int fd, int type, void *data) /* delete the reset alarm if any before committing */ del_alarm(&STATE_SYNC(reset_cache_alarm)); - /* fork new process and insert it the process list */ - ret = fork_process_new(CTD_PROC_COMMIT, CTD_PROC_F_EXCL, - NULL, NULL); - if (ret == 0) { - dlog(LOG_NOTICE, "committing external cache"); - cache_commit(STATE_SYNC(external), STATE_SYNC(commit)); - exit(EXIT_SUCCESS); - } + dlog(LOG_NOTICE, "committing external cache"); + cache_commit(STATE_SYNC(external), STATE_SYNC(commit).h, fd); + /* Keep the client socket open, we want synchronous commits. */ + ret = LOCAL_RET_STOLEN; break; case RESET_TIMERS: if (!alarm_pending(&STATE_SYNC(reset_cache_alarm))) { -- cgit v1.2.3 From 4694ae1e0939f69f4d2696b0caff62ce6a17d92f Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 19 Jul 2009 15:31:25 +0200 Subject: conntrackd: improve handling of external messages With this patch, a) we set the file descriptors for the synchronization channels as non-blocking, b) we perform more than one recv() call per select() signal on the socket and c) we limit the iteration to the value that EventIterationLimit has set. Signed-off-by: Pablo Neira Ayuso --- src/mcast.c | 3 ++- src/sync-mode.c | 19 +++++++++++++++++-- src/udp.c | 3 ++- 3 files changed, 21 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/mcast.c b/src/mcast.c index 600fdc2..ec11100 100644 --- a/src/mcast.c +++ b/src/mcast.c @@ -288,7 +288,8 @@ ssize_t mcast_recv(struct mcast_sock *m, void *data, int size) (struct sockaddr *)&m->addr, &sin_size); if (ret == -1) { - m->stats.error++; + if (errno != EAGAIN) + m->stats.error++; return ret; } diff --git a/src/sync-mode.c b/src/sync-mode.c index 7853d91..8cf7aa3 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -36,6 +36,7 @@ #include #include #include +#include static void do_channel_handler_step(int i, struct nethdr *net, size_t remain) @@ -118,7 +119,7 @@ retry: } /* handler for messages received */ -static void channel_handler(struct channel *m, int i) +static int channel_handler_routine(struct channel *m, int i) { ssize_t numbytes; ssize_t remain; @@ -126,7 +127,7 @@ static void channel_handler(struct channel *m, int i) numbytes = channel_recv(m, __net, sizeof(__net)); if (numbytes <= 0) - return; + return -1; remain = numbytes; while (remain > 0) { @@ -167,6 +168,19 @@ static void channel_handler(struct channel *m, int i) ptr += net->len; remain -= net->len; } + return 0; +} + +/* handler for messages received */ +static void channel_handler(struct channel *m, int i) +{ + int k; + + for (k=0; kchannel_num; i++) { int fd = channel_get_fd(STATE_SYNC(channel)->channel[i]); + fcntl(fd, F_SETFL, O_NONBLOCK); if (register_fd(fd, STATE(fds)) == -1) return -1; } diff --git a/src/udp.c b/src/udp.c index d9943a0..4b9eb80 100644 --- a/src/udp.c +++ b/src/udp.c @@ -198,7 +198,8 @@ ssize_t udp_recv(struct udp_sock *m, void *data, int size) (struct sockaddr *)&m->addr, &sin_size); if (ret == -1) { - m->stats.error++; + if (errno != EAGAIN) + m->stats.error++; return ret; } -- cgit v1.2.3 From 441342f4701a4bbc41c24721d4c60b857e1c5d1e Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 19 Jul 2009 15:34:56 +0200 Subject: conntrackd: reset event limit iteration counter With this patch, we reset the event iteration limit counter after we have performed an event handling run. Thus, every run loop always performs a maximum of EventIterationLimit event handling instead of keeping the old credits for the next run loop. Signed-off-by: Pablo Neira Ayuso --- src/run.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/run.c b/src/run.c index 87b6fb2..8a15e14 100644 --- a/src/run.c +++ b/src/run.c @@ -466,6 +466,9 @@ static void __run(struct timeval *next_alarm) /* conntrack event has happened */ if (FD_ISSET(nfct_fd(STATE(event)), &readfds)) { ret = nfct_catch(STATE(event)); + /* reset event iteration limit counter */ + STATE(event_iterations_limit) = + CONFIG(event_iterations_limit); if (ret == -1) { switch(errno) { case ENOBUFS: -- cgit v1.2.3 From 0521db731c0daa417a3dfb67fba7c6f80596e553 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 21 Jul 2009 14:36:18 +0200 Subject: conntrackd: add clause to enable ctnetlink reliable event delivery This patch adds the NetlinkEventsReliable clause, this is useful to turn on reliable Netlink event delivery. This features requires a Linux kernel >= 2.6.31. Signed-off-by: Pablo Neira Ayuso --- doc/stats/conntrackd.conf | 7 +++++++ doc/sync/alarm/conntrackd.conf | 7 +++++++ doc/sync/ftfw/conntrackd.conf | 8 ++++++++ doc/sync/notrack/conntrackd.conf | 7 +++++++ include/conntrackd.h | 3 +++ src/netlink.c | 12 ++++++++++++ src/read_config_lex.l | 1 + src/read_config_yy.y | 13 ++++++++++++- 8 files changed, 57 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/doc/stats/conntrackd.conf b/doc/stats/conntrackd.conf index 8945293..ef6a698 100644 --- a/doc/stats/conntrackd.conf +++ b/doc/stats/conntrackd.conf @@ -110,6 +110,13 @@ Stats { # LogFile on + # If you want reliable event reporting over Netlink, set on this + # option. If you set on this clause, it is a good idea to set off + # NetlinkOverrunResync. This option is off by default and you need + # a Linux kernel >= 2.6.31. + # + # NetlinkEventsReliable Off + # # By default, the daemon receives state updates following an # event-driven model. You can modify this behaviour by switching to diff --git a/doc/sync/alarm/conntrackd.conf b/doc/sync/alarm/conntrackd.conf index a108569..805a531 100644 --- a/doc/sync/alarm/conntrackd.conf +++ b/doc/sync/alarm/conntrackd.conf @@ -278,6 +278,13 @@ General { # # NetlinkOverrunResync On + # If you want reliable event reporting over Netlink, set on this + # option. If you set on this clause, it is a good idea to set off + # NetlinkOverrunResync. This option is off by default and you need + # a Linux kernel >= 2.6.31. + # + # NetlinkEventsReliable Off + # # By default, the daemon receives state updates following an # event-driven model. You can modify this behaviour by switching to diff --git a/doc/sync/ftfw/conntrackd.conf b/doc/sync/ftfw/conntrackd.conf index c1208f9..ceca224 100644 --- a/doc/sync/ftfw/conntrackd.conf +++ b/doc/sync/ftfw/conntrackd.conf @@ -287,6 +287,14 @@ General { # # NetlinkOverrunResync On + # + # If you want reliable event reporting over Netlink, set on this + # option. If you set on this clause, it is a good idea to set off + # NetlinkOverrunResync. This option is off by default and you need + # a Linux kernel >= 2.6.31. + # + # NetlinkEventsReliable Off + # # By default, the daemon receives state updates following an # event-driven model. You can modify this behaviour by switching to diff --git a/doc/sync/notrack/conntrackd.conf b/doc/sync/notrack/conntrackd.conf index b528fab..1efeb81 100644 --- a/doc/sync/notrack/conntrackd.conf +++ b/doc/sync/notrack/conntrackd.conf @@ -268,6 +268,13 @@ General { # # NetlinkOverrunResync On + # If you want reliable event reporting over Netlink, set on this + # option. If you set on this clause, it is a good idea to set off + # NetlinkOverrunResync. This option is off by default and you need + # a Linux kernel >= 2.6.31. + # + # NetlinkEventsReliable Off + # # By default, the daemon receives state updates following an # event-driven model. You can modify this behaviour by switching to diff --git a/include/conntrackd.h b/include/conntrackd.h index 12fd17f..907ce33 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -95,6 +95,9 @@ struct ct_conf { int poll_kernel_secs; int filter_from_kernelspace; int event_iterations_limit; + struct { + int events_reliable; + } netlink; struct { int commit_steps; } general; diff --git a/src/netlink.c b/src/netlink.c index 5c07201..a43f782 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -75,6 +75,18 @@ struct nfct_handle *nl_init_event_handler(void) CONFIG(netlink_buffer_size_max_grown) = CONFIG(netlink_buffer_size); + if (CONFIG(netlink).events_reliable) { + int on = 1; + + setsockopt(nfct_fd(h), SOL_NETLINK, + NETLINK_BROADCAST_SEND_ERROR, &on, sizeof(int)); + + setsockopt(nfct_fd(h), SOL_NETLINK, + NETLINK_NO_ENOBUFS, &on, sizeof(int)); + + dlog(LOG_NOTICE, "reliable ctnetlink event delivery " + "is ENABLED."); + } return h; } diff --git a/src/read_config_lex.l b/src/read_config_lex.l index cd03ad4..dad7555 100644 --- a/src/read_config_lex.l +++ b/src/read_config_lex.l @@ -134,6 +134,7 @@ notrack [N|n][O|o][T|t][R|r][A|a][C|c][K|k] "Scheduler" { return T_SCHEDULER; } "Type" { return T_TYPE; } "Priority" { return T_PRIO; } +"NetlinkEventsReliable" { return T_NETLINK_EVENTS_RELIABLE; } {is_on} { return T_ON; } {is_off} { return T_OFF; } diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 0e9b99b..87f99b6 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -71,7 +71,7 @@ static void __max_dedicated_links_reached(void); %token T_FILTER T_ADDRESS T_PROTOCOL T_STATE T_ACCEPT T_IGNORE %token T_FROM T_USERSPACE T_KERNELSPACE T_EVENT_ITER_LIMIT T_DEFAULT %token T_NETLINK_OVERRUN_RESYNC T_NICE T_IPV4_DEST_ADDR T_IPV6_DEST_ADDR -%token T_SCHEDULER T_TYPE T_PRIO +%token T_SCHEDULER T_TYPE T_PRIO T_NETLINK_EVENTS_RELIABLE %token T_IP T_PATH_VAL %token T_NUMBER @@ -873,6 +873,7 @@ general_line: hashsize | poll_secs | filter | netlink_overrun_resync + | netlink_events_reliable | nice | scheduler ; @@ -902,6 +903,16 @@ netlink_overrun_resync : T_NETLINK_OVERRUN_RESYNC T_NUMBER conf.nl_overrun_resync = $2; }; +netlink_events_reliable : T_NETLINK_EVENTS_RELIABLE T_ON +{ + conf.netlink.events_reliable = 1; +}; + +netlink_events_reliable : T_NETLINK_EVENTS_RELIABLE T_OFF +{ + conf.netlink.events_reliable = 0; +}; + nice : T_NICE T_SIGNED_NUMBER { conf.nice = $2; -- cgit v1.2.3 From e55321739fa5e04920feeb2a25b02073d8eb9e10 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 21 Jul 2009 16:57:54 +0200 Subject: conntrackd: add support for IPv6 kernel-space filtering via BSF This patch adds the missing support to filter IPv6 from kernel-space by means of the BSF API that libnetfilter_conntrack provides. Signed-off-by: Pablo Neira Ayuso --- doc/stats/conntrackd.conf | 1 + doc/sync/alarm/conntrackd.conf | 3 +++ doc/sync/ftfw/conntrackd.conf | 3 +++ doc/sync/notrack/conntrackd.conf | 3 +++ include/cidr.h | 1 + src/cidr.c | 11 +++++++++++ src/read_config_yy.y | 17 ++++++++++++++++- 7 files changed, 38 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/doc/stats/conntrackd.conf b/doc/stats/conntrackd.conf index ef6a698..0941f64 100644 --- a/doc/stats/conntrackd.conf +++ b/doc/stats/conntrackd.conf @@ -88,6 +88,7 @@ General { # Address Ignore { IPv4_address 127.0.0.1 # loopback + # IPv6_address ::1 } # diff --git a/doc/sync/alarm/conntrackd.conf b/doc/sync/alarm/conntrackd.conf index 805a531..800012f 100644 --- a/doc/sync/alarm/conntrackd.conf +++ b/doc/sync/alarm/conntrackd.conf @@ -351,6 +351,9 @@ General { # # You can also specify networks in format IP/cidr. # IPv4_address 192.168.0.0/24 + # + # You can also specify an IPv6 address + # IPv6_address ::1 } # diff --git a/doc/sync/ftfw/conntrackd.conf b/doc/sync/ftfw/conntrackd.conf index ceca224..602c3d1 100644 --- a/doc/sync/ftfw/conntrackd.conf +++ b/doc/sync/ftfw/conntrackd.conf @@ -361,6 +361,9 @@ General { # # You can also specify networks in format IP/cidr. # IPv4_address 192.168.0.0/24 + # + # You can also specify an IPv6 address + # IPv6_address ::1 } # diff --git a/doc/sync/notrack/conntrackd.conf b/doc/sync/notrack/conntrackd.conf index 1efeb81..6968025 100644 --- a/doc/sync/notrack/conntrackd.conf +++ b/doc/sync/notrack/conntrackd.conf @@ -341,6 +341,9 @@ General { # # You can also specify networks in format IP/cidr. # IPv4_address 192.168.0.0/24 + # + # You can also specify an IPv6 address + # IPv6_address ::1 } # diff --git a/include/cidr.h b/include/cidr.h index f8a4e2a..413c321 100644 --- a/include/cidr.h +++ b/include/cidr.h @@ -4,5 +4,6 @@ uint32_t ipv4_cidr2mask_host(uint8_t cidr); uint32_t ipv4_cidr2mask_net(uint8_t cidr); void ipv6_cidr2mask_host(uint8_t cidr, uint32_t *res); void ipv6_cidr2mask_net(uint8_t cidr, uint32_t *res); +void ipv6_addr2addr_host(uint32_t *addr, uint32_t *res); #endif diff --git a/src/cidr.c b/src/cidr.c index d43dabc..91025b6 100644 --- a/src/cidr.c +++ b/src/cidr.c @@ -57,3 +57,14 @@ void ipv6_cidr2mask_net(uint8_t cidr, uint32_t *res) res[i] = htonl(res[i]); } +/* I need this function because I initially defined an IPv6 address as + * uint32 u[4]. Using char u[16] instead would allow to remove this. */ +void ipv6_addr2addr_host(uint32_t *addr, uint32_t *res) +{ + int i; + + memset(res, 0, sizeof(uint32_t)*4); + for (i = 0; i < 4; i++) { + res[i] = ntohl(addr[i]); + } +} diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 87f99b6..f3f4730 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -1053,6 +1053,12 @@ filter_item : T_ADDRESS T_IGNORE '{' filter_address_list '}' nfct_filter_set_logic(STATE(filter), NFCT_FILTER_DST_IPV4, NFCT_FILTER_LOGIC_NEGATIVE); + nfct_filter_set_logic(STATE(filter), + NFCT_FILTER_SRC_IPV6, + NFCT_FILTER_LOGIC_NEGATIVE); + nfct_filter_set_logic(STATE(filter), + NFCT_FILTER_DST_IPV6, + NFCT_FILTER_LOGIC_NEGATIVE); }; filter_address_list : @@ -1121,7 +1127,8 @@ filter_address_item : T_IPV6_ADDR T_IP { union inet_address ip; char *slash; - int cidr; + int cidr = 128; + struct nfct_filter_ipv6 filter_ipv6; memset(&ip, 0, sizeof(union inet_address)); @@ -1166,6 +1173,14 @@ filter_address_item : T_IPV6_ADDR T_IP "ignore pool!"); } } + __kernel_filter_start(); + + /* host byte order */ + ipv6_addr2addr_host(ip.ipv6, filter_ipv6.addr); + ipv6_cidr2mask_host(cidr, filter_ipv6.mask); + + nfct_filter_add_attr(STATE(filter), NFCT_FILTER_SRC_IPV6, &filter_ipv6); + nfct_filter_add_attr(STATE(filter), NFCT_FILTER_DST_IPV6, &filter_ipv6); }; filter_item : T_STATE T_ACCEPT '{' filter_state_list '}' -- cgit v1.2.3 From 817f847b52bb05c924491deb994194fd5c1c3ba2 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 21 Jul 2009 16:58:43 +0200 Subject: conntrackd: use conntrack ID in the cache lookup This patch adds the conntrack ID to the comparison that is made in the lookup of entries that are stored in the cache. For old kernels, this field is set to zero for all entries so this patch does not make any difference. For recent kernels, this allows to keep two entries with the same tuple and different IDs: this is possible if NetlinkEventsReliable is set on. Moreover, this patch is useful to test the reliable ctnetlink event delivery in 2.6.31 works fine. Signed-off-by: Pablo Neira Ayuso --- src/cache.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/cache.c b/src/cache.c index f95bef6..ccdce86 100644 --- a/src/cache.c +++ b/src/cache.c @@ -90,7 +90,9 @@ static int compare(const void *data1, const void *data2) const struct cache_object *obj = data1; const struct nf_conntrack *ct = data2; - return nfct_cmp(obj->ct, ct, NFCT_CMP_ORIG); + return nfct_cmp(obj->ct, ct, NFCT_CMP_ORIG) && + nfct_get_attr_u32(obj->ct, ATTR_ID) == + nfct_get_attr_u32(ct, ATTR_ID); } struct cache_feature *cache_feature[CACHE_MAX_FEATURE] = { -- cgit v1.2.3 From 2c5bed23c8afdd7f349d861fb7e7c8ba33ae3fe1 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 14 Aug 2009 16:33:42 +0200 Subject: conntrackd: fix crash for unubuffered channel on exit path This patch fixes a crash in the exit path for channels that are not buffered (no CHANNEL_F_BUFFERED flag set). This fix does not affect any existing channel in the tree. Signed-off-by: Pablo Neira Ayuso --- src/channel.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/channel.c b/src/channel.c index 255026a..9d74b7f 100644 --- a/src/channel.c +++ b/src/channel.c @@ -57,6 +57,9 @@ channel_buffer_open(int mtu) static void channel_buffer_close(struct channel_buffer *b) { + if (b == NULL) + return; + free(b->data); free(b); } -- cgit v1.2.3 From 32ca6a144903b2e6318ee61d1dda3f670d3c09da Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 17 Aug 2009 12:51:34 +0200 Subject: conntrackd: more robust sanity checking on synchronization messages This patch fixes an infinite loop that can occur if a message of zero length is received. Moreover, now we always stop the processing if the message is malformed. Signed-off-by: Pablo Neira Ayuso --- src/sync-mode.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/sync-mode.c b/src/sync-mode.c index 8cf7aa3..9e3ac39 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -132,6 +132,7 @@ static int channel_handler_routine(struct channel *m, int i) remain = numbytes; while (remain > 0) { struct nethdr *net = (struct nethdr *) ptr; + int len; if (remain < NETHDR_SIZ) { STATE_SYNC(error).msg_rcv_malformed++; @@ -139,7 +140,8 @@ static int channel_handler_routine(struct channel *m, int i) break; } - if (ntohs(net->len) > remain) { + len = ntohs(net->len); + if (len > remain || len <= 0) { STATE_SYNC(error).msg_rcv_malformed++; STATE_SYNC(error).msg_rcv_bad_size++; break; @@ -149,16 +151,19 @@ static int channel_handler_routine(struct channel *m, int i) if (remain < NETHDR_ACK_SIZ) { STATE_SYNC(error).msg_rcv_malformed++; STATE_SYNC(error).msg_rcv_truncated++; + break; } - if (ntohs(net->len) < NETHDR_ACK_SIZ) { + if (len < NETHDR_ACK_SIZ) { STATE_SYNC(error).msg_rcv_malformed++; STATE_SYNC(error).msg_rcv_bad_size++; + break; } } else { - if (ntohs(net->len) < NETHDR_SIZ) { + if (len < NETHDR_SIZ) { STATE_SYNC(error).msg_rcv_malformed++; STATE_SYNC(error).msg_rcv_bad_size++; + break; } } -- cgit v1.2.3 From 3e6852f806c4368eda451b39f12b2ac2f2b5d33b Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 19 Aug 2009 16:59:38 +0200 Subject: conntrackd: add `DisableExternalCache' clause This patch adds the clause `DisableExternalCache' that allows you to disable the external cache and to directly inject the entries into the kernel conntrack table. As a result, the CPU consumption of conntrackd increases. This clause can only be used with the FT-FW and the notrack synchronization modes, but not with the alarm mode. Signed-off-by: Pablo Neira Ayuso --- doc/sync/ftfw/conntrackd.conf | 13 ++++ doc/sync/notrack/conntrackd.conf | 13 ++++ include/Makefile.am | 2 +- include/conntrackd.h | 5 +- include/external.h | 24 +++++++ include/origin.h | 1 + src/Makefile.am | 1 + src/external_cache.c | 122 +++++++++++++++++++++++++++++++ src/external_inject.c | 150 +++++++++++++++++++++++++++++++++++++++ src/read_config_lex.l | 1 + src/read_config_yy.y | 13 ++++ src/sync-mode.c | 73 +++++++++---------- 12 files changed, 375 insertions(+), 43 deletions(-) create mode 100644 include/external.h create mode 100644 src/external_cache.c create mode 100644 src/external_inject.c (limited to 'src') diff --git a/doc/sync/ftfw/conntrackd.conf b/doc/sync/ftfw/conntrackd.conf index 602c3d1..76c3aef 100644 --- a/doc/sync/ftfw/conntrackd.conf +++ b/doc/sync/ftfw/conntrackd.conf @@ -189,6 +189,19 @@ Sync { # # Checksum on # } + + # + # This clause allows you to disable the external cache. Thus, the + # state entries are directly injected into the kernel conntrack + # table. As a result, you save memory in user-space but you consume + # slots in the kernel conntrack table for backup state entries. + # Moreover, disabling the external cache means more CPU consumption. + # You need a Linux kernel >= 2.6.29 to use this feature. By default, + # this clause is set off. If you are installing conntrackd for first + # time, please read the user manual and I encourage you to consider + # using the fail-over scripts instead of enabling this option! + # + # DisableExternalCache Off } # diff --git a/doc/sync/notrack/conntrackd.conf b/doc/sync/notrack/conntrackd.conf index 6968025..9cdb2c7 100644 --- a/doc/sync/notrack/conntrackd.conf +++ b/doc/sync/notrack/conntrackd.conf @@ -170,6 +170,19 @@ Sync { # # Checksum on # } + + # + # This clause allows you to disable the external cache. Thus, the + # state entries are directly injected into the kernel conntrack + # table. As a result, you save memory in user-space but you consume + # slots in the kernel conntrack table for backup state entries. + # Moreover, disabling the external cache means more CPU consumption. + # You need a Linux kernel >= 2.6.29 to use this feature. By default, + # this clause is set off. If you are installing conntrackd for first + # time, please read the user manual and I encourage you to consider + # using the fail-over scripts instead of enabling this option! + # + # DisableExternalCache Off } # diff --git a/include/Makefile.am b/include/Makefile.am index b72fb36..0fa76af 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -4,5 +4,5 @@ noinst_HEADERS = alarm.h jhash.h cache.h linux_list.h linux_rbtree.h \ debug.h log.h hash.h mcast.h conntrack.h \ network.h filter.h queue.h vector.h cidr.h \ traffic_stats.h netlink.h fds.h event.h bitops.h channel.h \ - process.h origin.h + process.h origin.h external.h diff --git a/include/conntrackd.h b/include/conntrackd.h index 907ce33..ce8f9d4 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -95,6 +95,9 @@ struct ct_conf { int poll_kernel_secs; int filter_from_kernelspace; int event_iterations_limit; + struct { + int external_cache_disable; + } sync; struct { int events_reliable; } netlink; @@ -172,7 +175,7 @@ struct ct_general_state { struct ct_sync_state { struct cache *internal; /* internal events cache (netlink) */ - struct cache *external; /* external events cache (mcast) */ + struct external_handler *external; struct multichannel *channel; struct nlif_handle *interface; diff --git a/include/external.h b/include/external.h new file mode 100644 index 0000000..938941a --- /dev/null +++ b/include/external.h @@ -0,0 +1,24 @@ +#ifndef _EXTERNAL_H_ +#define _EXTERNAL_H_ + +struct nf_conntrack; + +struct external_handler { + int (*init)(void); + void (*close)(void); + + void (*new)(struct nf_conntrack *ct); + void (*update)(struct nf_conntrack *ct); + void (*destroy)(struct nf_conntrack *ct); + + void (*dump)(int fd, int type); + void (*flush)(void); + void (*commit)(struct nfct_handle *h, int fd); + void (*stats)(int fd); + void (*stats_ext)(int fd); +}; + +extern struct external_handler external_cache; +extern struct external_handler external_inject; + +#endif diff --git a/include/origin.h b/include/origin.h index 89308f3..1b974e9 100644 --- a/include/origin.h +++ b/include/origin.h @@ -6,6 +6,7 @@ enum { any process, but not conntrackd */ CTD_ORIGIN_COMMIT, /* event comes from committer */ CTD_ORIGIN_FLUSH, /* event comes from flush */ + CTD_ORIGIN_INJECT, /* event comes from direct inject */ }; int origin_register(struct nfct_handle *h, int origin_type); diff --git a/src/Makefile.am b/src/Makefile.am index 1c8b34f..753c809 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -20,6 +20,7 @@ conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c rbtree.c \ network.c cidr.c \ build.c parse.c \ channel.c multichannel.c channel_mcast.c channel_udp.c \ + external_cache.c external_inject.c \ read_config_yy.y read_config_lex.l # yacc and lex generate dirty code diff --git a/src/external_cache.c b/src/external_cache.c new file mode 100644 index 0000000..c70c818 --- /dev/null +++ b/src/external_cache.c @@ -0,0 +1,122 @@ +/* + * (C) 2006-2009 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "conntrackd.h" +#include "sync.h" +#include "log.h" +#include "cache.h" +#include "external.h" + +#include +#include + +static struct cache *external; + +static int external_cache_init(void) +{ + external = cache_create("external", + STATE_SYNC(sync)->external_cache_flags, + NULL); + if (external == NULL) { + dlog(LOG_ERR, "can't allocate memory for the external cache"); + return -1; + } + return 0; +} + +static void external_cache_close(void) +{ + cache_destroy(external); +} + +static void external_cache_new(struct nf_conntrack *ct) +{ + struct cache_object *obj; + int id; + + obj = cache_find(external, ct, &id); + if (obj == NULL) { +retry: + obj = cache_object_new(external, ct); + if (obj == NULL) + return; + + if (cache_add(external, obj, id) == -1) { + cache_object_free(obj); + return; + } + } else { + cache_del(external, obj); + cache_object_free(obj); + goto retry; + } +} + +static void external_cache_upd(struct nf_conntrack *ct) +{ + cache_update_force(external, ct); +} + +static void external_cache_del(struct nf_conntrack *ct) +{ + struct cache_object *obj; + int id; + + obj = cache_find(external, ct, &id); + if (obj) { + cache_del(external, obj); + cache_object_free(obj); + } +} + +static void external_cache_dump(int fd, int type) +{ + cache_dump(external, fd, type); +} + +static void external_cache_commit(struct nfct_handle *h, int fd) +{ + cache_commit(external, h, fd); +} + +static void external_cache_flush(void) +{ + cache_flush(external); +} + +static void external_cache_stats(int fd) +{ + cache_stats(external, fd); +} + +static void external_cache_stats_ext(int fd) +{ + cache_stats_extended(external, fd); +} + +struct external_handler external_cache = { + .init = external_cache_init, + .close = external_cache_close, + .new = external_cache_new, + .update = external_cache_upd, + .destroy = external_cache_del, + .dump = external_cache_dump, + .commit = external_cache_commit, + .flush = external_cache_flush, + .stats = external_cache_stats, + .stats_ext = external_cache_stats_ext, +}; diff --git a/src/external_inject.c b/src/external_inject.c new file mode 100644 index 0000000..ec1cb16 --- /dev/null +++ b/src/external_inject.c @@ -0,0 +1,150 @@ +/* + * (C) 2009 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "conntrackd.h" +#include "sync.h" +#include "log.h" +#include "cache.h" +#include "origin.h" +#include "external.h" +#include "netlink.h" + +#include +#include +#include + +static struct nfct_handle *inject; + +static int external_inject_init(void) +{ + /* handler to directly inject conntracks into kernel-space */ + inject = nfct_open(CONNTRACK, 0); + if (inject == NULL) { + dlog(LOG_ERR, "can't open netlink handler: %s", + strerror(errno)); + dlog(LOG_ERR, "no ctnetlink kernel support?"); + return -1; + } + /* we are directly injecting the entries into the kernel */ + origin_register(inject, CTD_ORIGIN_INJECT); + return 0; +} + +static void external_inject_close(void) +{ + origin_unregister(inject); + nfct_close(inject); +} + +static void external_inject_new(struct nf_conntrack *ct) +{ + int ret, retry = 1; + +retry: + if (nl_create_conntrack(inject, ct, 0) == -1) { + /* if the state entry exists, we delete and try again */ + if (errno == EEXIST && retry == 1) { + ret = nl_destroy_conntrack(inject, ct); + if (ret == 0 || (ret == -1 && errno == ENOENT)) { + if (retry) { + retry = 0; + goto retry; + } + } + dlog(LOG_ERR, "inject-add1: %s", strerror(errno)); + dlog_ct(STATE(log), ct, NFCT_O_PLAIN); + return; + } + dlog(LOG_ERR, "inject-add2: %s", strerror(errno)); + dlog_ct(STATE(log), ct, NFCT_O_PLAIN); + } +} + +static void external_inject_upd(struct nf_conntrack *ct) +{ + int ret; + + /* if we successfully update the entry, everything is OK */ + if (nl_update_conntrack(inject, ct, 0) != -1) + return; + + /* state entries does not exist, we have to create it */ + if (errno == ENOENT) { + if (nl_create_conntrack(inject, ct, 0) == -1) { + dlog(LOG_ERR, "inject-upd1: %s", strerror(errno)); + dlog_ct(STATE(log), ct, NFCT_O_PLAIN); + } + return; + } + + /* we failed to update the entry, there are some operations that + * may trigger this error, eg. unset some status bits. Try harder, + * delete the existing entry and create a new one. */ + ret = nl_destroy_conntrack(inject, ct); + if (ret == 0 || (ret == -1 && errno == ENOENT)) { + if (nl_create_conntrack(inject, ct, 0) == -1) { + dlog(LOG_ERR, "inject-upd2: %s", strerror(errno)); + dlog_ct(STATE(log), ct, NFCT_O_PLAIN); + } + return; + } + dlog(LOG_ERR, "inject-upd3: %s", strerror(errno)); + dlog_ct(STATE(log), ct, NFCT_O_PLAIN); +} + +static void external_inject_del(struct nf_conntrack *ct) +{ + if (nl_destroy_conntrack(inject, ct) == -1) { + if (errno != ENOENT) { + dlog(LOG_ERR, "inject-del: %s", strerror(errno)); + dlog_ct(STATE(log), ct, NFCT_O_PLAIN); + } + } +} + +static void external_inject_dump(int fd, int type) +{ +} + +static void external_inject_commit(struct nfct_handle *h, int fd) +{ +} + +static void external_inject_flush(void) +{ +} + +static void external_inject_stats(int fd) +{ +} + +static void external_inject_stats_ext(int fd) +{ +} + +struct external_handler external_inject = { + .init = external_inject_init, + .close = external_inject_close, + .new = external_inject_new, + .update = external_inject_upd, + .destroy = external_inject_del, + .dump = external_inject_dump, + .commit = external_inject_commit, + .flush = external_inject_flush, + .stats = external_inject_stats, + .stats_ext = external_inject_stats_ext, +}; diff --git a/src/read_config_lex.l b/src/read_config_lex.l index dad7555..d3f83aa 100644 --- a/src/read_config_lex.l +++ b/src/read_config_lex.l @@ -135,6 +135,7 @@ notrack [N|n][O|o][T|t][R|r][A|a][C|c][K|k] "Type" { return T_TYPE; } "Priority" { return T_PRIO; } "NetlinkEventsReliable" { return T_NETLINK_EVENTS_RELIABLE; } +"DisableExternalCache" { return T_DISABLE_EXTERNAL_CACHE; } {is_on} { return T_ON; } {is_off} { return T_OFF; } diff --git a/src/read_config_yy.y b/src/read_config_yy.y index f3f4730..38c5929 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -72,6 +72,7 @@ static void __max_dedicated_links_reached(void); %token T_FROM T_USERSPACE T_KERNELSPACE T_EVENT_ITER_LIMIT T_DEFAULT %token T_NETLINK_OVERRUN_RESYNC T_NICE T_IPV4_DEST_ADDR T_IPV6_DEST_ADDR %token T_SCHEDULER T_TYPE T_PRIO T_NETLINK_EVENTS_RELIABLE +%token T_DISABLE_EXTERNAL_CACHE %token T_IP T_PATH_VAL %token T_NUMBER @@ -698,6 +699,7 @@ sync_mode_ftfw_line: resend_queue_size | timeout | purge | window_size + | disable_external_cache ; sync_mode_notrack_list: @@ -705,8 +707,19 @@ sync_mode_notrack_list: sync_mode_notrack_line: timeout | purge + | disable_external_cache ; +disable_external_cache: T_DISABLE_EXTERNAL_CACHE T_ON +{ + conf.sync.external_cache_disable = 1; +}; + +disable_external_cache: T_DISABLE_EXTERNAL_CACHE T_OFF +{ + conf.sync.external_cache_disable = 0; +}; + resend_buffer_size: T_RESEND_BUFFER_SIZE T_NUMBER { print_err(CTD_CFG_WARN, "`ResendBufferSize' is deprecated. " diff --git a/src/sync-mode.c b/src/sync-mode.c index 9e3ac39..174df80 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -28,6 +28,7 @@ #include "queue.h" #include "process.h" #include "origin.h" +#include "external.h" #include #include @@ -43,8 +44,6 @@ do_channel_handler_step(int i, struct nethdr *net, size_t remain) { char __ct[nfct_maxsize()]; struct nf_conntrack *ct = (struct nf_conntrack *)(void*) __ct; - struct cache_object *obj; - int id; if (net->version != CONNTRACKD_PROTOCOL_VERSION) { STATE_SYNC(error).msg_rcv_malformed++; @@ -84,32 +83,13 @@ do_channel_handler_step(int i, struct nethdr *net, size_t remain) switch(net->type) { case NET_T_STATE_NEW: - obj = cache_find(STATE_SYNC(external), ct, &id); - if (obj == NULL) { -retry: - obj = cache_object_new(STATE_SYNC(external), ct); - if (obj == NULL) - return; - - if (cache_add(STATE_SYNC(external), obj, id) == -1) { - cache_object_free(obj); - return; - } - } else { - cache_del(STATE_SYNC(external), obj); - cache_object_free(obj); - goto retry; - } + STATE_SYNC(external)->new(ct); break; case NET_T_STATE_UPD: - cache_update_force(STATE_SYNC(external), ct); + STATE_SYNC(external)->update(ct); break; case NET_T_STATE_DEL: - obj = cache_find(STATE_SYNC(external), ct, &id); - if (obj) { - cache_del(STATE_SYNC(external), obj); - cache_object_free(obj); - } + STATE_SYNC(external)->destroy(ct); break; default: STATE_SYNC(error).msg_rcv_malformed++; @@ -275,15 +255,14 @@ static int init_sync(void) return -1; } - STATE_SYNC(external) = - cache_create("external", - STATE_SYNC(sync)->external_cache_flags, - NULL); - - if (!STATE_SYNC(external)) { - dlog(LOG_ERR, "can't allocate memory for the external cache"); - return -1; + if (CONFIG(sync).external_cache_disable == 0) { + STATE_SYNC(external) = &external_cache; + } else { + STATE_SYNC(external) = &external_inject; + dlog(LOG_NOTICE, "disabling external cache"); } + if (STATE_SYNC(external)->init() == -1) + return -1; channel_init(); @@ -361,7 +340,7 @@ static void run_sync(fd_set *readfds) if (FD_ISSET(get_read_evfd(STATE_SYNC(commit).evfd), readfds)) { read_evfd(STATE_SYNC(commit).evfd); - cache_commit(STATE_SYNC(external), STATE_SYNC(commit).h, 0); + STATE_SYNC(external)->commit(STATE_SYNC(commit).h, 0); } /* flush pending messages */ @@ -371,7 +350,7 @@ static void run_sync(fd_set *readfds) static void kill_sync(void) { cache_destroy(STATE_SYNC(internal)); - cache_destroy(STATE_SYNC(external)); + STATE_SYNC(external)->close(); multichannel_close(STATE_SYNC(channel)); @@ -452,7 +431,7 @@ static int local_handler_sync(int fd, int type, void *data) case DUMP_EXTERNAL: ret = fork_process_new(CTD_PROC_ANY, 0, NULL, NULL); if (ret == 0) { - cache_dump(STATE_SYNC(external), fd, NFCT_O_PLAIN); + STATE_SYNC(external)->dump(fd, NFCT_O_PLAIN); exit(EXIT_SUCCESS); } break; @@ -466,7 +445,7 @@ static int local_handler_sync(int fd, int type, void *data) case DUMP_EXT_XML: ret = fork_process_new(CTD_PROC_ANY, 0, NULL, NULL); if (ret == 0) { - cache_dump(STATE_SYNC(external), fd, NFCT_O_XML); + STATE_SYNC(external)->dump(fd, NFCT_O_XML); exit(EXIT_SUCCESS); } break; @@ -475,7 +454,7 @@ static int local_handler_sync(int fd, int type, void *data) del_alarm(&STATE_SYNC(reset_cache_alarm)); dlog(LOG_NOTICE, "committing external cache"); - cache_commit(STATE_SYNC(external), STATE_SYNC(commit).h, fd); + STATE_SYNC(external)->commit(STATE_SYNC(commit).h, fd); /* Keep the client socket open, we want synchronous commits. */ ret = LOCAL_RET_STOLEN; break; @@ -492,7 +471,7 @@ static int local_handler_sync(int fd, int type, void *data) del_alarm(&STATE_SYNC(reset_cache_alarm)); dlog(LOG_NOTICE, "flushing caches"); cache_flush(STATE_SYNC(internal)); - cache_flush(STATE_SYNC(external)); + STATE_SYNC(external)->flush(); break; case FLUSH_INT_CACHE: /* inmediate flush, remove pending flush scheduled if any */ @@ -502,14 +481,14 @@ static int local_handler_sync(int fd, int type, void *data) break; case FLUSH_EXT_CACHE: dlog(LOG_NOTICE, "flushing external cache"); - cache_flush(STATE_SYNC(external)); + STATE_SYNC(external)->flush(); break; case KILL: killer(0); break; case STATS: cache_stats(STATE_SYNC(internal), fd); - cache_stats(STATE_SYNC(external), fd); + STATE_SYNC(external)->stats(fd); dump_traffic_stats(fd); multichannel_stats(STATE_SYNC(channel), fd); dump_stats_sync(fd); @@ -520,7 +499,7 @@ static int local_handler_sync(int fd, int type, void *data) break; case STATS_CACHE: cache_stats_extended(STATE_SYNC(internal), fd); - cache_stats_extended(STATE_SYNC(external), fd); + STATE_SYNC(external)->stats_ext(fd); break; case STATS_LINK: multichannel_stats_extended(STATE_SYNC(channel), @@ -616,6 +595,10 @@ event_new_sync(struct nf_conntrack *ct, int origin) struct cache_object *obj; int id; + /* this event has been triggered by a direct inject, skip */ + if (origin == CTD_ORIGIN_INJECT) + return; + /* required by linux kernel <= 2.6.20 */ nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES); nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS); @@ -649,6 +632,10 @@ event_update_sync(struct nf_conntrack *ct, int origin) { struct cache_object *obj; + /* this event has been triggered by a direct inject, skip */ + if (origin == CTD_ORIGIN_INJECT) + return; + obj = cache_update_force(STATE_SYNC(internal), ct); if (obj == NULL) return; @@ -663,6 +650,10 @@ event_destroy_sync(struct nf_conntrack *ct, int origin) struct cache_object *obj; int id; + /* this event has been triggered by a direct inject, skip */ + if (origin == CTD_ORIGIN_INJECT) + return 0; + /* we don't synchronize events for objects that are not in the cache */ obj = cache_find(STATE_SYNC(internal), ct, &id); if (obj == NULL) -- cgit v1.2.3 From 58411110894c0a9e6a1a1ec9dbdf2fbe2ef3da00 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 21 Aug 2009 16:06:08 +0200 Subject: conntrackd: reduce the number of gettimeofday() syscalls This patch reduces the number of gettimeofday syscalls by caching the current time in a variable at the beginning of the main loop. Based on a suggestion from Vincent Jardin. Signed-off-by: Pablo Neira Ayuso --- include/Makefile.am | 2 +- include/cache.h | 1 + include/date.h | 10 ++++++++++ src/Makefile.am | 2 +- src/alarm.c | 7 ++++--- src/cache.c | 4 ++-- src/date.c | 28 ++++++++++++++++++++++++++++ src/run.c | 3 +++ 8 files changed, 50 insertions(+), 7 deletions(-) create mode 100644 include/date.h create mode 100644 src/date.c (limited to 'src') diff --git a/include/Makefile.am b/include/Makefile.am index 0fa76af..844c5b8 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -4,5 +4,5 @@ noinst_HEADERS = alarm.h jhash.h cache.h linux_list.h linux_rbtree.h \ debug.h log.h hash.h mcast.h conntrack.h \ network.h filter.h queue.h vector.h cidr.h \ traffic_stats.h netlink.h fds.h event.h bitops.h channel.h \ - process.h origin.h external.h + process.h origin.h external.h date.h diff --git a/include/cache.h b/include/cache.h index 7e61085..28917f2 100644 --- a/include/cache.h +++ b/include/cache.h @@ -4,6 +4,7 @@ #include #include #include "hash.h" +#include "date.h" /* cache features */ enum { diff --git a/include/date.h b/include/date.h new file mode 100644 index 0000000..296b996 --- /dev/null +++ b/include/date.h @@ -0,0 +1,10 @@ +#ifndef _DATE_H_ +#define _DATE_H_ + +#include + +int do_gettimeofday(void); +void gettimeofday_cached(struct timeval *tv); +int time_cached(void); + +#endif diff --git a/src/Makefile.am b/src/Makefile.am index 753c809..e969f4d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -12,7 +12,7 @@ conntrack_LDFLAGS = $(all_libraries) @LIBNETFILTER_CONNTRACK_LIBS@ conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c rbtree.c \ local.c log.c mcast.c udp.c netlink.c vector.c \ - filter.c fds.c event.c process.c origin.c \ + filter.c fds.c event.c process.c origin.c date.c \ cache.c cache_iterators.c \ cache_timer.c \ sync-mode.c sync-alarm.c sync-ftfw.c sync-notrack.c \ diff --git a/src/alarm.c b/src/alarm.c index fe938a0..006721a 100644 --- a/src/alarm.c +++ b/src/alarm.c @@ -17,6 +17,7 @@ */ #include "alarm.h" +#include "date.h" #include #include @@ -61,7 +62,7 @@ void add_alarm(struct alarm_block *alarm, unsigned long sc, unsigned long usc) del_alarm(alarm); alarm->tv.tv_sec = sc; alarm->tv.tv_usec = usc; - gettimeofday(&tv, NULL); + gettimeofday_cached(&tv); timeradd(&alarm->tv, &tv, &alarm->tv); __add_alarm(alarm); } @@ -107,7 +108,7 @@ get_next_alarm_run(struct timeval *next_run) struct rb_node *node; struct timeval tv; - gettimeofday(&tv, NULL); + gettimeofday_cached(&tv); node = rb_first(&alarm_root); if (node) { @@ -126,7 +127,7 @@ do_alarm_run(struct timeval *next_run) struct alarm_block *this, *tmp; struct timeval tv; - gettimeofday(&tv, NULL); + gettimeofday_cached(&tv); INIT_LIST_HEAD(&alarm_run_queue); for (node = rb_first(&alarm_root); node; node = rb_next(node)) { diff --git a/src/cache.c b/src/cache.c index ccdce86..74c5c4b 100644 --- a/src/cache.c +++ b/src/cache.c @@ -250,7 +250,7 @@ static int __add(struct cache *c, struct cache_object *obj, int id) c->extra->add(obj, ((char *) obj) + c->extra_offset); c->stats.active++; - obj->lifetime = obj->lastupdate = time(NULL); + obj->lifetime = obj->lastupdate = time_cached(); obj->status = C_OBJ_NEW; obj->refcnt++; return 0; @@ -288,7 +288,7 @@ void cache_update(struct cache *c, struct cache_object *obj, int id, c->extra->update(obj, ((char *) obj) + c->extra_offset); c->stats.upd_ok++; - obj->lastupdate = time(NULL); + obj->lastupdate = time_cached(); obj->status = C_OBJ_ALIVE; } diff --git a/src/date.c b/src/date.c new file mode 100644 index 0000000..f5a5ada --- /dev/null +++ b/src/date.c @@ -0,0 +1,28 @@ +/* + * (C) 2009 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 "date.h" +#include +#include + +static struct timeval now; + +int do_gettimeofday(void) +{ + return gettimeofday(&now, NULL); +} + +void gettimeofday_cached(struct timeval *tv) +{ + memcpy(tv, &now, sizeof(struct timeval)); +} + +int time_cached(void) +{ + return now.tv_sec; +} diff --git a/src/run.c b/src/run.c index 8a15e14..54ab1a5 100644 --- a/src/run.c +++ b/src/run.c @@ -27,6 +27,7 @@ #include "traffic_stats.h" #include "process.h" #include "origin.h" +#include "date.h" #include #include @@ -545,6 +546,8 @@ run(void) struct timeval *next = NULL; while(1) { + do_gettimeofday(); + sigprocmask(SIG_BLOCK, &STATE(block), NULL); if (next != NULL && !timerisset(next)) next = do_alarm_run(&next_alarm); -- cgit v1.2.3 From 9d99a7699d7021a1c219d6553e037ac7ba4a5a37 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 21 Aug 2009 16:06:11 +0200 Subject: conntrackd: allow to remove file descriptors from set With this patch, we can remove file descriptors dinamically from our own file descriptor pool. Signed-off-by: Pablo Neira Ayuso --- include/fds.h | 9 +++++++++ src/fds.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) (limited to 'src') diff --git a/include/fds.h b/include/fds.h index 019d3f9..f3728d7 100644 --- a/include/fds.h +++ b/include/fds.h @@ -1,13 +1,22 @@ #ifndef _FDS_H_ #define _FDS_H_ +#include "linux_list.h" + struct fds { int maxfd; fd_set readfds; + struct list_head list; +}; + +struct fds_item { + struct list_head head; + int fd; }; struct fds *create_fds(void); void destroy_fds(struct fds *); int register_fd(int fd, struct fds *fds); +int unregister_fd(int fd, struct fds *fds); #endif diff --git a/src/fds.c b/src/fds.c index fac3482..6304fcd 100644 --- a/src/fds.c +++ b/src/fds.c @@ -27,20 +27,66 @@ struct fds *create_fds(void) if (fds == NULL) return NULL; + INIT_LIST_HEAD(&fds->list); + return fds; } void destroy_fds(struct fds *fds) { + struct fds_item *this, *tmp; + + list_for_each_entry_safe(this, tmp, &fds->list, head) { + list_del(&this->head); + FD_CLR(this->fd, &fds->readfds); + free(this); + } free(fds); } int register_fd(int fd, struct fds *fds) { + struct fds_item *item; + FD_SET(fd, &fds->readfds); if (fd > fds->maxfd) fds->maxfd = fd; + item = calloc(sizeof(struct fds_item), 1); + if (item == NULL) + return -1; + + item->fd = fd; + list_add(&item->head, &fds->list); + return 0; } + +int unregister_fd(int fd, struct fds *fds) +{ + int found = 0, maxfd = -1; + struct fds_item *this, *tmp; + + list_for_each_entry_safe(this, tmp, &fds->list, head) { + if (this->fd == fd) { + list_del(&this->head); + FD_CLR(this->fd, &fds->readfds); + free(this); + found = 1; + /* ... and recalculate maxfd, see below. */ + } + } + /* not found, report an error. */ + if (!found) + return -1; + + /* calculate the new maximum fd. */ + list_for_each_entry(this, &fds->list, head) { + if (maxfd < this->fd) { + maxfd = this->fd; + } + } + return 0; +} + -- cgit v1.2.3 From cf3be894fcb95adb360425c8482954522e9110d2 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 23 Aug 2009 12:11:20 +0200 Subject: conntrackd: add support state-replication based on TCP This patch adds support for TCP as protocol to replicate state-changes between two daemons. Note that this only makes sense with the notrack mode. Signed-off-by: Pablo Neira Ayuso --- doc/sync/notrack/conntrackd.conf | 3 +- include/Makefile.am | 2 +- include/channel.h | 18 +- include/mcast.h | 1 + include/tcp.h | 75 +++++++ include/udp.h | 1 + src/Makefile.am | 1 + src/channel.c | 17 ++ src/channel_mcast.c | 15 ++ src/channel_tcp.c | 149 +++++++++++++ src/channel_udp.c | 15 ++ src/mcast.c | 5 + src/read_config_lex.l | 1 + src/read_config_yy.y | 158 +++++++++++++- src/sync-mode.c | 65 ++++-- src/tcp.c | 440 +++++++++++++++++++++++++++++++++++++++ src/udp.c | 5 + 17 files changed, 954 insertions(+), 17 deletions(-) create mode 100644 include/tcp.h create mode 100644 src/channel_tcp.c create mode 100644 src/tcp.c (limited to 'src') diff --git a/doc/sync/notrack/conntrackd.conf b/doc/sync/notrack/conntrackd.conf index 9cdb2c7..25c4e7f 100644 --- a/doc/sync/notrack/conntrackd.conf +++ b/doc/sync/notrack/conntrackd.conf @@ -122,7 +122,8 @@ Sync { # # You can use Unicast UDP instead of Multicast to propagate events. # Note that you cannot use unicast UDP and Multicast at the same - # time, you can only select one. + # time, you can only select one. You can also select TCP in notrack + # mode. # # UDP { # diff --git a/include/Makefile.am b/include/Makefile.am index 844c5b8..a89490e 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -1,6 +1,6 @@ noinst_HEADERS = alarm.h jhash.h cache.h linux_list.h linux_rbtree.h \ - sync.h conntrackd.h local.h udp.h \ + sync.h conntrackd.h local.h udp.h tcp.h \ debug.h log.h hash.h mcast.h conntrack.h \ network.h filter.h queue.h vector.h cidr.h \ traffic_stats.h netlink.h fds.h event.h bitops.h channel.h \ diff --git a/include/channel.h b/include/channel.h index 1d3c48c..98605d9 100644 --- a/include/channel.h +++ b/include/channel.h @@ -3,6 +3,7 @@ #include "mcast.h" #include "udp.h" +#include "tcp.h" struct channel; struct nethdr; @@ -11,6 +12,7 @@ enum { CHANNEL_NONE, CHANNEL_MCAST, CHANNEL_UDP, + CHANNEL_TCP, CHANNEL_MAX, }; @@ -24,13 +26,20 @@ struct udp_channel { struct udp_sock *server; }; +struct tcp_channel { + struct tcp_sock *client; + struct tcp_sock *server; +}; + #define CHANNEL_F_DEFAULT (1 << 0) #define CHANNEL_F_BUFFERED (1 << 1) -#define CHANNEL_F_MAX (1 << 2) +#define CHANNEL_F_STREAM (1 << 2) +#define CHANNEL_F_MAX (1 << 3) union channel_type_conf { struct mcast_conf mcast; struct udp_conf udp; + struct tcp_conf tcp; }; struct channel_conf { @@ -47,7 +56,10 @@ struct channel_ops { void (*close)(void *channel); int (*send)(void *channel, const void *data, int len); int (*recv)(void *channel, char *buf, int len); + int (*accept)(struct channel *c); int (*get_fd)(void *channel); + int (*isset)(struct channel *c, fd_set *readfds); + int (*accept_isset)(struct channel *c, fd_set *readfds); void (*stats)(struct channel *c, int fd); void (*stats_extended)(struct channel *c, int active, struct nlif_handle *h, int fd); @@ -72,8 +84,12 @@ void channel_close(struct channel *c); int channel_send(struct channel *c, const struct nethdr *net); int channel_send_flush(struct channel *c); int channel_recv(struct channel *c, char *buf, int size); +int channel_accept(struct channel *c); int channel_get_fd(struct channel *c); +int channel_accept_isset(struct channel *c, fd_set *readfds); +int channel_isset(struct channel *c, fd_set *readfds); + void channel_stats(struct channel *c, int fd); void channel_stats_extended(struct channel *c, int active, struct nlif_handle *h, int fd); diff --git a/include/mcast.h b/include/mcast.h index 38c77f9..402a033 100644 --- a/include/mcast.h +++ b/include/mcast.h @@ -48,6 +48,7 @@ ssize_t mcast_send(struct mcast_sock *m, const void *data, int size); ssize_t mcast_recv(struct mcast_sock *m, void *data, int size); int mcast_get_fd(struct mcast_sock *m); +int mcast_isset(struct mcast_sock *m, fd_set *readfds); int mcast_snprintf_stats(char *buf, size_t buflen, char *ifname, struct mcast_stats *s, struct mcast_stats *r); diff --git a/include/tcp.h b/include/tcp.h new file mode 100644 index 0000000..1b1d391 --- /dev/null +++ b/include/tcp.h @@ -0,0 +1,75 @@ +#ifndef _TCP_H_ +#define _TCP_H_ + +#include +#include + +struct tcp_conf { + int ipproto; + int reuseaddr; + int checksum; + unsigned short port; + union { + struct { + struct in_addr inet_addr; + } ipv4; + struct { + struct in6_addr inet_addr6; + int scope_id; + } ipv6; + } server; + union { + struct in_addr inet_addr; + struct in6_addr inet_addr6; + } client; + int sndbuf; + int rcvbuf; +}; + +struct tcp_stats { + uint64_t bytes; + uint64_t messages; + uint64_t error; +}; + +enum tcp_sock_state { + TCP_SERVER_ACCEPTING, + TCP_SERVER_CONNECTED, + TCP_CLIENT_DISCONNECTED, + TCP_CLIENT_CONNECTED +}; + +struct tcp_sock { + int state; /* enum tcp_sock_state */ + int fd; + int client_fd; /* only for the server side */ + union { + struct sockaddr_in ipv4; + struct sockaddr_in6 ipv6; + } addr; + socklen_t sockaddr_len; + struct tcp_stats stats; +}; + +struct tcp_sock *tcp_server_create(struct tcp_conf *conf); +void tcp_server_destroy(struct tcp_sock *m); + +struct tcp_sock *tcp_client_create(struct tcp_conf *conf); +void tcp_client_destroy(struct tcp_sock *m); + +ssize_t tcp_send(struct tcp_sock *m, const void *data, int size); +ssize_t tcp_recv(struct tcp_sock *m, void *data, int size); +int tcp_accept(struct tcp_sock *m); + +int tcp_get_fd(struct tcp_sock *m); +int tcp_isset(struct tcp_sock *m, fd_set *readfds); +int tcp_accept_isset(struct tcp_sock *m, fd_set *readfds); + +int tcp_snprintf_stats(char *buf, size_t buflen, char *ifname, + struct tcp_sock *s, struct tcp_sock *r); + +int tcp_snprintf_stats2(char *buf, size_t buflen, const char *ifname, + const char *status, int active, + struct tcp_stats *s, struct tcp_stats *r); + +#endif diff --git a/include/udp.h b/include/udp.h index 6c659b9..9f9c17a 100644 --- a/include/udp.h +++ b/include/udp.h @@ -52,6 +52,7 @@ ssize_t udp_send(struct udp_sock *m, const void *data, int size); ssize_t udp_recv(struct udp_sock *m, void *data, int size); int udp_get_fd(struct udp_sock *m); +int udp_isset(struct udp_sock *m, fd_set *readfds); int udp_snprintf_stats(char *buf, size_t buflen, char *ifname, struct udp_stats *s, struct udp_stats *r); diff --git a/src/Makefile.am b/src/Makefile.am index e969f4d..8b36642 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -20,6 +20,7 @@ conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c rbtree.c \ network.c cidr.c \ build.c parse.c \ channel.c multichannel.c channel_mcast.c channel_udp.c \ + tcp.c channel_tcp.c \ external_cache.c external_inject.c \ read_config_yy.y read_config_lex.l diff --git a/src/channel.c b/src/channel.c index 9d74b7f..76fb057 100644 --- a/src/channel.c +++ b/src/channel.c @@ -20,11 +20,13 @@ static struct channel_ops *ops[CHANNEL_MAX]; extern struct channel_ops channel_mcast; extern struct channel_ops channel_udp; +extern struct channel_ops channel_tcp; void channel_init(void) { ops[CHANNEL_MCAST] = &channel_mcast; ops[CHANNEL_UDP] = &channel_udp; + ops[CHANNEL_TCP] = &channel_tcp; } #define HEADERSIZ 28 /* IP header (20 bytes) + UDP header 8 (bytes) */ @@ -183,3 +185,18 @@ void channel_stats_extended(struct channel *c, int active, { return c->ops->stats_extended(c, active, h, fd); } + +int channel_accept_isset(struct channel *c, fd_set *readfds) +{ + return c->ops->accept_isset(c, readfds); +} + +int channel_isset(struct channel *c, fd_set *readfds) +{ + return c->ops->isset(c, readfds); +} + +int channel_accept(struct channel *c) +{ + return c->ops->accept(c); +} diff --git a/src/channel_mcast.c b/src/channel_mcast.c index 898b194..9fcacac 100644 --- a/src/channel_mcast.c +++ b/src/channel_mcast.c @@ -112,12 +112,27 @@ channel_mcast_stats_extended(struct channel *c, int active, send(fd, buf, size, 0); } +static int +channel_mcast_isset(struct channel *c, fd_set *readfds) +{ + struct mcast_channel *m = c->data; + return mcast_isset(m->server, readfds); +} + +static int +channel_mcast_accept_isset(struct channel *c, fd_set *readfds) +{ + return 0; +} + struct channel_ops channel_mcast = { .open = channel_mcast_open, .close = channel_mcast_close, .send = channel_mcast_send, .recv = channel_mcast_recv, .get_fd = channel_mcast_get_fd, + .isset = channel_mcast_isset, + .accept_isset = channel_mcast_accept_isset, .stats = channel_mcast_stats, .stats_extended = channel_mcast_stats_extended, }; diff --git a/src/channel_tcp.c b/src/channel_tcp.c new file mode 100644 index 0000000..9fb4b07 --- /dev/null +++ b/src/channel_tcp.c @@ -0,0 +1,149 @@ +/* + * (C) 2009 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. + * + * TCP support has been sponsored by 6WIND . + */ + +#include +#include + +#include "channel.h" +#include "tcp.h" + +static void +*channel_tcp_open(void *conf) +{ + struct tcp_channel *m; + struct tcp_conf *c = conf; + + m = calloc(sizeof(struct tcp_channel), 1); + if (m == NULL) + return NULL; + + m->client = tcp_client_create(c); + if (m->client == NULL) { + free(m); + return NULL; + } + + m->server = tcp_server_create(c); + if (m->server == NULL) { + tcp_client_destroy(m->client); + free(m); + return NULL; + } + return m; +} + +static int +channel_tcp_send(void *channel, const void *data, int len) +{ + struct tcp_channel *m = channel; + return tcp_send(m->client, data, len); +} + +static int +channel_tcp_recv(void *channel, char *buf, int size) +{ + struct tcp_channel *m = channel; + return tcp_recv(m->server, buf, size); +} + +static void +channel_tcp_close(void *channel) +{ + struct tcp_channel *m = channel; + tcp_client_destroy(m->client); + tcp_server_destroy(m->server); + free(m); +} + +static int +channel_tcp_get_fd(void *channel) +{ + struct tcp_channel *m = channel; + return tcp_get_fd(m->server); +} + +static void +channel_tcp_stats(struct channel *c, int fd) +{ + struct tcp_channel *m = c->data; + char ifname[IFNAMSIZ], buf[512]; + int size; + + if_indextoname(c->channel_ifindex, ifname); + size = tcp_snprintf_stats(buf, sizeof(buf), ifname, + m->client, m->server); + send(fd, buf, size, 0); +} + +static void +channel_tcp_stats_extended(struct channel *c, int active, + struct nlif_handle *h, int fd) +{ + struct tcp_channel *m = c->data; + char ifname[IFNAMSIZ], buf[512]; + const char *status; + unsigned int flags; + int size; + + if_indextoname(c->channel_ifindex, ifname); + nlif_get_ifflags(h, c->channel_ifindex, &flags); + /* + * IFF_UP shows administrative status + * IFF_RUNNING shows carrier status + */ + if (flags & IFF_UP) { + if (!(flags & IFF_RUNNING)) + status = "NO-CARRIER"; + else + status = "RUNNING"; + } else { + status = "DOWN"; + } + size = tcp_snprintf_stats2(buf, sizeof(buf), + ifname, status, active, + &m->client->stats, + &m->server->stats); + send(fd, buf, size, 0); +} + +static int +channel_tcp_isset(struct channel *c, fd_set *readfds) +{ + struct tcp_channel *m = c->data; + return tcp_isset(m->server, readfds); +} + +static int +channel_tcp_accept_isset(struct channel *c, fd_set *readfds) +{ + struct tcp_channel *m = c->data; + return tcp_accept_isset(m->server, readfds); +} + +static int +channel_tcp_accept(struct channel *c) +{ + struct tcp_channel *m = c->data; + return tcp_accept(m->server); +} + +struct channel_ops channel_tcp = { + .open = channel_tcp_open, + .close = channel_tcp_close, + .send = channel_tcp_send, + .recv = channel_tcp_recv, + .accept = channel_tcp_accept, + .get_fd = channel_tcp_get_fd, + .isset = channel_tcp_isset, + .accept_isset = channel_tcp_accept_isset, + .stats = channel_tcp_stats, + .stats_extended = channel_tcp_stats_extended, +}; diff --git a/src/channel_udp.c b/src/channel_udp.c index 1c15b47..5c88647 100644 --- a/src/channel_udp.c +++ b/src/channel_udp.c @@ -112,12 +112,27 @@ channel_udp_stats_extended(struct channel *c, int active, send(fd, buf, size, 0); } +static int +channel_udp_isset(struct channel *c, fd_set *readfds) +{ + struct udp_channel *m = c->data; + return udp_isset(m->server, readfds); +} + +static int +channel_udp_accept_isset(struct channel *c, fd_set *readfds) +{ + return 0; +} + struct channel_ops channel_udp = { .open = channel_udp_open, .close = channel_udp_close, .send = channel_udp_send, .recv = channel_udp_recv, .get_fd = channel_udp_get_fd, + .isset = channel_udp_isset, + .accept_isset = channel_udp_accept_isset, .stats = channel_udp_stats, .stats_extended = channel_udp_stats_extended, }; diff --git a/src/mcast.c b/src/mcast.c index ec11100..4107d5d 100644 --- a/src/mcast.c +++ b/src/mcast.c @@ -304,6 +304,11 @@ int mcast_get_fd(struct mcast_sock *m) return m->fd; } +int mcast_isset(struct mcast_sock *m, fd_set *readfds) +{ + return FD_ISSET(m->fd, readfds); +} + int mcast_snprintf_stats(char *buf, size_t buflen, char *ifname, struct mcast_stats *s, struct mcast_stats *r) diff --git a/src/read_config_lex.l b/src/read_config_lex.l index d3f83aa..9c53c6c 100644 --- a/src/read_config_lex.l +++ b/src/read_config_lex.l @@ -65,6 +65,7 @@ notrack [N|n][O|o][T|t][R|r][A|a][C|c][K|k] "Interface" { return T_IFACE; } "Multicast" { return T_MULTICAST; } "UDP" { return T_UDP; } +"TCP" { return T_TCP; } "HashSize" { return T_HASHSIZE; } "RefreshTime" { return T_REFRESH; } "CacheTimeout" { return T_EXPIRE; } diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 38c5929..0804689 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -58,7 +58,7 @@ static void __max_dedicated_links_reached(void); %token T_IPV4_ADDR T_IPV4_IFACE T_PORT T_HASHSIZE T_HASHLIMIT T_MULTICAST %token T_PATH T_UNIX T_REFRESH T_IPV6_ADDR T_IPV6_IFACE %token T_IGNORE_UDP T_IGNORE_ICMP T_IGNORE_TRAFFIC T_BACKLOG T_GROUP -%token T_LOG T_UDP T_ICMP T_IGMP T_VRRP T_IGNORE_PROTOCOL +%token T_LOG T_UDP T_ICMP T_IGMP T_VRRP T_TCP T_IGNORE_PROTOCOL %token T_LOCK T_STRIP_NAT T_BUFFER_SIZE_MAX_GROWN T_EXPIRE T_TIMEOUT %token T_GENERAL T_SYNC T_STATS T_RELAX_TRANSITIONS T_BUFFER_SIZE T_DELAY %token T_SYNC_MODE T_LISTEN_TO T_FAMILY T_RESEND_BUFFER_SIZE @@ -573,6 +573,142 @@ udp_option: T_CHECKSUM T_OFF conf.channel[conf.channel_num].u.udp.checksum = 1; }; +tcp_line : T_TCP '{' tcp_options '}' +{ + if (conf.channel_type_global != CHANNEL_NONE && + conf.channel_type_global != CHANNEL_TCP) { + print_err(CTD_CFG_ERROR, "cannot use `TCP' with other " + "dedicated link protocols!"); + exit(EXIT_FAILURE); + } + conf.channel_type_global = CHANNEL_TCP; + conf.channel[conf.channel_num].channel_type = CHANNEL_TCP; + conf.channel[conf.channel_num].channel_flags = CHANNEL_F_BUFFERED | + CHANNEL_F_STREAM; + conf.channel_num++; +}; + +tcp_line : T_TCP T_DEFAULT '{' tcp_options '}' +{ + if (conf.channel_type_global != CHANNEL_NONE && + conf.channel_type_global != CHANNEL_TCP) { + print_err(CTD_CFG_ERROR, "cannot use `TCP' with other " + "dedicated link protocols!"); + exit(EXIT_FAILURE); + } + conf.channel_type_global = CHANNEL_TCP; + conf.channel[conf.channel_num].channel_type = CHANNEL_TCP; + conf.channel[conf.channel_num].channel_flags = CHANNEL_F_DEFAULT | + CHANNEL_F_BUFFERED | + CHANNEL_F_STREAM; + conf.channel_default = conf.channel_num; + conf.channel_num++; +}; + +tcp_options : + | tcp_options tcp_option; + +tcp_option : T_IPV4_ADDR T_IP +{ + __max_dedicated_links_reached(); + + if (!inet_aton($2, &conf.channel[conf.channel_num].u.tcp.server.ipv4)) { + print_err(CTD_CFG_WARN, "%s is not a valid IPv4 address", $2); + break; + } + conf.channel[conf.channel_num].u.tcp.ipproto = AF_INET; +}; + +tcp_option : T_IPV6_ADDR T_IP +{ + __max_dedicated_links_reached(); + +#ifdef HAVE_INET_PTON_IPV6 + if (inet_pton(AF_INET6, $2, + &conf.channel[conf.channel_num].u.tcp.server.ipv6) <= 0) { + print_err(CTD_CFG_WARN, "%s is not a valid IPv6 address", $2); + break; + } +#else + print_err(CTD_CFG_WARN, "cannot find inet_pton(), IPv6 unsupported!"); + break; +#endif + conf.channel[conf.channel_num].u.tcp.ipproto = AF_INET6; +}; + +tcp_option : T_IPV4_DEST_ADDR T_IP +{ + __max_dedicated_links_reached(); + + if (!inet_aton($2, &conf.channel[conf.channel_num].u.tcp.client)) { + print_err(CTD_CFG_WARN, "%s is not a valid IPv4 address", $2); + break; + } + conf.channel[conf.channel_num].u.tcp.ipproto = AF_INET; +}; + +tcp_option : T_IPV6_DEST_ADDR T_IP +{ + __max_dedicated_links_reached(); + +#ifdef HAVE_INET_PTON_IPV6 + if (inet_pton(AF_INET6, $2, + &conf.channel[conf.channel_num].u.tcp.client) <= 0) { + print_err(CTD_CFG_WARN, "%s is not a valid IPv6 address", $2); + break; + } +#else + print_err(CTD_CFG_WARN, "cannot find inet_pton(), IPv6 unsupported!"); + break; +#endif + conf.channel[conf.channel_num].u.tcp.ipproto = AF_INET6; +}; + +tcp_option : T_IFACE T_STRING +{ + int idx; + + __max_dedicated_links_reached(); + strncpy(conf.channel[conf.channel_num].channel_ifname, $2, IFNAMSIZ); + + idx = if_nametoindex($2); + if (!idx) { + print_err(CTD_CFG_WARN, "%s is an invalid interface", $2); + break; + } + conf.channel[conf.channel_num].u.tcp.server.ipv6.scope_id = idx; +}; + +tcp_option : T_PORT T_NUMBER +{ + __max_dedicated_links_reached(); + conf.channel[conf.channel_num].u.tcp.port = $2; +}; + +tcp_option: T_SNDBUFF T_NUMBER +{ + __max_dedicated_links_reached(); + conf.channel[conf.channel_num].u.tcp.sndbuf = $2; +}; + +tcp_option: T_RCVBUFF T_NUMBER +{ + __max_dedicated_links_reached(); + conf.channel[conf.channel_num].u.tcp.rcvbuf = $2; +}; + +tcp_option: T_CHECKSUM T_ON +{ + __max_dedicated_links_reached(); + conf.channel[conf.channel_num].u.tcp.checksum = 0; +}; + +tcp_option: T_CHECKSUM T_OFF +{ + __max_dedicated_links_reached(); + conf.channel[conf.channel_num].u.tcp.checksum = 1; +}; + hashsize : T_HASHSIZE T_NUMBER { conf.hashsize = $2; @@ -654,6 +790,7 @@ sync_line: refreshtime | checksum | multicast_line | udp_line + | tcp_line | relax_transitions | delay_destroy_msgs | sync_mode_alarm @@ -1043,6 +1180,25 @@ filter_protocol_item : T_STRING pent->p_proto); }; +filter_protocol_item : T_TCP +{ + struct protoent *pent; + + pent = getprotobyname("tcp"); + if (pent == NULL) { + print_err(CTD_CFG_WARN, "getprotobyname() cannot find " + "protocol `tcp' in /etc/protocols"); + break; + } + ct_filter_add_proto(STATE(us_filter), pent->p_proto); + + __kernel_filter_start(); + + nfct_filter_add_attr_u32(STATE(filter), + NFCT_FILTER_L4PROTO, + pent->p_proto); +}; + filter_item : T_ADDRESS T_ACCEPT '{' filter_address_list '}' { ct_filter_set_logic(STATE(us_filter), diff --git a/src/sync-mode.c b/src/sync-mode.c index 174df80..6781f10 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -98,39 +98,70 @@ do_channel_handler_step(int i, struct nethdr *net, size_t remain) } } +static char __net[65536]; /* XXX: maximum MTU for IPv4 */ +static char *cur = __net; + +static int channel_stream(struct channel *m, const char *ptr, ssize_t remain) +{ + if (m->channel_flags & CHANNEL_F_STREAM) { + /* truncated data. */ + memcpy(__net, ptr, remain); + cur = __net + remain; + return 1; + } + return 0; +} + /* handler for messages received */ static int channel_handler_routine(struct channel *m, int i) { ssize_t numbytes; - ssize_t remain; - char __net[65536], *ptr = __net; /* XXX: maximum MTU for IPv4 */ + ssize_t remain, pending = cur - __net; + char *ptr = __net; - numbytes = channel_recv(m, __net, sizeof(__net)); + numbytes = channel_recv(m, cur, sizeof(__net) - pending); if (numbytes <= 0) return -1; remain = numbytes; + if (pending) { + remain += pending; + cur = __net; + } + while (remain > 0) { struct nethdr *net = (struct nethdr *) ptr; int len; if (remain < NETHDR_SIZ) { - STATE_SYNC(error).msg_rcv_malformed++; - STATE_SYNC(error).msg_rcv_truncated++; + if (!channel_stream(m, ptr, remain)) { + STATE_SYNC(error).msg_rcv_malformed++; + STATE_SYNC(error).msg_rcv_truncated++; + } break; } len = ntohs(net->len); - if (len > remain || len <= 0) { + if (len <= 0) { STATE_SYNC(error).msg_rcv_malformed++; STATE_SYNC(error).msg_rcv_bad_size++; break; } + if (len > remain) { + if (!channel_stream(m, ptr, remain)) { + STATE_SYNC(error).msg_rcv_malformed++; + STATE_SYNC(error).msg_rcv_bad_size++; + } + break; + } + if (IS_ACK(net) || IS_NACK(net) || IS_RESYNC(net)) { if (remain < NETHDR_ACK_SIZ) { - STATE_SYNC(error).msg_rcv_malformed++; - STATE_SYNC(error).msg_rcv_truncated++; + if (!channel_stream(m, ptr, remain)) { + STATE_SYNC(error).msg_rcv_malformed++; + STATE_SYNC(error).msg_rcv_truncated++; + } break; } @@ -322,15 +353,23 @@ static int init_sync(void) return 0; } +static void channel_check(struct channel *c, int i, fd_set *readfds) +{ + /* In case that this channel is connection-oriented. */ + if (channel_accept_isset(c, readfds)) + channel_accept(c); + + /* For data handling. */ + if (channel_isset(c, readfds)) + channel_handler(c, i); +} + static void run_sync(fd_set *readfds) { int i; - for (i=0; ichannel_num; i++) { - int fd = channel_get_fd(STATE_SYNC(channel)->channel[i]); - if (FD_ISSET(fd, readfds)) - channel_handler(STATE_SYNC(channel)->channel[i], i); - } + for (i=0; ichannel_num; i++) + channel_check(STATE_SYNC(channel)->channel[i], i, readfds); if (FD_ISSET(queue_get_eventfd(STATE_SYNC(tx_queue)), readfds)) STATE_SYNC(sync)->xmit(); diff --git a/src/tcp.c b/src/tcp.c new file mode 100644 index 0000000..f99c1cb --- /dev/null +++ b/src/tcp.c @@ -0,0 +1,440 @@ +/* + * (C) 2009 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. + * + * TCP support has been sponsored by 6WIND . + */ + +#include "tcp.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "conntrackd.h" +#include "fds.h" + +struct tcp_sock *tcp_server_create(struct tcp_conf *c) +{ + int yes = 1, ret; + struct tcp_sock *m; + socklen_t socklen = sizeof(int); + + m = calloc(sizeof(struct tcp_sock), 1); + if (m == NULL) + return NULL; + + switch(c->ipproto) { + case AF_INET: + m->addr.ipv4.sin_family = AF_INET; + m->addr.ipv4.sin_port = htons(c->port); + m->addr.ipv4.sin_addr = c->server.ipv4.inet_addr; + m->sockaddr_len = sizeof(struct sockaddr_in); + break; + + case AF_INET6: + m->addr.ipv6.sin6_family = AF_INET6; + m->addr.ipv6.sin6_port = htons(c->port); + m->addr.ipv6.sin6_addr = c->server.ipv6.inet_addr6; + m->addr.ipv6.sin6_scope_id = c->server.ipv6.scope_id; + m->sockaddr_len = sizeof(struct sockaddr_in6); + break; + } + + m->fd = socket(c->ipproto, SOCK_STREAM, 0); + if (m->fd == -1) { + free(m); + return NULL; + } + + if (setsockopt(m->fd, SOL_SOCKET, SO_REUSEADDR, &yes, + sizeof(int)) == -1) { + close(m->fd); + free(m); + return NULL; + } + + if (setsockopt(m->fd, SOL_SOCKET, SO_KEEPALIVE, &yes, + sizeof(int)) == -1) { + close(m->fd); + free(m); + return NULL; + } + +#ifndef SO_RCVBUFFORCE +#define SO_RCVBUFFORCE 33 +#endif + + if (c->rcvbuf && + setsockopt(m->fd, SOL_SOCKET, SO_RCVBUFFORCE, &c->rcvbuf, + sizeof(int)) == -1) { + /* not supported in linux kernel < 2.6.14 */ + if (errno != ENOPROTOOPT) { + close(m->fd); + free(m); + return NULL; + } + } + + getsockopt(m->fd, SOL_SOCKET, SO_RCVBUF, &c->rcvbuf, &socklen); + + if (bind(m->fd, (struct sockaddr *) &m->addr, m->sockaddr_len) == -1) { + close(m->fd); + free(m); + return NULL; + } + + if (listen(m->fd, 1) == -1) { + close(m->fd); + free(m); + return NULL; + } + + if (fcntl(m->fd, F_SETFL, O_NONBLOCK) == -1) { + close(m->fd); + free(m); + return NULL; + } + + /* now we accept new connections ... */ + ret = accept(m->fd, NULL, NULL); + if (ret == -1) { + if (errno != EAGAIN) { + /* unexpected error, give up. */ + close(m->fd); + free(m); + m = NULL; + } else { + /* still in progress ... we'll do it in tcp_recv() */ + m->state = TCP_SERVER_ACCEPTING; + } + } else { + /* very unlikely at this stage. */ + if (fcntl(ret, F_SETFL, O_NONBLOCK) == -1) { + /* unexpected error, give up. */ + close(m->fd); + free(m); + return NULL; + } + m->client_fd = ret; + m->state = TCP_SERVER_CONNECTED; + register_fd(m->client_fd, STATE(fds)); + } + + return m; +} + +void tcp_server_destroy(struct tcp_sock *m) +{ + close(m->fd); + free(m); +} + +static int +tcp_client_init(struct tcp_sock *m, struct tcp_conf *c) +{ + int ret = 0; + socklen_t socklen = sizeof(int); + + m->fd = socket(c->ipproto, SOCK_STREAM, 0); + if (m->fd == -1) + return -1; + + if (setsockopt(m->fd, SOL_SOCKET, SO_NO_CHECK, &c->checksum, + sizeof(int)) == -1) { + close(m->fd); + return -1; + } + +#ifndef SO_SNDBUFFORCE +#define SO_SNDBUFFORCE 32 +#endif + + if (c->sndbuf && + setsockopt(m->fd, SOL_SOCKET, SO_SNDBUFFORCE, &c->sndbuf, + sizeof(int)) == -1) { + /* not supported in linux kernel < 2.6.14 */ + if (errno != ENOPROTOOPT) { + close(m->fd); + return -1; + } + } + + getsockopt(m->fd, SOL_SOCKET, SO_SNDBUF, &c->sndbuf, &socklen); + + switch(c->ipproto) { + case AF_INET: + m->addr.ipv4.sin_family = AF_INET; + m->addr.ipv4.sin_port = htons(c->port); + m->addr.ipv4.sin_addr = c->client.inet_addr; + m->sockaddr_len = sizeof(struct sockaddr_in); + break; + case AF_INET6: + m->addr.ipv6.sin6_family = AF_INET6; + m->addr.ipv6.sin6_port = htons(c->port); + memcpy(&m->addr.ipv6.sin6_addr, &c->client.inet_addr6, + sizeof(struct in6_addr)); + m->sockaddr_len = sizeof(struct sockaddr_in6); + break; + default: + ret = -1; + break; + } + + if (ret == -1) { + close(m->fd); + return -1; + } + + if (fcntl(m->fd, F_SETFL, O_NONBLOCK) == -1) { + close(m->fd); + return -1; + } + + ret = connect(m->fd, (struct sockaddr *)&m->addr, m->sockaddr_len); + if (ret == -1) { + if (errno == EINPROGRESS) { + /* connection in progress ... */ + m->state = TCP_CLIENT_DISCONNECTED; + } else if (errno == ECONNREFUSED) { + /* connection refused. */ + m->state = TCP_CLIENT_DISCONNECTED; + } else { + /* unexpected error, give up. */ + close(m->fd); + return -1; + } + } else { + /* very unlikely at this stage. */ + m->state = TCP_CLIENT_CONNECTED; + } + return 0; +} + +static struct tcp_conf *tcp_client_conf; /* XXX: need this to re-connect. */ + +struct tcp_sock *tcp_client_create(struct tcp_conf *c) +{ + struct tcp_sock *m; + + tcp_client_conf = c; + + m = calloc(sizeof(struct tcp_sock), 1); + if (m == NULL) + return NULL; + + if (tcp_client_init(m, c) == -1) { + free(m); + return NULL; + } + + return m; +} + +void tcp_client_destroy(struct tcp_sock *m) +{ + close(m->fd); + free(m); +} + +int tcp_accept(struct tcp_sock *m) +{ + int ret; + + /* we got an attempt to connect but we already have a client? */ + if (m->state != TCP_SERVER_ACCEPTING) { + /* clear the session and restart ... */ + unregister_fd(m->client_fd, STATE(fds)); + close(m->client_fd); + m->client_fd = -1; + m->state = TCP_SERVER_ACCEPTING; + } + + /* the other peer wants to connect ... */ + ret = accept(m->fd, NULL, NULL); + if (ret == -1) { + if (errno != EAGAIN) { + /* unexpected error. Give us another try. */ + m->state = TCP_SERVER_ACCEPTING; + } else { + /* waiting for new connections. */ + m->state = TCP_SERVER_ACCEPTING; + } + } else { + /* the peer finally got connected. */ + if (fcntl(ret, F_SETFL, O_NONBLOCK) == -1) { + /* close the connection and give us another chance. */ + close(ret); + return -1; + } + + m->client_fd = ret; + m->state = TCP_SERVER_CONNECTED; + register_fd(m->client_fd, STATE(fds)); + } + return m->client_fd; +} + +ssize_t tcp_send(struct tcp_sock *m, const void *data, int size) +{ + ssize_t ret = 0; + + switch(m->state) { + case TCP_CLIENT_DISCONNECTED: + ret = connect(m->fd, (struct sockaddr *)&m->addr, + m->sockaddr_len); + if (ret == -1) { + if (errno == EINPROGRESS || errno == EALREADY) { + /* connection in progress or already trying. */ + m->state = TCP_CLIENT_DISCONNECTED; + } else if (errno == ECONNREFUSED) { + /* connection refused. */ + m->state = TCP_CLIENT_DISCONNECTED; + } else { + /* unexpected error, give up. */ + m->state = TCP_CLIENT_DISCONNECTED; + } + break; + } else { + /* we got connected :) */ + m->state = TCP_CLIENT_CONNECTED; + } + case TCP_CLIENT_CONNECTED: + ret = sendto(m->fd, data, size, 0, + (struct sockaddr *) &m->addr, m->sockaddr_len); + if (ret == -1) { + if (errno == EPIPE || errno == ECONNRESET) { + close(m->fd); + tcp_client_init(m, tcp_client_conf); + m->state = TCP_CLIENT_DISCONNECTED; + } else { + m->stats.error++; + return 0; + } + } + } + + if (ret >= 0) { + m->stats.bytes += ret; + m->stats.messages++; + } + return ret; +} + +ssize_t tcp_recv(struct tcp_sock *m, void *data, int size) +{ + ssize_t ret = 0; + socklen_t sin_size = sizeof(struct sockaddr_in); + + /* we are not connected, skip. */ + if (m->state != TCP_SERVER_CONNECTED) + return 0; + + ret = recvfrom(m->client_fd, data, size, 0, + (struct sockaddr *)&m->addr, &sin_size); + if (ret == -1) { + /* the other peer has disconnected... */ + if (errno == ENOTCONN) { + unregister_fd(m->client_fd, STATE(fds)); + close(m->client_fd); + m->client_fd = -1; + m->state = TCP_SERVER_ACCEPTING; + tcp_accept(m); + } else if (errno != EAGAIN) { + m->stats.error++; + } + } else if (ret == 0) { + /* the other peer has closed the connection... */ + unregister_fd(m->client_fd, STATE(fds)); + close(m->client_fd); + m->client_fd = -1; + m->state = TCP_SERVER_ACCEPTING; + tcp_accept(m); + } + + if (ret >= 0) { + m->stats.bytes += ret; + m->stats.messages++; + } + return ret; +} + +int tcp_get_fd(struct tcp_sock *m) +{ + return m->fd; +} + +int tcp_isset(struct tcp_sock *m, fd_set *readfds) +{ + return m->client_fd >= 0 ? FD_ISSET(m->client_fd, readfds) : 0; +} + +int tcp_accept_isset(struct tcp_sock *m, fd_set *readfds) +{ + return FD_ISSET(m->fd, readfds); +} + +int +tcp_snprintf_stats(char *buf, size_t buflen, char *ifname, + struct tcp_sock *client, struct tcp_sock *server) +{ + size_t size; + struct tcp_stats *s = &client->stats, *r = &server->stats; + + size = snprintf(buf, buflen, "TCP traffic (active device=%s) " + "server=%s client=%s:\n" + "%20llu Bytes sent " + "%20llu Bytes recv\n" + "%20llu Pckts sent " + "%20llu Pckts recv\n" + "%20llu Error send " + "%20llu Error recv\n\n", + ifname, + server->state == TCP_SERVER_CONNECTED ? + "connected" : "disconnected", + client->state == TCP_CLIENT_CONNECTED ? + "connected" : "disconnected", + (unsigned long long)s->bytes, + (unsigned long long)r->bytes, + (unsigned long long)s->messages, + (unsigned long long)r->messages, + (unsigned long long)s->error, + (unsigned long long)r->error); + return size; +} + +int +tcp_snprintf_stats2(char *buf, size_t buflen, const char *ifname, + const char *status, int active, + struct tcp_stats *s, struct tcp_stats *r) +{ + size_t size; + + size = snprintf(buf, buflen, + "TCP traffic device=%s status=%s role=%s:\n" + "%20llu Bytes sent " + "%20llu Bytes recv\n" + "%20llu Pckts sent " + "%20llu Pckts recv\n" + "%20llu Error send " + "%20llu Error recv\n\n", + ifname, status, active ? "ACTIVE" : "BACKUP", + (unsigned long long)s->bytes, + (unsigned long long)r->bytes, + (unsigned long long)s->messages, + (unsigned long long)r->messages, + (unsigned long long)s->error, + (unsigned long long)r->error); + return size; +} diff --git a/src/udp.c b/src/udp.c index 4b9eb80..ecaa46e 100644 --- a/src/udp.c +++ b/src/udp.c @@ -214,6 +214,11 @@ int udp_get_fd(struct udp_sock *m) return m->fd; } +int udp_isset(struct udp_sock *m, fd_set *readfds) +{ + return FD_ISSET(m->fd, readfds); +} + int udp_snprintf_stats(char *buf, size_t buflen, char *ifname, struct udp_stats *s, struct udp_stats *r) -- cgit v1.2.3 From 55b1c38aca5552f3a2140d2cb5406ec1afe67f20 Mon Sep 17 00:00:00 2001 From: Samuel Gauthier Date: Thu, 3 Sep 2009 15:05:14 +0200 Subject: conntrackd: better parse_payload protection against corrupted packets As we get attr->nta_attr directly from net message, it can be corrupted. Hence, we must check that nta_attr value is valid before trying to reach h[attr->nta_attr] element. Signed-off-by: Samuel Gauthier Signed-off-by: Pablo Neira Ayuso --- src/parse.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/parse.c b/src/parse.c index 1bdfcc7..b5f257c 100644 --- a/src/parse.c +++ b/src/parse.c @@ -208,6 +208,8 @@ int parse_payload(struct nf_conntrack *ct, struct nethdr *net, size_t remain) ATTR_NETWORK2HOST(attr); if (attr->nta_len > len) return -1; + if (attr->nta_attr > NTA_MAX) + return -1; if (attr->nta_len != h[attr->nta_attr].size) return -1; if (h[attr->nta_attr].parse == NULL) { -- cgit v1.2.3 From 189dbc5853ce73448ca0d2423bbac3aa23712478 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 11 Sep 2009 16:19:41 +0200 Subject: conntrackd: fix MTU for TCP channels Use the TCP header size (20 bytes) instead of the UDP header size (8 bytes) to calculate the maximum packet size. Reported-by: Samuel Gauthier Signed-off-by: Pablo Neira Ayuso --- include/channel.h | 1 + src/channel.c | 9 ++++----- src/channel_mcast.c | 1 + src/channel_tcp.c | 1 + src/channel_udp.c | 1 + 5 files changed, 8 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/include/channel.h b/include/channel.h index 98605d9..d06e510 100644 --- a/include/channel.h +++ b/include/channel.h @@ -52,6 +52,7 @@ struct channel_conf { struct nlif_handle; struct channel_ops { + int headersiz; void * (*open)(void *conf); void (*close)(void *channel); int (*send)(void *channel, const void *data, int len); diff --git a/src/channel.c b/src/channel.c index 76fb057..7374d1b 100644 --- a/src/channel.c +++ b/src/channel.c @@ -29,8 +29,6 @@ void channel_init(void) ops[CHANNEL_TCP] = &channel_tcp; } -#define HEADERSIZ 28 /* IP header (20 bytes) + UDP header 8 (bytes) */ - struct channel_buffer { char *data; int size; @@ -38,7 +36,7 @@ struct channel_buffer { }; static struct channel_buffer * -channel_buffer_open(int mtu) +channel_buffer_open(int mtu, int headersiz) { struct channel_buffer *b; @@ -46,7 +44,7 @@ channel_buffer_open(int mtu) if (b == NULL) return NULL; - b->size = mtu - HEADERSIZ; + b->size = mtu - headersiz; b->data = malloc(b->size); if (b->data == NULL) { @@ -108,7 +106,8 @@ channel_open(struct channel_conf *conf) c->ops = ops[conf->channel_type]; if (conf->channel_flags & CHANNEL_F_BUFFERED) { - c->buffer = channel_buffer_open(c->channel_ifmtu); + c->buffer = channel_buffer_open(c->channel_ifmtu, + c->ops->headersiz); if (c->buffer == NULL) { free(c); return NULL; diff --git a/src/channel_mcast.c b/src/channel_mcast.c index 9fcacac..35801d7 100644 --- a/src/channel_mcast.c +++ b/src/channel_mcast.c @@ -126,6 +126,7 @@ channel_mcast_accept_isset(struct channel *c, fd_set *readfds) } struct channel_ops channel_mcast = { + .headersiz = 28, /* IP header (20 bytes) + UDP header 8 (bytes) */ .open = channel_mcast_open, .close = channel_mcast_close, .send = channel_mcast_send, diff --git a/src/channel_tcp.c b/src/channel_tcp.c index 9fb4b07..f132840 100644 --- a/src/channel_tcp.c +++ b/src/channel_tcp.c @@ -136,6 +136,7 @@ channel_tcp_accept(struct channel *c) } struct channel_ops channel_tcp = { + .headersiz = 40, /* IP header (20 bytes) + TCP header 20 (bytes) */ .open = channel_tcp_open, .close = channel_tcp_close, .send = channel_tcp_send, diff --git a/src/channel_udp.c b/src/channel_udp.c index 5c88647..a46a2b1 100644 --- a/src/channel_udp.c +++ b/src/channel_udp.c @@ -126,6 +126,7 @@ channel_udp_accept_isset(struct channel *c, fd_set *readfds) } struct channel_ops channel_udp = { + .headersiz = 28, /* IP header (20 bytes) + UDP header 8 (bytes) */ .open = channel_udp_open, .close = channel_udp_close, .send = channel_udp_send, -- cgit v1.2.3 From 530eed5796faa5fd16c39743a4516bef0e26449c Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 17 Sep 2009 16:10:43 +0200 Subject: conntrackd: fix return value in notrack_local() In 9406f29b89f6727c3db5485d109466701393b4d4, we added different return values for the UNIX sockets that we use to extract the daemon statistics. Unfortunately, I forgot to change this as well. This patch fixes a problem that blocks the client socket indefinitely. Signed-off-by: Pablo Neira Ayuso --- src/sync-notrack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/sync-notrack.c b/src/sync-notrack.c index 6502bcd..14ecde5 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -77,7 +77,7 @@ static int do_cache_to_tx(void *data1, void *data2) static int notrack_local(int fd, int type, void *data) { - int ret = 1; + int ret = LOCAL_RET_OK; switch(type) { case REQUEST_DUMP: -- cgit v1.2.3 From 81d97cfa2654827029492b23fc11bcb86e8e3912 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 21 Sep 2009 11:24:43 +0200 Subject: conntrackd: improve error handling in tcp_send With this patch, we increase the error stats if: * we failed to connect to the other peer. * some unexpected error made connect() fail. * sendto returned ECONNRESET or EPIPE. Moreover, we propagate the sendto() errors to upper layers under failure as Samuel Gauthier suggested. Signed-off-by: Pablo Neira Ayuso --- src/tcp.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/tcp.c b/src/tcp.c index f99c1cb..2b7ca19 100644 --- a/src/tcp.c +++ b/src/tcp.c @@ -301,9 +301,11 @@ ssize_t tcp_send(struct tcp_sock *m, const void *data, int size) } else if (errno == ECONNREFUSED) { /* connection refused. */ m->state = TCP_CLIENT_DISCONNECTED; + m->stats.error++; } else { /* unexpected error, give up. */ m->state = TCP_CLIENT_DISCONNECTED; + m->stats.error++; } break; } else { @@ -318,9 +320,10 @@ ssize_t tcp_send(struct tcp_sock *m, const void *data, int size) close(m->fd); tcp_client_init(m, tcp_client_conf); m->state = TCP_CLIENT_DISCONNECTED; + m->stats.error++; } else { m->stats.error++; - return 0; + return -1; } } } -- cgit v1.2.3 From fc61453d3f30b440e04bb6b3781e1e2348c85cfb Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 21 Sep 2009 13:11:36 +0200 Subject: conntrackd: fix `conf' local variable in channel.c that shadows global This patch avoids the shadowing of the global `conf' variable that is used to store the configuration information. Signed-off-by: Pablo Neira Ayuso --- src/channel.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/channel.c b/src/channel.c index 7374d1b..c442b0b 100644 --- a/src/channel.c +++ b/src/channel.c @@ -65,31 +65,31 @@ channel_buffer_close(struct channel_buffer *b) } struct channel * -channel_open(struct channel_conf *conf) +channel_open(struct channel_conf *cfg) { struct channel *c; struct ifreq ifr; int fd; - if (conf->channel_type >= CHANNEL_MAX) + if (cfg->channel_type >= CHANNEL_MAX) return NULL; - if (!conf->channel_ifname[0]) + if (!cfg->channel_ifname[0]) return NULL; - if (conf->channel_flags >= CHANNEL_F_MAX) + if (cfg->channel_flags >= CHANNEL_F_MAX) return NULL; c = calloc(sizeof(struct channel), 1); if (c == NULL) return NULL; - c->channel_type = conf->channel_type; + c->channel_type = cfg->channel_type; fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd == -1) { free(c); return NULL; } - strncpy(ifr.ifr_name, conf->channel_ifname, sizeof(ifr.ifr_name)); + strncpy(ifr.ifr_name, cfg->channel_ifname, sizeof(ifr.ifr_name)); if (ioctl(fd, SIOCGIFMTU, &ifr) == -1) { free(c); @@ -98,14 +98,14 @@ channel_open(struct channel_conf *conf) close(fd); c->channel_ifmtu = ifr.ifr_mtu; - c->channel_ifindex = if_nametoindex(conf->channel_ifname); + c->channel_ifindex = if_nametoindex(cfg->channel_ifname); if (c->channel_ifindex == 0) { free(c); return NULL; } - c->ops = ops[conf->channel_type]; + c->ops = ops[cfg->channel_type]; - if (conf->channel_flags & CHANNEL_F_BUFFERED) { + if (cfg->channel_flags & CHANNEL_F_BUFFERED) { c->buffer = channel_buffer_open(c->channel_ifmtu, c->ops->headersiz); if (c->buffer == NULL) { @@ -113,9 +113,9 @@ channel_open(struct channel_conf *conf) return NULL; } } - c->channel_flags = conf->channel_flags; + c->channel_flags = cfg->channel_flags; - c->data = c->ops->open(&conf->u); + c->data = c->ops->open(&cfg->u); if (c->data == NULL) { channel_buffer_close(c->buffer); free(c); -- cgit v1.2.3 From da1160ad2c6e05c9e5594e17e5e35cbb461871e4 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 23 Sep 2009 15:18:30 +0200 Subject: conntrackd: fix re-connect with multiple TCP channels This patch fixes a bug in the TCP support that breaks re-connections of the client side if several TCP channels are used in the configuration file. Signed-off-by: Pablo Neira Ayuso --- include/tcp.h | 1 + src/tcp.c | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/include/tcp.h b/include/tcp.h index 1b1d391..2f0fd0a 100644 --- a/include/tcp.h +++ b/include/tcp.h @@ -49,6 +49,7 @@ struct tcp_sock { } addr; socklen_t sockaddr_len; struct tcp_stats stats; + struct tcp_conf *conf; }; struct tcp_sock *tcp_server_create(struct tcp_conf *conf); diff --git a/src/tcp.c b/src/tcp.c index 2b7ca19..ce2cd6f 100644 --- a/src/tcp.c +++ b/src/tcp.c @@ -35,6 +35,8 @@ struct tcp_sock *tcp_server_create(struct tcp_conf *c) if (m == NULL) return NULL; + m->conf = c; + switch(c->ipproto) { case AF_INET: m->addr.ipv4.sin_family = AF_INET; @@ -222,18 +224,16 @@ tcp_client_init(struct tcp_sock *m, struct tcp_conf *c) return 0; } -static struct tcp_conf *tcp_client_conf; /* XXX: need this to re-connect. */ - struct tcp_sock *tcp_client_create(struct tcp_conf *c) { struct tcp_sock *m; - tcp_client_conf = c; - m = calloc(sizeof(struct tcp_sock), 1); if (m == NULL) return NULL; + m->conf = c; + if (tcp_client_init(m, c) == -1) { free(m); return NULL; @@ -318,7 +318,7 @@ ssize_t tcp_send(struct tcp_sock *m, const void *data, int size) if (ret == -1) { if (errno == EPIPE || errno == ECONNRESET) { close(m->fd); - tcp_client_init(m, tcp_client_conf); + tcp_client_init(m, m->conf); m->state = TCP_CLIENT_DISCONNECTED; m->stats.error++; } else { -- cgit v1.2.3 From 90bbd8b34565ff5106dde34e0798c5e33fb4b786 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 23 Sep 2009 17:58:19 +0200 Subject: conntrackd: rate-limit the amount of connect() calls This patch rate-limits the amount of connect() calls to avoid syn-floods when the other peer is not connected and we are generating updates. Signed-off-by: Pablo Neira Ayuso --- src/tcp.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'src') diff --git a/src/tcp.c b/src/tcp.c index ce2cd6f..c551c54 100644 --- a/src/tcp.c +++ b/src/tcp.c @@ -224,6 +224,10 @@ tcp_client_init(struct tcp_sock *m, struct tcp_conf *c) return 0; } +/* We use this to rate-limit the amount of connect() calls per second. */ +static struct alarm_block tcp_connect_alarm; +static void tcp_connect_alarm_cb(struct alarm_block *a, void *data) {} + struct tcp_sock *tcp_client_create(struct tcp_conf *c) { struct tcp_sock *m; @@ -239,6 +243,8 @@ struct tcp_sock *tcp_client_create(struct tcp_conf *c) return NULL; } + init_alarm(&tcp_connect_alarm, NULL, tcp_connect_alarm_cb); + return m; } @@ -286,12 +292,20 @@ int tcp_accept(struct tcp_sock *m) return m->client_fd; } +#define TCP_CONNECT_TIMEOUT 1 + ssize_t tcp_send(struct tcp_sock *m, const void *data, int size) { ssize_t ret = 0; switch(m->state) { case TCP_CLIENT_DISCONNECTED: + /* We rate-limit the amount of connect() calls. */ + if (alarm_pending(&tcp_connect_alarm)) { + ret = -1; + break; + } + add_alarm(&tcp_connect_alarm, TCP_CONNECT_TIMEOUT, 0); ret = connect(m->fd, (struct sockaddr *)&m->addr, m->sockaddr_len); if (ret == -1) { -- cgit v1.2.3 From 6360f319362fd13c86c3387a4bac57665d5ecd73 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 23 Sep 2009 18:12:37 +0200 Subject: conntrackd: add retention queue for TCP errors Under stress, the TCP stack may return EAGAIN if there is not space left in the sender buffer. We also enqueue any other error. Signed-off-by: Pablo Neira Ayuso --- include/channel.h | 6 ++- include/conntrackd.h | 3 ++ include/queue.h | 3 +- src/channel.c | 119 ++++++++++++++++++++++++++++++++++++++++++++++++-- src/read_config_lex.l | 1 + src/read_config_yy.y | 18 ++++++-- src/sync-mode.c | 5 ++- 7 files changed, 144 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/include/channel.h b/include/channel.h index d06e510..9b5fad8 100644 --- a/include/channel.h +++ b/include/channel.h @@ -34,7 +34,8 @@ struct tcp_channel { #define CHANNEL_F_DEFAULT (1 << 0) #define CHANNEL_F_BUFFERED (1 << 1) #define CHANNEL_F_STREAM (1 << 2) -#define CHANNEL_F_MAX (1 << 3) +#define CHANNEL_F_ERRORS (1 << 3) +#define CHANNEL_F_MAX (1 << 4) union channel_type_conf { struct mcast_conf mcast; @@ -78,7 +79,8 @@ struct channel { void *data; }; -void channel_init(void); +int channel_init(void); +void channel_end(void); struct channel *channel_open(struct channel_conf *conf); void channel_close(struct channel *c); diff --git a/include/conntrackd.h b/include/conntrackd.h index ce8f9d4..7737532 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -95,6 +95,9 @@ struct ct_conf { int poll_kernel_secs; int filter_from_kernelspace; int event_iterations_limit; + struct { + int error_queue_length; + } channelc; struct { int external_cache_disable; } sync; diff --git a/include/queue.h b/include/queue.h index cca9cba..188e106 100644 --- a/include/queue.h +++ b/include/queue.h @@ -13,7 +13,8 @@ struct queue_node { enum { Q_ELEM_OBJ = 0, - Q_ELEM_CTL = 1 + Q_ELEM_CTL = 1, + Q_ELEM_ERR = 2, }; void queue_node_init(struct queue_node *n, int type); diff --git a/src/channel.c b/src/channel.c index c442b0b..818bb01 100644 --- a/src/channel.c +++ b/src/channel.c @@ -13,20 +13,36 @@ #include #include #include +#include +#include "conntrackd.h" #include "channel.h" #include "network.h" +#include "queue.h" static struct channel_ops *ops[CHANNEL_MAX]; extern struct channel_ops channel_mcast; extern struct channel_ops channel_udp; extern struct channel_ops channel_tcp; -void channel_init(void) +static struct queue *errorq; + +int channel_init(void) { ops[CHANNEL_MCAST] = &channel_mcast; ops[CHANNEL_UDP] = &channel_udp; ops[CHANNEL_TCP] = &channel_tcp; + + errorq = queue_create("errorq", CONFIG(channelc).error_queue_length, 0); + if (errorq == NULL) { + return -1; + } + return 0; +} + +void channel_end(void) +{ + queue_destroy(errorq); } struct channel_buffer { @@ -133,9 +149,79 @@ channel_close(struct channel *c) free(c); } +struct channel_error { + char *data; + int len; +}; + +static void channel_enqueue_errors(struct channel *c) +{ + struct queue_object *qobj; + struct channel_error *error; + + qobj = queue_object_new(Q_ELEM_ERR, sizeof(struct channel_error)); + if (qobj == NULL) + return; + + error = (struct channel_error *)qobj->data; + error->len = c->buffer->len; + + error->data = malloc(c->buffer->len); + if (error->data == NULL) { + queue_object_free(qobj); + return; + } + memcpy(error->data, c->buffer->data, c->buffer->len); + if (queue_add(errorq, &qobj->qnode) < 0) { + if (errno == ENOSPC) { + struct queue_node *tail; + struct channel_error *tmp; + + tail = queue_del_head(errorq); + tmp = queue_node_data(tail); + free(tmp->data); + queue_object_free((struct queue_object *)tail); + + queue_add(errorq, &qobj->qnode); + } + } +} + +static int channel_handle_error_step(struct queue_node *n, const void *data2) +{ + struct channel_error *error; + const struct channel *c = data2; + int ret; + + error = queue_node_data(n); + ret = c->ops->send(c->data, error->data, error->len); + if (ret != -1) { + /* Success. Delete it from the error queue. */ + queue_del(n); + free(error->data); + queue_object_free((struct queue_object *)n); + } else { + /* We failed to deliver, give up now, try later. */ + return 1; + } + return 0; +} + +static int channel_handle_errors(struct channel *c) +{ + /* there are pending errors that we have to handle. */ + if (c->channel_flags & CHANNEL_F_ERRORS && queue_len(errorq) > 0) { + queue_iterate(errorq, c, channel_handle_error_step); + return queue_len(errorq) > 0; + } + return 0; +} + int channel_send(struct channel *c, const struct nethdr *net) { - int ret = 0, len = ntohs(net->len); + int ret = 0, len = ntohs(net->len), pending_errors; + + pending_errors = channel_handle_errors(c); if (!(c->channel_flags & CHANNEL_F_BUFFERED)) { c->ops->send(c->data, net, len); @@ -146,7 +232,19 @@ retry: memcpy(c->buffer->data + c->buffer->len, net, len); c->buffer->len += len; } else { - c->ops->send(c->data, c->buffer->data, c->buffer->len); + /* We've got pending packets to deliver, enqueue this + * packet to avoid possible re-ordering. */ + if (pending_errors) { + channel_enqueue_errors(c); + } else { + ret = c->ops->send(c->data, c->buffer->data, + c->buffer->len); + if (ret == -1 && + (c->channel_flags & CHANNEL_F_ERRORS)) { + /* Give it another chance to deliver. */ + channel_enqueue_errors(c); + } + } ret = 1; c->buffer->len = 0; goto retry; @@ -156,10 +254,23 @@ retry: int channel_send_flush(struct channel *c) { + int ret, pending_errors; + + pending_errors = channel_handle_errors(c); + if (!(c->channel_flags & CHANNEL_F_BUFFERED) || c->buffer->len == 0) return 0; - c->ops->send(c->data, c->buffer->data, c->buffer->len); + /* We still have pending errors to deliver, avoid any re-ordering. */ + if (pending_errors) { + channel_enqueue_errors(c); + } else { + ret = c->ops->send(c->data, c->buffer->data, c->buffer->len); + if (ret == -1 && (c->channel_flags & CHANNEL_F_ERRORS)) { + /* Give it another chance to deliver it. */ + channel_enqueue_errors(c); + } + } c->buffer->len = 0; return 1; } diff --git a/src/read_config_lex.l b/src/read_config_lex.l index 9c53c6c..b4be6f0 100644 --- a/src/read_config_lex.l +++ b/src/read_config_lex.l @@ -137,6 +137,7 @@ notrack [N|n][O|o][T|t][R|r][A|a][C|c][K|k] "Priority" { return T_PRIO; } "NetlinkEventsReliable" { return T_NETLINK_EVENTS_RELIABLE; } "DisableExternalCache" { return T_DISABLE_EXTERNAL_CACHE; } +"ErrorQueueLength" { return T_ERROR_QUEUE_LENGTH; } {is_on} { return T_ON; } {is_off} { return T_OFF; } diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 0804689..5075cf0 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -72,7 +72,7 @@ static void __max_dedicated_links_reached(void); %token T_FROM T_USERSPACE T_KERNELSPACE T_EVENT_ITER_LIMIT T_DEFAULT %token T_NETLINK_OVERRUN_RESYNC T_NICE T_IPV4_DEST_ADDR T_IPV6_DEST_ADDR %token T_SCHEDULER T_TYPE T_PRIO T_NETLINK_EVENTS_RELIABLE -%token T_DISABLE_EXTERNAL_CACHE +%token T_DISABLE_EXTERNAL_CACHE T_ERROR_QUEUE_LENGTH %token T_IP T_PATH_VAL %token T_NUMBER @@ -584,7 +584,8 @@ tcp_line : T_TCP '{' tcp_options '}' conf.channel_type_global = CHANNEL_TCP; conf.channel[conf.channel_num].channel_type = CHANNEL_TCP; conf.channel[conf.channel_num].channel_flags = CHANNEL_F_BUFFERED | - CHANNEL_F_STREAM; + CHANNEL_F_STREAM | + CHANNEL_F_ERRORS; conf.channel_num++; }; @@ -600,7 +601,8 @@ tcp_line : T_TCP T_DEFAULT '{' tcp_options '}' conf.channel[conf.channel_num].channel_type = CHANNEL_TCP; conf.channel[conf.channel_num].channel_flags = CHANNEL_F_DEFAULT | CHANNEL_F_BUFFERED | - CHANNEL_F_STREAM; + CHANNEL_F_STREAM | + CHANNEL_F_ERRORS; conf.channel_default = conf.channel_num; conf.channel_num++; }; @@ -709,6 +711,12 @@ tcp_option: T_CHECKSUM T_OFF conf.channel[conf.channel_num].u.tcp.checksum = 1; }; +tcp_option: T_ERROR_QUEUE_LENGTH T_NUMBER +{ + __max_dedicated_links_reached(); + CONFIG(channelc).error_queue_length = $2; +}; + hashsize : T_HASHSIZE T_NUMBER { conf.hashsize = $2; @@ -1583,5 +1591,9 @@ init_config(char *filename) if (CONFIG(nl_overrun_resync) == 0) CONFIG(nl_overrun_resync) = 30; + /* default to 128 elements in the channel error queue */ + if (CONFIG(channelc).error_queue_length == 0) + CONFIG(channelc).error_queue_length = 128; + return 0; } diff --git a/src/sync-mode.c b/src/sync-mode.c index 6781f10..63fae68 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -295,7 +295,8 @@ static int init_sync(void) if (STATE_SYNC(external)->init() == -1) return -1; - channel_init(); + if (channel_init() == -1) + return -1; /* channel to send events on the wire */ STATE_SYNC(channel) = @@ -397,6 +398,8 @@ static void kill_sync(void) queue_destroy(STATE_SYNC(tx_queue)); + channel_end(); + origin_unregister(STATE_SYNC(commit).h); nfct_close(STATE_SYNC(commit).h); destroy_evfd(STATE_SYNC(commit).evfd); -- cgit v1.2.3 From 84ebcb1c96cd84d6d09f0b3fe534b9a0c5a120d8 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 23 Sep 2009 18:14:09 +0200 Subject: conntrackd: add alive control messages to notrack mode This patch adds the alive control message to the notrack mode. This helps to diagnose problems in the synchronization and the state of the channel, specifically for TCP-based channels. Signed-off-by: Pablo Neira Ayuso --- src/sync-notrack.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'src') diff --git a/src/sync-notrack.c b/src/sync-notrack.c index 14ecde5..d9f273e 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -26,6 +26,11 @@ #include +static struct alarm_block alive_alarm; + +/* XXX: alive message expiration configurable */ +#define ALIVE_INT 1 + struct cache_notrack { struct queue_node qnode; }; @@ -106,6 +111,9 @@ static int digest_msg(const struct nethdr *net) return MSG_CTL; } + if (IS_ALIVE(net)) + return MSG_CTL; + return MSG_BAD; } @@ -162,6 +170,7 @@ static int tx_queue_xmit(struct queue_node *n, const void *data2) static void notrack_xmit(void) { queue_iterate(STATE_SYNC(tx_queue), NULL, tx_queue_xmit); + add_alarm(&alive_alarm, ALIVE_INT, 0); } static void notrack_enqueue(struct cache_object *obj, int query) @@ -171,10 +180,40 @@ static void notrack_enqueue(struct cache_object *obj, int query) cache_object_get(obj); } +static void tx_queue_add_ctlmsg2(uint32_t flags) +{ + struct queue_object *qobj; + struct nethdr *ctl; + + qobj = queue_object_new(Q_ELEM_CTL, sizeof(struct nethdr_ack)); + if (qobj == NULL) + return; + + ctl = (struct nethdr *)qobj->data; + ctl->type = NET_T_CTL; + ctl->flags = flags; + + queue_add(STATE_SYNC(tx_queue), &qobj->qnode); +} + +static void do_alive_alarm(struct alarm_block *a, void *data) +{ + tx_queue_add_ctlmsg2(NET_F_ALIVE); + add_alarm(&alive_alarm, ALIVE_INT, 0); +} + +static int notrack_init(void) +{ + init_alarm(&alive_alarm, NULL, do_alive_alarm); + add_alarm(&alive_alarm, ALIVE_INT, 0); + return 0; +} + struct sync_mode sync_notrack = { .internal_cache_flags = NO_FEATURES, .external_cache_flags = NO_FEATURES, .internal_cache_extra = &cache_notrack_extra, + .init = notrack_init, .local = notrack_local, .recv = notrack_recv, .enqueue = notrack_enqueue, -- cgit v1.2.3 From bde8891c60cd31590b38459081886bb5d1910f97 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 26 Sep 2009 00:19:45 +0200 Subject: conntrackd: fix wrong calculation of new maxfd on unregister_fds() This patch fixes a missing calculation of maxfd when a file descriptor is unregistered. Reported-by: Jean Mickael Guerin Signed-off-by: Pablo Neira Ayuso --- src/fds.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/fds.c b/src/fds.c index 6304fcd..347eee1 100644 --- a/src/fds.c +++ b/src/fds.c @@ -87,6 +87,8 @@ int unregister_fd(int fd, struct fds *fds) maxfd = this->fd; } } + fds->maxfd = maxfd; + return 0; } -- cgit v1.2.3 From 0cd2397e80d21d77ddb97794f24bb6945849093d Mon Sep 17 00:00:00 2001 From: Hannes Eder Date: Wed, 7 Oct 2009 15:08:35 +0200 Subject: conntrack: fix output when no arguments are passed When 'conntrack' is called with no arguments then garbage is printed after the usage message. This patch fixes this. Signed-off-by: Hannes Eder Signed-off-by: Pablo Neira Ayuso --- src/conntrack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index 42b5133..0053a28 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -1493,7 +1493,7 @@ int main(int argc, char *argv[]) free_options(); - if (exit_msg[cmd][0]) { + if (command && exit_msg[cmd][0]) { fprintf(stderr, "%s v%s (conntrack-tools): ",PROGNAME,VERSION); fprintf(stderr, exit_msg[cmd], counter); if (counter == 0 && !(command & (CT_LIST | EXP_LIST))) -- cgit v1.2.3 From eb1127e0f72274bdcdcf6fdef96f1cbac5d19f02 Mon Sep 17 00:00:00 2001 From: Hannes Eder Date: Thu, 8 Oct 2009 18:04:11 +0200 Subject: conntrack: avoid error with expectations when using 'conntrack -E -e ALL ...' Avoid this error: conntrack v0.9.13 (conntrack-tools): Operation failed: No such file or directory when using 'conntrack -E -e ALL ...'. This is caused by the fact that netfilter expectations also get delivered, but things are not setup for this, nfnl_catch returns -1 and errno = ENOENT. Signed-off-by: Hannes Eder Signed-off-by: Pablo Neira Ayuso --- src/conntrack.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index 0053a28..8e546ab 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -1401,7 +1401,8 @@ int main(int argc, char *argv[]) case CT_EVENT: if (options & CT_OPT_EVENT_MASK) - cth = nfct_open(CONNTRACK, event_mask); + cth = nfct_open(CONNTRACK, + event_mask & NFCT_ALL_CT_GROUPS); else cth = nfct_open(CONNTRACK, NFCT_ALL_CT_GROUPS); -- cgit v1.2.3 From 910d392806be7457f95aaab73e81abe20772bd05 Mon Sep 17 00:00:00 2001 From: Hannes Eder Date: Thu, 8 Oct 2009 18:06:04 +0200 Subject: conntrack: use fscanf() instead of read() for showing counter Read an integer right away with fscanf() instead of read()-ing to a buffer, which was actually to small for the terminating '\0', and atoi()-ing. Furthermore read() might not read enough, though unlikely here. Signed-off-by: Hannes Eder Signed-off-by: Pablo Neira Ayuso --- src/conntrack.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index 8e546ab..eec3868 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -1445,19 +1445,18 @@ int main(int argc, char *argv[]) break; case CT_COUNT: { #define NF_CONNTRACK_COUNT_PROC "/proc/sys/net/netfilter/nf_conntrack_count" - int fd, count; - char buf[strlen("2147483647")]; /* INT_MAX */ - fd = open(NF_CONNTRACK_COUNT_PROC, O_RDONLY); - if (fd == -1) { + FILE *fd; + int count; + fd = fopen(NF_CONNTRACK_COUNT_PROC, "r"); + if (fd == NULL) { exit_error(OTHER_PROBLEM, "Can't open %s", NF_CONNTRACK_COUNT_PROC); } - if (read(fd, buf, sizeof(buf)) == -1) { + if (fscanf(fd, "%d", &count) != 1) { exit_error(OTHER_PROBLEM, "Can't read %s", NF_CONNTRACK_COUNT_PROC); } - close(fd); - count = atoi(buf); + fclose(fd); printf("%d\n", count); break; } -- cgit v1.2.3 From 0b03f4b759e439edd2c3da0add08050276d7dc5f Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 14 Oct 2009 15:58:18 +0200 Subject: conntrackd: add statistics when the external cache is disabled # conntrackd -s external inject: connections created: 0 failed: 0 connections updated: 0 failed: 0 connections destroyed: 0 failed: 0 Signed-off-by: Pablo Neira Ayuso --- src/external_inject.c | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/external_inject.c b/src/external_inject.c index ec1cb16..8e5bbea 100644 --- a/src/external_inject.c +++ b/src/external_inject.c @@ -29,6 +29,15 @@ static struct nfct_handle *inject; +struct { + uint32_t add_ok; + uint32_t add_fail; + uint32_t upd_ok; + uint32_t upd_fail; + uint32_t del_ok; + uint32_t del_fail; +} external_inject_stat; + static int external_inject_init(void) { /* handler to directly inject conntracks into kernel-space */ @@ -65,10 +74,12 @@ retry: goto retry; } } + external_inject_stat.add_fail++; dlog(LOG_ERR, "inject-add1: %s", strerror(errno)); dlog_ct(STATE(log), ct, NFCT_O_PLAIN); return; } + external_inject_stat.add_fail++; dlog(LOG_ERR, "inject-add2: %s", strerror(errno)); dlog_ct(STATE(log), ct, NFCT_O_PLAIN); } @@ -85,6 +96,7 @@ static void external_inject_upd(struct nf_conntrack *ct) /* state entries does not exist, we have to create it */ if (errno == ENOENT) { if (nl_create_conntrack(inject, ct, 0) == -1) { + external_inject_stat.upd_fail++; dlog(LOG_ERR, "inject-upd1: %s", strerror(errno)); dlog_ct(STATE(log), ct, NFCT_O_PLAIN); } @@ -97,11 +109,13 @@ static void external_inject_upd(struct nf_conntrack *ct) ret = nl_destroy_conntrack(inject, ct); if (ret == 0 || (ret == -1 && errno == ENOENT)) { if (nl_create_conntrack(inject, ct, 0) == -1) { + external_inject_stat.upd_fail++; dlog(LOG_ERR, "inject-upd2: %s", strerror(errno)); dlog_ct(STATE(log), ct, NFCT_O_PLAIN); } return; } + external_inject_stat.upd_fail++; dlog(LOG_ERR, "inject-upd3: %s", strerror(errno)); dlog_ct(STATE(log), ct, NFCT_O_PLAIN); } @@ -110,6 +124,7 @@ static void external_inject_del(struct nf_conntrack *ct) { if (nl_destroy_conntrack(inject, ct) == -1) { if (errno != ENOENT) { + external_inject_stat.del_fail++; dlog(LOG_ERR, "inject-del: %s", strerror(errno)); dlog_ct(STATE(log), ct, NFCT_O_PLAIN); } @@ -130,10 +145,21 @@ static void external_inject_flush(void) static void external_inject_stats(int fd) { -} - -static void external_inject_stats_ext(int fd) -{ + char buf[512]; + int size; + + size = sprintf(buf, "external inject:\n" + "connections created:\t\t%12u\tfailed:\t%12u\n" + "connections updated:\t\t%12u\tfailed:\t%12u\n" + "connections destroyed:\t\t%12u\tfailed:\t%12u\n\n", + external_inject_stat.add_ok, + external_inject_stat.add_fail, + external_inject_stat.upd_ok, + external_inject_stat.upd_fail, + external_inject_stat.del_ok, + external_inject_stat.del_fail); + + send(fd, buf, size, 0); } struct external_handler external_inject = { @@ -146,5 +172,5 @@ struct external_handler external_inject = { .commit = external_inject_commit, .flush = external_inject_flush, .stats = external_inject_stats, - .stats_ext = external_inject_stats_ext, + .stats_ext = external_inject_stats, }; -- cgit v1.2.3 From 6e7166b7d396884eedbaf250f8a06864f63c07fc Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 14 Oct 2009 16:14:12 +0200 Subject: conntrackd: add missing external statistics In 0b03f4b759e439edd2c3da0add08050276d7dc5f, I forgot to increase the stats for successful cases. This patch fixes this. Signed-off-by: Pablo Neira Ayuso --- src/external_inject.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/external_inject.c b/src/external_inject.c index 8e5bbea..a54bb13 100644 --- a/src/external_inject.c +++ b/src/external_inject.c @@ -82,6 +82,8 @@ retry: external_inject_stat.add_fail++; dlog(LOG_ERR, "inject-add2: %s", strerror(errno)); dlog_ct(STATE(log), ct, NFCT_O_PLAIN); + } else { + external_inject_stat.add_ok++; } } @@ -90,8 +92,10 @@ static void external_inject_upd(struct nf_conntrack *ct) int ret; /* if we successfully update the entry, everything is OK */ - if (nl_update_conntrack(inject, ct, 0) != -1) + if (nl_update_conntrack(inject, ct, 0) != -1) { + external_inject_stat.upd_ok++; return; + } /* state entries does not exist, we have to create it */ if (errno == ENOENT) { @@ -99,6 +103,8 @@ static void external_inject_upd(struct nf_conntrack *ct) external_inject_stat.upd_fail++; dlog(LOG_ERR, "inject-upd1: %s", strerror(errno)); dlog_ct(STATE(log), ct, NFCT_O_PLAIN); + } else { + external_inject_stat.upd_ok++; } return; } @@ -112,6 +118,8 @@ static void external_inject_upd(struct nf_conntrack *ct) external_inject_stat.upd_fail++; dlog(LOG_ERR, "inject-upd2: %s", strerror(errno)); dlog_ct(STATE(log), ct, NFCT_O_PLAIN); + } else { + external_inject_stat.upd_ok++; } return; } @@ -128,6 +136,8 @@ static void external_inject_del(struct nf_conntrack *ct) dlog(LOG_ERR, "inject-del: %s", strerror(errno)); dlog_ct(STATE(log), ct, NFCT_O_PLAIN); } + } else { + external_inject_stat.del_ok++; } } -- cgit v1.2.3 From 8ad5df6121c46753a6d12fafa5ab9da309ddb721 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 21 Oct 2009 01:43:07 +0200 Subject: conntrackd: add `DisableInternalCache' clause This patch adds the clause `DisableInternalCache' that allows you to bypass the internal cache. This clause can only be used with the notrack synchronization mode. Signed-off-by: Pablo Neira Ayuso --- include/Makefile.am | 2 +- include/conntrackd.h | 12 +-- include/internal.h | 39 +++++++++ src/Makefile.am | 1 + src/internal_bypass.c | 165 +++++++++++++++++++++++++++++++++++++ src/internal_cache.c | 220 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/read_config_lex.l | 1 + src/read_config_yy.y | 13 ++- src/run.c | 62 ++++++++------ src/stats-mode.c | 24 +++--- src/sync-alarm.c | 5 +- src/sync-ftfw.c | 19 +++-- src/sync-mode.c | 190 ++++--------------------------------------- src/sync-notrack.c | 53 ++++++++++-- 14 files changed, 572 insertions(+), 234 deletions(-) create mode 100644 include/internal.h create mode 100644 src/internal_bypass.c create mode 100644 src/internal_cache.c (limited to 'src') diff --git a/include/Makefile.am b/include/Makefile.am index a89490e..cbbca6b 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -4,5 +4,5 @@ noinst_HEADERS = alarm.h jhash.h cache.h linux_list.h linux_rbtree.h \ debug.h log.h hash.h mcast.h conntrack.h \ network.h filter.h queue.h vector.h cidr.h \ traffic_stats.h netlink.h fds.h event.h bitops.h channel.h \ - process.h origin.h external.h date.h + process.h origin.h internal.h external.h date.h diff --git a/include/conntrackd.h b/include/conntrackd.h index 7737532..c7f33f0 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -6,6 +6,7 @@ #include "alarm.h" #include "filter.h" #include "channel.h" +#include "internal.h" #include #include @@ -99,6 +100,7 @@ struct ct_conf { int error_queue_length; } channelc; struct { + int internal_cache_disable; int external_cache_disable; } sync; struct { @@ -177,7 +179,6 @@ struct ct_general_state { #define STATE_SYNC(x) state.sync->x struct ct_sync_state { - struct cache *internal; /* internal events cache (netlink) */ struct external_handler *external; struct multichannel *channel; @@ -239,18 +240,11 @@ extern union ct_state state; extern struct ct_general_state st; struct ct_mode { + struct internal_handler *internal; int (*init)(void); void (*run)(fd_set *readfds); int (*local)(int fd, int type, void *data); void (*kill)(void); - void (*dump)(struct nf_conntrack *ct); - int (*resync)(enum nf_conntrack_msg_type type, - struct nf_conntrack *ct, - void *data); - int (*purge)(void); - void (*event_new)(struct nf_conntrack *ct, int origin); - void (*event_upd)(struct nf_conntrack *ct, int origin); - int (*event_dst)(struct nf_conntrack *ct, int origin); }; /* conntrackd modes */ diff --git a/include/internal.h b/include/internal.h new file mode 100644 index 0000000..1f11340 --- /dev/null +++ b/include/internal.h @@ -0,0 +1,39 @@ +#ifndef _INTERNAL_H_ +#define _INTERNAL_H_ + +#include + +struct nf_conntrack; + +enum { + INTERNAL_F_POPULATE = (1 << 0), + INTERNAL_F_RESYNC = (1 << 1), + INTERNAL_F_MAX = (1 << 2) +}; + +struct internal_handler { + void *data; + unsigned int flags; + + int (*init)(void); + void (*close)(void); + + void (*new)(struct nf_conntrack *ct, int origin_type); + void (*update)(struct nf_conntrack *ct, int origin_type); + int (*destroy)(struct nf_conntrack *ct, int origin_type); + + void (*dump)(int fd, int type); + void (*populate)(struct nf_conntrack *ct); + void (*purge)(void); + int (*resync)(enum nf_conntrack_msg_type type, + struct nf_conntrack *ct, void *data); + void (*flush)(void); + + void (*stats)(int fd); + void (*stats_ext)(int fd); +}; + +extern struct internal_handler internal_cache; +extern struct internal_handler internal_bypass; + +#endif diff --git a/src/Makefile.am b/src/Makefile.am index 8b36642..76f0e73 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -22,6 +22,7 @@ conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c rbtree.c \ channel.c multichannel.c channel_mcast.c channel_udp.c \ tcp.c channel_tcp.c \ external_cache.c external_inject.c \ + internal_cache.c internal_bypass.c \ read_config_yy.y read_config_lex.l # yacc and lex generate dirty code diff --git a/src/internal_bypass.c b/src/internal_bypass.c new file mode 100644 index 0000000..4caaf4f --- /dev/null +++ b/src/internal_bypass.c @@ -0,0 +1,165 @@ +/* + * (C) 2009 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. + * + * This feature has been sponsored by 6WIND . + */ +#include "conntrackd.h" +#include "sync.h" +#include "log.h" +#include "cache.h" +#include "netlink.h" +#include "network.h" +#include "origin.h" + +static int _init(void) +{ + return 0; +} + +static void _close(void) +{ +} + +static int dump_cb(enum nf_conntrack_msg_type type, + struct nf_conntrack *ct, void *data) +{ + char buf[1024]; + int size, *fd = data; + + size = nfct_snprintf(buf, 1024, ct, NFCT_T_UNKNOWN, NFCT_O_DEFAULT, 0); + if (size < 1024) { + buf[size] = '\n'; + size++; + } + send(*fd, buf, size, 0); + + return NFCT_CB_CONTINUE; +} + +static void dump(int fd, int type) +{ + struct nfct_handle *h; + u_int32_t family = AF_UNSPEC; + int ret; + + h = nfct_open(CONNTRACK, 0); + if (h == NULL) { + dlog(LOG_ERR, "can't allocate memory for the internal cache"); + return; + } + nfct_callback_register(h, NFCT_T_ALL, dump_cb, &fd); + ret = nfct_query(h, NFCT_Q_DUMP, &family); + if (ret == -1) { + dlog(LOG_ERR, "can't dump kernel table"); + } + nfct_close(h); +} + +static void flush(void) +{ + nl_flush_conntrack_table(STATE(flush)); +} + +struct { + uint32_t new; + uint32_t upd; + uint32_t del; +} internal_bypass_stats; + +static void stats(int fd) +{ + char buf[512]; + int size; + + size = sprintf(buf, "internal bypass:\n" + "connections new:\t\t%12u\n" + "connections updated:\t\t%12u\n" + "connections destroyed:\t\t%12u\n\n", + internal_bypass_stats.new, + internal_bypass_stats.upd, + internal_bypass_stats.del); + + send(fd, buf, size, 0); +} + +/* unused, INTERNAL_F_POPULATE is unset. No cache, nothing to populate. */ +static void populate(struct nf_conntrack *ct) +{ +} + +/* unused, INTERNAL_F_RESYNC is unset. */ +static void purge(void) +{ +} + +/* unused, INTERNAL_F_RESYNC is unset. Nothing to resync, we have no cache. */ +static int resync(enum nf_conntrack_msg_type type, + struct nf_conntrack *ct, + void *data) +{ + return NFCT_CB_CONTINUE; +} + +static void +event_new_sync(struct nf_conntrack *ct, int origin) +{ + struct nethdr *net; + + /* this event has been triggered by me, skip */ + if (origin != CTD_ORIGIN_NOT_ME) + return; + + net = BUILD_NETMSG(ct, NET_T_STATE_NEW); + multichannel_send(STATE_SYNC(channel), net); + internal_bypass_stats.new++; +} + +static void +event_update_sync(struct nf_conntrack *ct, int origin) +{ + struct nethdr *net; + + /* this event has been triggered by me, skip */ + if (origin != CTD_ORIGIN_NOT_ME) + return; + + net = BUILD_NETMSG(ct, NET_T_STATE_UPD); + multichannel_send(STATE_SYNC(channel), net); + internal_bypass_stats.upd++; +} + +static int +event_destroy_sync(struct nf_conntrack *ct, int origin) +{ + struct nethdr *net; + + /* this event has been triggered by me, skip */ + if (origin != CTD_ORIGIN_NOT_ME) + return 1; + + net = BUILD_NETMSG(ct, NET_T_STATE_DEL); + multichannel_send(STATE_SYNC(channel), net); + internal_bypass_stats.del++; + + return 1; +} + +struct internal_handler internal_bypass = { + .init = _init, + .close = _close, + .dump = dump, + .flush = flush, + .stats = stats, + .stats_ext = stats, + .populate = populate, + .purge = purge, + .resync = resync, + .new = event_new_sync, + .update = event_update_sync, + .destroy = event_destroy_sync, +}; diff --git a/src/internal_cache.c b/src/internal_cache.c new file mode 100644 index 0000000..daadfd6 --- /dev/null +++ b/src/internal_cache.c @@ -0,0 +1,220 @@ +/* + * (C) 2009 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 "conntrackd.h" +#include "sync.h" +#include "log.h" +#include "cache.h" +#include "netlink.h" +#include "network.h" +#include "origin.h" + +static inline void sync_send(struct cache_object *obj, int query) +{ + STATE_SYNC(sync)->enqueue(obj, query); +} + +static int _init(void) +{ + STATE(mode)->internal->data = + cache_create("internal", + STATE_SYNC(sync)->internal_cache_flags, + STATE_SYNC(sync)->internal_cache_extra); + + if (!STATE(mode)->internal->data) { + dlog(LOG_ERR, "can't allocate memory for the internal cache"); + return -1; + } + return 0; +} + +static void _close(void) +{ + cache_destroy(STATE(mode)->internal->data); +} + +static void dump(int fd, int type) +{ + cache_dump(STATE(mode)->internal->data, fd, NFCT_O_PLAIN); +} + +static void flush(void) +{ + cache_flush(STATE(mode)->internal->data); +} + +static void stats(int fd) +{ + cache_stats(STATE(mode)->internal->data, fd); +} + +static void stats_ext(int fd) +{ + cache_stats_extended(STATE(mode)->internal->data, fd); +} + +static void populate(struct nf_conntrack *ct) +{ + /* This is required by kernels < 2.6.20 */ + nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES); + nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS); + nfct_attr_unset(ct, ATTR_REPL_COUNTER_BYTES); + nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); + nfct_attr_unset(ct, ATTR_USE); + + cache_update_force(STATE(mode)->internal->data, ct); +} + +static int purge_step(void *data1, void *data2) +{ + struct cache_object *obj = data2; + + STATE(get_retval) = 0; + nl_get_conntrack(STATE(get), obj->ct); /* modifies STATE(get_reval) */ + if (!STATE(get_retval)) { + if (obj->status != C_OBJ_DEAD) { + cache_object_set_status(obj, C_OBJ_DEAD); + sync_send(obj, NET_T_STATE_DEL); + cache_object_put(obj); + } + } + + return 0; +} + +static void purge(void) +{ + cache_iterate(STATE(mode)->internal->data, NULL, purge_step); +} + +static int resync(enum nf_conntrack_msg_type type, + struct nf_conntrack *ct, + void *data) +{ + struct cache_object *obj; + + if (ct_filter_conntrack(ct, 1)) + return NFCT_CB_CONTINUE; + + /* This is required by kernels < 2.6.20 */ + nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES); + nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS); + nfct_attr_unset(ct, ATTR_REPL_COUNTER_BYTES); + nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); + nfct_attr_unset(ct, ATTR_USE); + + obj = cache_update_force(STATE(mode)->internal->data, ct); + if (obj == NULL) + return NFCT_CB_CONTINUE; + + switch (obj->status) { + case C_OBJ_NEW: + sync_send(obj, NET_T_STATE_NEW); + break; + case C_OBJ_ALIVE: + sync_send(obj, NET_T_STATE_UPD); + break; + } + return NFCT_CB_CONTINUE; +} + +static void +event_new_sync(struct nf_conntrack *ct, int origin) +{ + struct cache_object *obj; + int id; + + /* this event has been triggered by a direct inject, skip */ + if (origin == CTD_ORIGIN_INJECT) + return; + + /* required by linux kernel <= 2.6.20 */ + nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES); + nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS); + nfct_attr_unset(ct, ATTR_REPL_COUNTER_BYTES); + nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); + + obj = cache_find(STATE(mode)->internal->data, ct, &id); + if (obj == NULL) { +retry: + obj = cache_object_new(STATE(mode)->internal->data, ct); + if (obj == NULL) + return; + if (cache_add(STATE(mode)->internal->data, obj, id) == -1) { + cache_object_free(obj); + return; + } + /* only synchronize events that have been triggered by other + * processes or the kernel, but don't propagate events that + * have been triggered by conntrackd itself, eg. commits. */ + if (origin == CTD_ORIGIN_NOT_ME) + sync_send(obj, NET_T_STATE_NEW); + } else { + cache_del(STATE(mode)->internal->data, obj); + cache_object_free(obj); + goto retry; + } +} + +static void +event_update_sync(struct nf_conntrack *ct, int origin) +{ + struct cache_object *obj; + + /* this event has been triggered by a direct inject, skip */ + if (origin == CTD_ORIGIN_INJECT) + return; + + obj = cache_update_force(STATE(mode)->internal->data, ct); + if (obj == NULL) + return; + + if (origin == CTD_ORIGIN_NOT_ME) + sync_send(obj, NET_T_STATE_UPD); +} + +static int +event_destroy_sync(struct nf_conntrack *ct, int origin) +{ + struct cache_object *obj; + int id; + + /* this event has been triggered by a direct inject, skip */ + if (origin == CTD_ORIGIN_INJECT) + return 0; + + /* we don't synchronize events for objects that are not in the cache */ + obj = cache_find(STATE(mode)->internal->data, ct, &id); + if (obj == NULL) + return 0; + + if (obj->status != C_OBJ_DEAD) { + cache_object_set_status(obj, C_OBJ_DEAD); + if (origin == CTD_ORIGIN_NOT_ME) { + sync_send(obj, NET_T_STATE_DEL); + } + cache_object_put(obj); + } + return 1; +} + +struct internal_handler internal_cache = { + .flags = INTERNAL_F_POPULATE | INTERNAL_F_RESYNC, + .init = _init, + .close = _close, + .dump = dump, + .flush = flush, + .stats = stats, + .stats_ext = stats_ext, + .populate = populate, + .purge = purge, + .resync = resync, + .new = event_new_sync, + .update = event_update_sync, + .destroy = event_destroy_sync, +}; diff --git a/src/read_config_lex.l b/src/read_config_lex.l index b4be6f0..b2d4bdb 100644 --- a/src/read_config_lex.l +++ b/src/read_config_lex.l @@ -136,6 +136,7 @@ notrack [N|n][O|o][T|t][R|r][A|a][C|c][K|k] "Type" { return T_TYPE; } "Priority" { return T_PRIO; } "NetlinkEventsReliable" { return T_NETLINK_EVENTS_RELIABLE; } +"DisableInternalCache" { return T_DISABLE_INTERNAL_CACHE; } "DisableExternalCache" { return T_DISABLE_EXTERNAL_CACHE; } "ErrorQueueLength" { return T_ERROR_QUEUE_LENGTH; } diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 5075cf0..157e945 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -72,7 +72,7 @@ static void __max_dedicated_links_reached(void); %token T_FROM T_USERSPACE T_KERNELSPACE T_EVENT_ITER_LIMIT T_DEFAULT %token T_NETLINK_OVERRUN_RESYNC T_NICE T_IPV4_DEST_ADDR T_IPV6_DEST_ADDR %token T_SCHEDULER T_TYPE T_PRIO T_NETLINK_EVENTS_RELIABLE -%token T_DISABLE_EXTERNAL_CACHE T_ERROR_QUEUE_LENGTH +%token T_DISABLE_INTERNAL_CACHE T_DISABLE_EXTERNAL_CACHE T_ERROR_QUEUE_LENGTH %token T_IP T_PATH_VAL %token T_NUMBER @@ -852,9 +852,20 @@ sync_mode_notrack_list: sync_mode_notrack_line: timeout | purge + | disable_internal_cache | disable_external_cache ; +disable_internal_cache: T_DISABLE_INTERNAL_CACHE T_ON +{ + conf.sync.internal_cache_disable = 1; +}; + +disable_internal_cache: T_DISABLE_INTERNAL_CACHE T_OFF +{ + conf.sync.internal_cache_disable = 0; +}; + disable_external_cache: T_DISABLE_EXTERNAL_CACHE T_ON { conf.sync.external_cache_disable = 1; diff --git a/src/run.c b/src/run.c index 54ab1a5..803bbcc 100644 --- a/src/run.c +++ b/src/run.c @@ -28,6 +28,7 @@ #include "process.h" #include "origin.h" #include "date.h" +#include "internal.h" #include #include @@ -56,7 +57,9 @@ void killer(int foo) local_server_destroy(&STATE(local)); STATE(mode)->kill(); - nfct_close(STATE(dump)); /* cache_wt needs this here */ + if (STATE(mode)->internal->flags & INTERNAL_F_POPULATE) { + nfct_close(STATE(dump)); + } destroy_fds(STATE(fds)); unlink(CONFIG(lockfile)); @@ -210,9 +213,13 @@ static int local_handler(int fd, void *data) } break; case RESYNC_MASTER: - STATE(stats).nl_kernel_table_resync++; - dlog(LOG_NOTICE, "resync with master table"); - nl_dump_conntrack_table(STATE(dump)); + if (STATE(mode)->internal->flags & INTERNAL_F_POPULATE) { + STATE(stats).nl_kernel_table_resync++; + dlog(LOG_NOTICE, "resync with master table"); + nl_dump_conntrack_table(STATE(dump)); + } else { + dlog(LOG_NOTICE, "resync is unsupported in this mode"); + } break; case STATS_RUNTIME: dump_stats_runtime(fd); @@ -238,8 +245,8 @@ static void do_overrun_resync_alarm(struct alarm_block *a, void *data) static void do_polling_alarm(struct alarm_block *a, void *data) { - if (STATE(mode)->purge) - STATE(mode)->purge(); + if (STATE(mode)->internal->purge) + STATE(mode)->internal->purge(); nl_send_resync(STATE(resync)); add_alarm(&STATE(polling_alarm), CONFIG(poll_kernel_secs), 0); @@ -264,13 +271,13 @@ static int event_handler(const struct nlmsghdr *nlh, switch(type) { case NFCT_T_NEW: - STATE(mode)->event_new(ct, origin_type); + STATE(mode)->internal->new(ct, origin_type); break; case NFCT_T_UPDATE: - STATE(mode)->event_upd(ct, origin_type); + STATE(mode)->internal->update(ct, origin_type); break; case NFCT_T_DESTROY: - if (STATE(mode)->event_dst(ct, origin_type)) + if (STATE(mode)->internal->destroy(ct, origin_type)) update_traffic_stats(ct); break; default: @@ -295,7 +302,7 @@ static int dump_handler(enum nf_conntrack_msg_type type, switch(type) { case NFCT_T_UPDATE: - STATE(mode)->dump(ct); + STATE(mode)->internal->populate(ct); break; default: STATE(stats).nl_dump_unknown_type++; @@ -371,23 +378,26 @@ init(void) } nfct_callback_register(STATE(resync), NFCT_T_ALL, - STATE(mode)->resync, + STATE(mode)->internal->resync, NULL); register_fd(nfct_fd(STATE(resync)), STATE(fds)); fcntl(nfct_fd(STATE(resync)), F_SETFL, O_NONBLOCK); - STATE(dump) = nfct_open(CONNTRACK, 0); - if (STATE(dump) == NULL) { - dlog(LOG_ERR, "can't open netlink handler: %s", - strerror(errno)); - dlog(LOG_ERR, "no ctnetlink kernel support?"); - return -1; - } - nfct_callback_register(STATE(dump), NFCT_T_ALL, dump_handler, NULL); + if (STATE(mode)->internal->flags & INTERNAL_F_POPULATE) { + STATE(dump) = nfct_open(CONNTRACK, 0); + if (STATE(dump) == NULL) { + dlog(LOG_ERR, "can't open netlink handler: %s", + strerror(errno)); + dlog(LOG_ERR, "no ctnetlink kernel support?"); + return -1; + } + nfct_callback_register(STATE(dump), NFCT_T_ALL, + dump_handler, NULL); - if (nl_dump_conntrack_table(STATE(dump)) == -1) { - dlog(LOG_ERR, "can't get kernel conntrack table"); - return -1; + if (nl_dump_conntrack_table(STATE(dump)) == -1) { + dlog(LOG_ERR, "can't get kernel conntrack table"); + return -1; + } } STATE(get) = nfct_open(CONNTRACK, 0); @@ -499,7 +509,9 @@ static void __run(struct timeval *next_alarm) * we resync ourselves. */ nl_resize_socket_buffer(STATE(event)); - if (CONFIG(nl_overrun_resync) > 0) { + if (CONFIG(nl_overrun_resync) > 0 && + STATE(mode)->internal->flags & + INTERNAL_F_RESYNC) { add_alarm(&STATE(resync_alarm), CONFIG(nl_overrun_resync),0); } @@ -523,8 +535,8 @@ static void __run(struct timeval *next_alarm) } if (FD_ISSET(nfct_fd(STATE(resync)), &readfds)) { nfct_catch(STATE(resync)); - if (STATE(mode)->purge) - STATE(mode)->purge(); + if (STATE(mode)->internal->purge) + STATE(mode)->internal->purge(); } } else { /* using polling mode */ diff --git a/src/stats-mode.c b/src/stats-mode.c index 5cfb638..0403ce2 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -21,6 +21,7 @@ #include "cache.h" #include "log.h" #include "conntrackd.h" +#include "internal.h" #include #include @@ -87,7 +88,7 @@ static int local_handler_stats(int fd, int type, void *data) return ret; } -static void dump_stats(struct nf_conntrack *ct) +static void populate_stats(struct nf_conntrack *ct) { nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES); nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS); @@ -134,11 +135,9 @@ static int purge_step(void *data1, void *data2) return 0; } -static int purge_stats(void) +static void purge_stats(void) { cache_iterate(STATE_STATS(cache), NULL, purge_step); - - return 0; } static void @@ -188,15 +187,20 @@ event_destroy_stats(struct nf_conntrack *ct, int origin) return 0; } +static struct internal_handler internal_cache_stats = { + .flags = INTERNAL_F_POPULATE | INTERNAL_F_RESYNC, + .populate = populate_stats, + .resync = resync_stats, + .purge = purge_stats, + .new = event_new_stats, + .update = event_update_stats, + .destroy = event_destroy_stats +}; + struct ct_mode stats_mode = { .init = init_stats, .run = NULL, .local = local_handler_stats, .kill = kill_stats, - .dump = dump_stats, - .resync = resync_stats, - .purge = purge_stats, - .event_new = event_new_stats, - .event_upd = event_update_stats, - .event_dst = event_destroy_stats + .internal = &internal_cache_stats, }; diff --git a/src/sync-alarm.c b/src/sync-alarm.c index 4757026..0fc7943 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -109,7 +109,8 @@ static int alarm_recv(const struct nethdr *net) static void alarm_enqueue(struct cache_object *obj, int query) { - struct cache_alarm *ca = cache_get_extra(STATE_SYNC(internal), obj); + struct cache_alarm *ca = + cache_get_extra(STATE(mode)->internal->data, obj); if (queue_add(STATE_SYNC(tx_queue), &ca->qnode)) cache_object_get(obj); } @@ -134,7 +135,7 @@ static int tx_queue_xmit(struct queue_node *n, const void *data) int type; ca = (struct cache_alarm *)n; - obj = cache_data_get_object(STATE_SYNC(internal), ca); + obj = cache_data_get_object(STATE(mode)->internal->data, ca); type = object_status_to_network_type(obj->status); net = BUILD_NETMSG(obj->ct, type); multichannel_send(STATE_SYNC(channel), net); diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 0d31e17..86edeab 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -166,7 +166,8 @@ static void ftfw_kill(void) static int do_cache_to_tx(void *data1, void *data2) { struct cache_object *obj = data2; - struct cache_ftfw *cn = cache_get_extra(STATE_SYNC(internal), obj); + struct cache_ftfw *cn = + cache_get_extra(STATE(mode)->internal->data, obj); if (queue_in(rs_queue, &cn->qnode)) { queue_del(&cn->qnode); @@ -224,7 +225,8 @@ static int ftfw_local(int fd, int type, void *data) break; case SEND_BULK: dlog(LOG_NOTICE, "sending bulk update"); - cache_iterate(STATE_SYNC(internal), NULL, do_cache_to_tx); + cache_iterate(STATE(mode)->internal->data, + NULL, do_cache_to_tx); break; case STATS_RSQUEUE: ftfw_local_queue(fd); @@ -303,7 +305,7 @@ static int rs_queue_empty(struct queue_node *n, const void *data) cn = (struct cache_ftfw *) n; if (h == NULL) { queue_del(n); - obj = cache_data_get_object(STATE_SYNC(internal), cn); + obj = cache_data_get_object(STATE(mode)->internal->data, cn); cache_object_put(obj); return 0; } @@ -314,7 +316,7 @@ static int rs_queue_empty(struct queue_node *n, const void *data) dp("queue: deleting from queue (seq=%u)\n", cn->seq); queue_del(n); - obj = cache_data_get_object(STATE_SYNC(internal), cn); + obj = cache_data_get_object(STATE(mode)->internal->data, cn); cache_object_put(obj); break; } @@ -347,7 +349,7 @@ static int digest_msg(const struct nethdr *net) } else if (IS_RESYNC(net)) { dp("RESYNC ALL\n"); - cache_iterate(STATE_SYNC(internal), NULL, do_cache_to_tx); + cache_iterate(STATE(mode)->internal->data, NULL, do_cache_to_tx); return MSG_CTL; } else if (IS_ALIVE(net)) @@ -464,7 +466,7 @@ static void rs_queue_purge_full(void) struct cache_object *obj; cn = (struct cache_ftfw *)n; - obj = cache_data_get_object(STATE_SYNC(internal), cn); + obj = cache_data_get_object(STATE(mode)->internal->data, cn); cache_object_put(obj); break; } @@ -512,7 +514,7 @@ static int tx_queue_xmit(struct queue_node *n, const void *data) struct nethdr *net; cn = (struct cache_ftfw *)n; - obj = cache_data_get_object(STATE_SYNC(internal), cn); + obj = cache_data_get_object(STATE(mode)->internal->data, cn); type = object_status_to_network_type(obj->status); net = BUILD_NETMSG(obj->ct, type); nethdr_set_hello(net); @@ -546,7 +548,8 @@ static void ftfw_xmit(void) static void ftfw_enqueue(struct cache_object *obj, int type) { - struct cache_ftfw *cn = cache_get_extra(STATE_SYNC(internal), obj); + struct cache_ftfw *cn = + cache_get_extra(STATE(mode)->internal->data, obj); if (queue_in(rs_queue, &cn->qnode)) { queue_del(&cn->qnode); queue_add(STATE_SYNC(tx_queue), &cn->qnode); diff --git a/src/sync-mode.c b/src/sync-mode.c index 63fae68..ecc2f0d 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -28,6 +28,7 @@ #include "queue.h" #include "process.h" #include "origin.h" +#include "internal.h" #include "external.h" #include @@ -246,7 +247,7 @@ static void do_reset_cache_alarm(struct alarm_block *a, void *data) exit(EXIT_SUCCESS); } /* this is not required if events don't get lost */ - cache_flush(STATE_SYNC(internal)); + STATE(mode)->internal->flush(); } static int init_sync(void) @@ -276,15 +277,15 @@ static int init_sync(void) if (STATE_SYNC(sync)->init) STATE_SYNC(sync)->init(); - STATE_SYNC(internal) = - cache_create("internal", - STATE_SYNC(sync)->internal_cache_flags, - STATE_SYNC(sync)->internal_cache_extra); + if (CONFIG(sync).internal_cache_disable == 0) { + STATE(mode)->internal = &internal_cache; + } else { + STATE(mode)->internal = &internal_bypass; + dlog(LOG_NOTICE, "disabling internal cache"); - if (!STATE_SYNC(internal)) { - dlog(LOG_ERR, "can't allocate memory for the internal cache"); - return -1; } + if (STATE(mode)->internal->init() == -1) + return -1; if (CONFIG(sync).external_cache_disable == 0) { STATE_SYNC(external) = &external_cache; @@ -389,7 +390,7 @@ static void run_sync(fd_set *readfds) static void kill_sync(void) { - cache_destroy(STATE_SYNC(internal)); + STATE(mode)->internal->close(); STATE_SYNC(external)->close(); multichannel_close(STATE_SYNC(channel)); @@ -466,7 +467,7 @@ static int local_handler_sync(int fd, int type, void *data) case DUMP_INTERNAL: ret = fork_process_new(CTD_PROC_ANY, 0, NULL, NULL); if (ret == 0) { - cache_dump(STATE_SYNC(internal), fd, NFCT_O_PLAIN); + STATE(mode)->internal->dump(fd, NFCT_O_PLAIN); exit(EXIT_SUCCESS); } break; @@ -480,7 +481,7 @@ static int local_handler_sync(int fd, int type, void *data) case DUMP_INT_XML: ret = fork_process_new(CTD_PROC_ANY, 0, NULL, NULL); if (ret == 0) { - cache_dump(STATE_SYNC(internal), fd, NFCT_O_XML); + STATE(mode)->internal->dump(fd, NFCT_O_XML); exit(EXIT_SUCCESS); } break; @@ -512,14 +513,14 @@ static int local_handler_sync(int fd, int type, void *data) /* inmediate flush, remove pending flush scheduled if any */ del_alarm(&STATE_SYNC(reset_cache_alarm)); dlog(LOG_NOTICE, "flushing caches"); - cache_flush(STATE_SYNC(internal)); + STATE(mode)->internal->flush(); STATE_SYNC(external)->flush(); break; case FLUSH_INT_CACHE: /* inmediate flush, remove pending flush scheduled if any */ del_alarm(&STATE_SYNC(reset_cache_alarm)); dlog(LOG_NOTICE, "flushing internal cache"); - cache_flush(STATE_SYNC(internal)); + STATE(mode)->internal->flush(); break; case FLUSH_EXT_CACHE: dlog(LOG_NOTICE, "flushing external cache"); @@ -529,7 +530,7 @@ static int local_handler_sync(int fd, int type, void *data) killer(0); break; case STATS: - cache_stats(STATE_SYNC(internal), fd); + STATE(mode)->internal->stats(fd); STATE_SYNC(external)->stats(fd); dump_traffic_stats(fd); multichannel_stats(STATE_SYNC(channel), fd); @@ -540,7 +541,7 @@ static int local_handler_sync(int fd, int type, void *data) multichannel_stats(STATE_SYNC(channel), fd); break; case STATS_CACHE: - cache_stats_extended(STATE_SYNC(internal), fd); + STATE(mode)->internal->stats_ext(fd); STATE_SYNC(external)->stats_ext(fd); break; case STATS_LINK: @@ -559,167 +560,10 @@ static int local_handler_sync(int fd, int type, void *data) return ret; } -static void sync_send(struct cache_object *obj, int query) -{ - STATE_SYNC(sync)->enqueue(obj, query); -} - -static void dump_sync(struct nf_conntrack *ct) -{ - /* This is required by kernels < 2.6.20 */ - nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES); - nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS); - nfct_attr_unset(ct, ATTR_REPL_COUNTER_BYTES); - nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); - nfct_attr_unset(ct, ATTR_USE); - - cache_update_force(STATE_SYNC(internal), ct); -} - -static int purge_step(void *data1, void *data2) -{ - struct cache_object *obj = data2; - - STATE(get_retval) = 0; - nl_get_conntrack(STATE(get), obj->ct); /* modifies STATE(get_reval) */ - if (!STATE(get_retval)) { - if (obj->status != C_OBJ_DEAD) { - cache_object_set_status(obj, C_OBJ_DEAD); - sync_send(obj, NET_T_STATE_DEL); - cache_object_put(obj); - } - } - - return 0; -} - -static int purge_sync(void) -{ - cache_iterate(STATE_SYNC(internal), NULL, purge_step); - - return 0; -} - -static int resync_sync(enum nf_conntrack_msg_type type, - struct nf_conntrack *ct, - void *data) -{ - struct cache_object *obj; - - if (ct_filter_conntrack(ct, 1)) - return NFCT_CB_CONTINUE; - - /* This is required by kernels < 2.6.20 */ - nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES); - nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS); - nfct_attr_unset(ct, ATTR_REPL_COUNTER_BYTES); - nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); - nfct_attr_unset(ct, ATTR_USE); - - obj = cache_update_force(STATE_SYNC(internal), ct); - if (obj == NULL) - return NFCT_CB_CONTINUE; - - switch (obj->status) { - case C_OBJ_NEW: - sync_send(obj, NET_T_STATE_NEW); - break; - case C_OBJ_ALIVE: - sync_send(obj, NET_T_STATE_UPD); - break; - } - return NFCT_CB_CONTINUE; -} - -static void -event_new_sync(struct nf_conntrack *ct, int origin) -{ - struct cache_object *obj; - int id; - - /* this event has been triggered by a direct inject, skip */ - if (origin == CTD_ORIGIN_INJECT) - return; - - /* required by linux kernel <= 2.6.20 */ - nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES); - nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS); - nfct_attr_unset(ct, ATTR_REPL_COUNTER_BYTES); - nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); - - obj = cache_find(STATE_SYNC(internal), ct, &id); - if (obj == NULL) { -retry: - obj = cache_object_new(STATE_SYNC(internal), ct); - if (obj == NULL) - return; - if (cache_add(STATE_SYNC(internal), obj, id) == -1) { - cache_object_free(obj); - return; - } - /* only synchronize events that have been triggered by other - * processes or the kernel, but don't propagate events that - * have been triggered by conntrackd itself, eg. commits. */ - if (origin == CTD_ORIGIN_NOT_ME) - sync_send(obj, NET_T_STATE_NEW); - } else { - cache_del(STATE_SYNC(internal), obj); - cache_object_free(obj); - goto retry; - } -} - -static void -event_update_sync(struct nf_conntrack *ct, int origin) -{ - struct cache_object *obj; - - /* this event has been triggered by a direct inject, skip */ - if (origin == CTD_ORIGIN_INJECT) - return; - - obj = cache_update_force(STATE_SYNC(internal), ct); - if (obj == NULL) - return; - - if (origin == CTD_ORIGIN_NOT_ME) - sync_send(obj, NET_T_STATE_UPD); -} - -static int -event_destroy_sync(struct nf_conntrack *ct, int origin) -{ - struct cache_object *obj; - int id; - - /* this event has been triggered by a direct inject, skip */ - if (origin == CTD_ORIGIN_INJECT) - return 0; - - /* we don't synchronize events for objects that are not in the cache */ - obj = cache_find(STATE_SYNC(internal), ct, &id); - if (obj == NULL) - return 0; - - if (obj->status != C_OBJ_DEAD) { - cache_object_set_status(obj, C_OBJ_DEAD); - if (origin == CTD_ORIGIN_NOT_ME) { - sync_send(obj, NET_T_STATE_DEL); - } - cache_object_put(obj); - } - return 1; -} - struct ct_mode sync_mode = { .init = init_sync, .run = run_sync, .local = local_handler_sync, .kill = kill_sync, - .dump = dump_sync, - .resync = resync_sync, - .purge = purge_sync, - .event_new = event_new_sync, - .event_upd = event_update_sync, - .event_dst = event_destroy_sync + /* the internal handler is set in run-time. */ }; diff --git a/src/sync-notrack.c b/src/sync-notrack.c index d9f273e..c4ad941 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -74,12 +74,44 @@ static void tx_queue_add_ctlmsg(uint32_t flags, uint32_t from, uint32_t to) static int do_cache_to_tx(void *data1, void *data2) { struct cache_object *obj = data2; - struct cache_notrack *cn = cache_get_extra(STATE_SYNC(internal), obj); + struct cache_notrack *cn = + cache_get_extra(STATE(mode)->internal->data, obj); if (queue_add(STATE_SYNC(tx_queue), &cn->qnode)) cache_object_get(obj); return 0; } +static int kernel_resync_cb(enum nf_conntrack_msg_type type, + struct nf_conntrack *ct, void *data) +{ + struct nethdr *net; + + net = BUILD_NETMSG(ct, NET_T_STATE_NEW); + multichannel_send(STATE_SYNC(channel), net); + + return NFCT_CB_CONTINUE; +} + +/* Only used if the internal cache is disabled. */ +static void kernel_resync(void) +{ + struct nfct_handle *h; + u_int32_t family = AF_UNSPEC; + int ret; + + h = nfct_open(CONNTRACK, 0); + if (h == NULL) { + dlog(LOG_ERR, "can't allocate memory for the internal cache"); + return; + } + nfct_callback_register(h, NFCT_T_ALL, kernel_resync_cb, NULL); + ret = nfct_query(h, NFCT_Q_DUMP, &family); + if (ret == -1) { + dlog(LOG_ERR, "can't dump kernel table"); + } + nfct_close(h); +} + static int notrack_local(int fd, int type, void *data) { int ret = LOCAL_RET_OK; @@ -91,7 +123,12 @@ static int notrack_local(int fd, int type, void *data) break; case SEND_BULK: dlog(LOG_NOTICE, "sending bulk update"); - cache_iterate(STATE_SYNC(internal), NULL, do_cache_to_tx); + if (CONFIG(sync).internal_cache_disable) { + kernel_resync(); + } else { + cache_iterate(STATE(mode)->internal->data, + NULL, do_cache_to_tx); + } break; default: ret = 0; @@ -107,7 +144,12 @@ static int digest_msg(const struct nethdr *net) return MSG_DATA; if (IS_RESYNC(net)) { - cache_iterate(STATE_SYNC(internal), NULL, do_cache_to_tx); + if (CONFIG(sync).internal_cache_disable) { + kernel_resync(); + } else { + cache_iterate(STATE(mode)->internal->data, + NULL, do_cache_to_tx); + } return MSG_CTL; } @@ -154,7 +196,7 @@ static int tx_queue_xmit(struct queue_node *n, const void *data2) struct nethdr *net; cn = (struct cache_ftfw *)n; - obj = cache_data_get_object(STATE_SYNC(internal), cn); + obj = cache_data_get_object(STATE(mode)->internal->data, cn); type = object_status_to_network_type(obj->status);; net = BUILD_NETMSG(obj->ct, type); @@ -175,7 +217,8 @@ static void notrack_xmit(void) static void notrack_enqueue(struct cache_object *obj, int query) { - struct cache_notrack *cn = cache_get_extra(STATE_SYNC(internal), obj); + struct cache_notrack *cn = + cache_get_extra(STATE(mode)->internal->data, obj); if (queue_add(STATE_SYNC(tx_queue), &cn->qnode)) cache_object_get(obj); } -- cgit v1.2.3 From 2f52fea14f94fb267e22280bce2d45f44c3b34f0 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 19 Dec 2009 13:55:00 +0100 Subject: conntrackd: use indirect call to build layer 4 protocol information With this patch, we use an indirect call to build the layer 4 information into the synchronization message. Signed-off-by: Pablo Neira Ayuso --- src/build.c | 53 +++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 43 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/build.c b/src/build.c index 92760f2..defb2ec 100644 --- a/src/build.c +++ b/src/build.c @@ -97,9 +97,50 @@ static enum nf_conntrack_attr nat_type[] = ATTR_ORIG_NAT_SEQ_OFFSET_AFTER, ATTR_REPL_NAT_SEQ_CORRECTION_POS, ATTR_REPL_NAT_SEQ_OFFSET_BEFORE, ATTR_REPL_NAT_SEQ_OFFSET_AFTER }; +static void build_l4proto_tcp(const struct nf_conntrack *ct, struct nethdr *n) +{ + if (!nfct_attr_is_set(ct, ATTR_TCP_STATE)) + return; + + __build_u8(ct, ATTR_TCP_STATE, n, NTA_TCP_STATE); +} + +static void build_l4proto_sctp(const struct nf_conntrack *ct, struct nethdr *n) +{ + if (!nfct_attr_is_set(ct, ATTR_SCTP_STATE)) + return; + + __build_u8(ct, ATTR_SCTP_STATE, n, NTA_SCTP_STATE); + __build_u32(ct, ATTR_SCTP_VTAG_ORIG, n, NTA_SCTP_VTAG_ORIG); + __build_u32(ct, ATTR_SCTP_VTAG_REPL, n, NTA_SCTP_VTAG_REPL); +} + +static void build_l4proto_dccp(const struct nf_conntrack *ct, struct nethdr *n) +{ + if (!nfct_attr_is_set(ct, ATTR_DCCP_STATE)) + return; + + __build_u8(ct, ATTR_DCCP_STATE, n, NTA_DCCP_STATE); + __build_u8(ct, ATTR_DCCP_ROLE, n, NTA_DCCP_ROLE); +} + +#ifndef IPPROTO_DCCP +#define IPPROTO_DCCP 33 +#endif + +static struct build_l4proto { + void (*build)(const struct nf_conntrack *, struct nethdr *n); +} l4proto_fcn[IPPROTO_MAX] = { + [IPPROTO_TCP] = { .build = build_l4proto_tcp }, + [IPPROTO_SCTP] = { .build = build_l4proto_sctp }, + [IPPROTO_DCCP] = { .build = build_l4proto_dccp }, +}; + /* XXX: ICMP not supported */ void build_payload(const struct nf_conntrack *ct, struct nethdr *n) { + uint8_t l4proto = nfct_get_attr_u8(ct, ATTR_L4PROTO); + if (nfct_attr_grp_is_set(ct, ATTR_GRP_ORIG_IPV4)) { __build_group(ct, ATTR_GRP_ORIG_IPV4, n, NTA_IPV4, sizeof(struct nfct_attr_grp_ipv4)); @@ -116,16 +157,8 @@ void build_payload(const struct nf_conntrack *ct, struct nethdr *n) __build_u32(ct, ATTR_STATUS, n, NTA_STATUS); - if (nfct_attr_is_set(ct, ATTR_TCP_STATE)) - __build_u8(ct, ATTR_TCP_STATE, n, NTA_TCP_STATE); - else if (nfct_attr_is_set(ct, ATTR_SCTP_STATE)) { - __build_u8(ct, ATTR_SCTP_STATE, n, NTA_SCTP_STATE); - __build_u32(ct, ATTR_SCTP_VTAG_ORIG, n, NTA_SCTP_VTAG_ORIG); - __build_u32(ct, ATTR_SCTP_VTAG_REPL, n, NTA_SCTP_VTAG_REPL); - } else if (nfct_attr_is_set(ct, ATTR_DCCP_STATE)) { - __build_u8(ct, ATTR_DCCP_STATE, n, NTA_DCCP_STATE); - __build_u8(ct, ATTR_DCCP_ROLE, n, NTA_DCCP_ROLE); - } + if (l4proto_fcn[l4proto].build) + l4proto_fcn[l4proto].build(ct, n); if (!CONFIG(commit_timeout) && nfct_attr_is_set(ct, ATTR_TIMEOUT)) __build_u32(ct, ATTR_TIMEOUT, n, NTA_TIMEOUT); -- cgit v1.2.3 From 65645763ebe870fa01b5c1a5dbe810feb9397ff2 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 6 Oct 2009 11:19:28 +0200 Subject: conntrackd: add ICMP support for state-synchronization This patch adds state-synchronization for ICMP. You SHOULD use a Linux kernel >= 2.6.31, otherwise this patch can result in tons of state-updates. Signed-off-by: Pablo Neira Ayuso --- doc/sync/alarm/conntrackd.conf | 1 + doc/sync/ftfw/conntrackd.conf | 1 + doc/sync/notrack/conntrackd.conf | 1 + include/network.h | 3 +++ src/build.c | 9 ++++++++- src/parse.c | 15 +++++++++++++++ 6 files changed, 29 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/doc/sync/alarm/conntrackd.conf b/doc/sync/alarm/conntrackd.conf index 800012f..3424e39 100644 --- a/doc/sync/alarm/conntrackd.conf +++ b/doc/sync/alarm/conntrackd.conf @@ -332,6 +332,7 @@ General { TCP SCTP DCCP + # ICMP # This requires a Linux kernel >= 2.6.31 } # diff --git a/doc/sync/ftfw/conntrackd.conf b/doc/sync/ftfw/conntrackd.conf index 81f2de1..df10aca 100644 --- a/doc/sync/ftfw/conntrackd.conf +++ b/doc/sync/ftfw/conntrackd.conf @@ -357,6 +357,7 @@ General { TCP SCTP DCCP + # ICMP # This requires a Linux kernel >= 2.6.31 } # diff --git a/doc/sync/notrack/conntrackd.conf b/doc/sync/notrack/conntrackd.conf index 529fbd9..5b9ebbb 100644 --- a/doc/sync/notrack/conntrackd.conf +++ b/doc/sync/notrack/conntrackd.conf @@ -338,6 +338,7 @@ General { TCP SCTP DCCP + # ICMP # This requires a Linux kernel >= 2.6.31 } # diff --git a/include/network.h b/include/network.h index dfc3015..70812b1 100644 --- a/include/network.h +++ b/include/network.h @@ -217,6 +217,9 @@ enum nta_attr { NTA_SCTP_VTAG_REPL, /* uint32_t */ NTA_DCCP_STATE = 20, /* uint8_t */ NTA_DCCP_ROLE, /* uint8_t */ + NTA_ICMP_TYPE, /* uint8_t */ + NTA_ICMP_CODE, /* uint8_t */ + NTA_ICMP_ID, /* uint16_t */ NTA_MAX }; diff --git a/src/build.c b/src/build.c index defb2ec..6d8b12e 100644 --- a/src/build.c +++ b/src/build.c @@ -124,6 +124,13 @@ static void build_l4proto_dccp(const struct nf_conntrack *ct, struct nethdr *n) __build_u8(ct, ATTR_DCCP_ROLE, n, NTA_DCCP_ROLE); } +static void build_l4proto_icmp(const struct nf_conntrack *ct, struct nethdr *n) +{ + __build_u8(ct, ATTR_ICMP_TYPE, n, NTA_ICMP_TYPE); + __build_u8(ct, ATTR_ICMP_CODE, n, NTA_ICMP_CODE); + __build_u16(ct, ATTR_ICMP_ID, n, NTA_ICMP_ID); +} + #ifndef IPPROTO_DCCP #define IPPROTO_DCCP 33 #endif @@ -134,9 +141,9 @@ static struct build_l4proto { [IPPROTO_TCP] = { .build = build_l4proto_tcp }, [IPPROTO_SCTP] = { .build = build_l4proto_sctp }, [IPPROTO_DCCP] = { .build = build_l4proto_dccp }, + [IPPROTO_ICMP] = { .build = build_l4proto_icmp }, }; -/* XXX: ICMP not supported */ void build_payload(const struct nf_conntrack *ct, struct nethdr *n) { uint8_t l4proto = nfct_get_attr_u8(ct, ATTR_L4PROTO); diff --git a/src/parse.c b/src/parse.c index b5f257c..e6eefe4 100644 --- a/src/parse.c +++ b/src/parse.c @@ -146,6 +146,21 @@ static struct parser h[NTA_MAX] = { .attr = ATTR_DCCP_ROLE, .size = NTA_SIZE(sizeof(uint8_t)), }, + [NTA_ICMP_TYPE] = { + .parse = parse_u8, + .attr = ATTR_ICMP_TYPE, + .size = NTA_SIZE(sizeof(uint8_t)), + }, + [NTA_ICMP_CODE] = { + .parse = parse_u8, + .attr = ATTR_ICMP_CODE, + .size = NTA_SIZE(sizeof(uint8_t)), + }, + [NTA_ICMP_ID] = { + .parse = parse_u16, + .attr = ATTR_ICMP_ID, + .size = NTA_SIZE(sizeof(uint16_t)), + }, }; static void -- cgit v1.2.3 From ba8f0e07adc2e124fdb34a8a8f86fcce42a939d8 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 23 Dec 2009 19:37:36 +0100 Subject: conntrackd: fix flow-state filtering for TCP This patch fixes the clause `State' in `Filter' that allows you to filter by protocol state. This bug was introduced during the implementation of the TCP-based synchronization. Signed-off-by: Pablo Neira Ayuso --- src/read_config_yy.y | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 157e945..6dfca98 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -936,6 +936,9 @@ state_proto: T_STRING }; state: tcp_state; +tcp_states: + | tcp_states tcp_state; + tcp_state: T_SYN_SENT { ct_filter_add_state(STATE(us_filter), @@ -1397,7 +1400,7 @@ filter_item : T_STATE T_IGNORE '{' filter_state_list '}' filter_state_list : | filter_state_list filter_state_item; -filter_state_item : states T_FOR state_proto ; +filter_state_item : tcp_states T_FOR T_TCP; stats: T_STATS '{' stats_list '}' { -- cgit v1.2.3 From 73da80df0c3cf4175662b3da4dfbd3574d34f96a Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 11 Feb 2010 11:56:37 +0100 Subject: conntrackd: fix UDP filtering in configuration file UDP filtering was broken during the addition of the UDP-based synchronization protocol that was introduced in 0.9.14. This patch fixes the problem. Signed-off-by: Pablo Neira Ayuso --- doc/stats/conntrackd.conf | 1 + doc/sync/alarm/conntrackd.conf | 1 + doc/sync/ftfw/conntrackd.conf | 1 + doc/sync/notrack/conntrackd.conf | 1 + src/read_config_yy.y | 19 +++++++++++++++++++ 5 files changed, 23 insertions(+) (limited to 'src') diff --git a/doc/stats/conntrackd.conf b/doc/stats/conntrackd.conf index 0941f64..22556a0 100644 --- a/doc/stats/conntrackd.conf +++ b/doc/stats/conntrackd.conf @@ -81,6 +81,7 @@ General { # Protocol Accept { TCP + # UDP } # diff --git a/doc/sync/alarm/conntrackd.conf b/doc/sync/alarm/conntrackd.conf index 3424e39..9b7d8c6 100644 --- a/doc/sync/alarm/conntrackd.conf +++ b/doc/sync/alarm/conntrackd.conf @@ -332,6 +332,7 @@ General { TCP SCTP DCCP + # UDP # ICMP # This requires a Linux kernel >= 2.6.31 } diff --git a/doc/sync/ftfw/conntrackd.conf b/doc/sync/ftfw/conntrackd.conf index df10aca..877ed68 100644 --- a/doc/sync/ftfw/conntrackd.conf +++ b/doc/sync/ftfw/conntrackd.conf @@ -357,6 +357,7 @@ General { TCP SCTP DCCP + # UDP # ICMP # This requires a Linux kernel >= 2.6.31 } diff --git a/doc/sync/notrack/conntrackd.conf b/doc/sync/notrack/conntrackd.conf index f8bccc4..693209a 100644 --- a/doc/sync/notrack/conntrackd.conf +++ b/doc/sync/notrack/conntrackd.conf @@ -394,6 +394,7 @@ General { TCP SCTP DCCP + # UDP # ICMP # This requires a Linux kernel >= 2.6.31 } diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 6dfca98..5f4e6be 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -1221,6 +1221,25 @@ filter_protocol_item : T_TCP pent->p_proto); }; +filter_protocol_item : T_UDP +{ + struct protoent *pent; + + pent = getprotobyname("udp"); + if (pent == NULL) { + print_err(CTD_CFG_WARN, "getprotobyname() cannot find " + "protocol `udp' in /etc/protocols"); + break; + } + ct_filter_add_proto(STATE(us_filter), pent->p_proto); + + __kernel_filter_start(); + + nfct_filter_add_attr_u32(STATE(filter), + NFCT_FILTER_L4PROTO, + pent->p_proto); +}; + filter_item : T_ADDRESS T_ACCEPT '{' filter_address_list '}' { ct_filter_set_logic(STATE(us_filter), -- cgit v1.2.3 From 56817d1c0cc30bcd65c56c2f73634b256603cc4d Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 29 Dec 2009 20:02:55 +0100 Subject: conntrackd: add support for TCP window scale factor synchronization This patch adds a new option TCPWindowTracking that allows not to disable TCP window tracking as it occurs by default. Signed-off-by: Pablo Neira Ayuso --- doc/sync/alarm/conntrackd.conf | 11 +++++++++++ doc/sync/ftfw/conntrackd.conf | 10 ++++++++++ doc/sync/notrack/conntrackd.conf | 11 +++++++++++ include/conntrackd.h | 1 + include/network.h | 2 ++ src/build.c | 4 ++++ src/netlink.c | 20 ++++++++++---------- src/parse.c | 10 ++++++++++ src/read_config_lex.l | 2 ++ src/read_config_yy.y | 18 ++++++++++++++++++ 10 files changed, 79 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/doc/sync/alarm/conntrackd.conf b/doc/sync/alarm/conntrackd.conf index 9b7d8c6..65c8715 100644 --- a/doc/sync/alarm/conntrackd.conf +++ b/doc/sync/alarm/conntrackd.conf @@ -180,6 +180,17 @@ Sync { # # Checksum on # } + + # + # Other unsorted options that are related to the synchronization. + # + # Options { + # + # TCP state-entries have window tracking disabled by default, + # you can enable it with this option. As said, default is off. + # + # TCPWindowTracking Off + # } } # diff --git a/doc/sync/ftfw/conntrackd.conf b/doc/sync/ftfw/conntrackd.conf index 877ed68..481fe8b 100644 --- a/doc/sync/ftfw/conntrackd.conf +++ b/doc/sync/ftfw/conntrackd.conf @@ -204,6 +204,16 @@ Sync { # Checksum on # } + # + # Other unsorted options that are related to the synchronization. + # + # Options { + # + # TCP state-entries have window tracking disabled by default, + # you can enable it with this option. As said, default is off. + # + # TCPWindowTracking Off + # } } # diff --git a/doc/sync/notrack/conntrackd.conf b/doc/sync/notrack/conntrackd.conf index 693209a..430ca25 100644 --- a/doc/sync/notrack/conntrackd.conf +++ b/doc/sync/notrack/conntrackd.conf @@ -242,6 +242,17 @@ Sync { # # Checksum on # } + + # + # Other unsorted options that are related to the synchronization. + # + # Options { + # + # TCP state-entries have window tracking disabled by default, + # you can enable it with this option. As said, default is off. + # + # TCPWindowTracking Off + # } } # diff --git a/include/conntrackd.h b/include/conntrackd.h index c7f33f0..b35c95d 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -102,6 +102,7 @@ struct ct_conf { struct { int internal_cache_disable; int external_cache_disable; + int tcp_window_tracking; } sync; struct { int events_reliable; diff --git a/include/network.h b/include/network.h index 70812b1..567317b 100644 --- a/include/network.h +++ b/include/network.h @@ -220,6 +220,8 @@ enum nta_attr { NTA_ICMP_TYPE, /* uint8_t */ NTA_ICMP_CODE, /* uint8_t */ NTA_ICMP_ID, /* uint16_t */ + NTA_TCP_WSCALE_ORIG, /* uint8_t */ + NTA_TCP_WSCALE_REPL, /* uint8_t */ NTA_MAX }; diff --git a/src/build.c b/src/build.c index 6d8b12e..0bfe8c1 100644 --- a/src/build.c +++ b/src/build.c @@ -103,6 +103,10 @@ static void build_l4proto_tcp(const struct nf_conntrack *ct, struct nethdr *n) return; __build_u8(ct, ATTR_TCP_STATE, n, NTA_TCP_STATE); + if (CONFIG(sync).tcp_window_tracking) { + __build_u8(ct, ATTR_TCP_WSCALE_ORIG, n, NTA_TCP_WSCALE_ORIG); + __build_u8(ct, ATTR_TCP_WSCALE_REPL, n, NTA_TCP_WSCALE_REPL); + } } static void build_l4proto_sctp(const struct nf_conntrack *ct, struct nethdr *n) diff --git a/src/netlink.c b/src/netlink.c index a43f782..5b6452a 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -196,12 +196,12 @@ int nl_create_conntrack(struct nfct_handle *h, nfct_setobjopt(ct, NFCT_SOPT_SETUP_REPLY); - /* - * TCP flags to overpass window tracking for recovered connections - */ + /* disable TCP window tracking for recovered connections if required */ if (nfct_attr_is_set(ct, ATTR_TCP_STATE)) { - uint8_t flags = IP_CT_TCP_FLAG_BE_LIBERAL | - IP_CT_TCP_FLAG_SACK_PERM; + uint8_t flags = IP_CT_TCP_FLAG_SACK_PERM; + + if (!CONFIG(sync).tcp_window_tracking) + flags |= IP_CT_TCP_FLAG_BE_LIBERAL; /* FIXME: workaround, we should send TCP flags in updates */ if (nfct_get_attr_u8(ct, ATTR_TCP_STATE) >= @@ -261,12 +261,12 @@ int nl_update_conntrack(struct nfct_handle *h, nfct_attr_unset(ct, ATTR_MASTER_PORT_DST); } - /* - * TCP flags to overpass window tracking for recovered connections - */ + /* disable TCP window tracking for recovered connections if required */ if (nfct_attr_is_set(ct, ATTR_TCP_STATE)) { - uint8_t flags = IP_CT_TCP_FLAG_BE_LIBERAL | - IP_CT_TCP_FLAG_SACK_PERM; + uint8_t flags = IP_CT_TCP_FLAG_SACK_PERM; + + if (!CONFIG(sync).tcp_window_tracking) + flags |= IP_CT_TCP_FLAG_BE_LIBERAL; /* FIXME: workaround, we should send TCP flags in updates */ if (nfct_get_attr_u8(ct, ATTR_TCP_STATE) >= diff --git a/src/parse.c b/src/parse.c index e6eefe4..3eb7f44 100644 --- a/src/parse.c +++ b/src/parse.c @@ -161,6 +161,16 @@ static struct parser h[NTA_MAX] = { .attr = ATTR_ICMP_ID, .size = NTA_SIZE(sizeof(uint16_t)), }, + [NTA_TCP_WSCALE_ORIG] = { + .parse = parse_u8, + .attr = ATTR_TCP_WSCALE_ORIG, + .size = NTA_SIZE(sizeof(uint8_t)), + }, + [NTA_TCP_WSCALE_REPL] = { + .parse = parse_u8, + .attr = ATTR_TCP_WSCALE_REPL, + .size = NTA_SIZE(sizeof(uint8_t)), + }, }; static void diff --git a/src/read_config_lex.l b/src/read_config_lex.l index b2d4bdb..f005099 100644 --- a/src/read_config_lex.l +++ b/src/read_config_lex.l @@ -138,6 +138,8 @@ notrack [N|n][O|o][T|t][R|r][A|a][C|c][K|k] "NetlinkEventsReliable" { return T_NETLINK_EVENTS_RELIABLE; } "DisableInternalCache" { return T_DISABLE_INTERNAL_CACHE; } "DisableExternalCache" { return T_DISABLE_EXTERNAL_CACHE; } +"Options" { return T_OPTIONS; } +"TCPWindowTracking" { return T_TCP_WINDOW_TRACKING; } "ErrorQueueLength" { return T_ERROR_QUEUE_LENGTH; } {is_on} { return T_ON; } diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 5f4e6be..bc76e92 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -73,6 +73,7 @@ static void __max_dedicated_links_reached(void); %token T_NETLINK_OVERRUN_RESYNC T_NICE T_IPV4_DEST_ADDR T_IPV6_DEST_ADDR %token T_SCHEDULER T_TYPE T_PRIO T_NETLINK_EVENTS_RELIABLE %token T_DISABLE_INTERNAL_CACHE T_DISABLE_EXTERNAL_CACHE T_ERROR_QUEUE_LENGTH +%token T_OPTIONS T_TCP_WINDOW_TRACKING %token T_IP T_PATH_VAL %token T_NUMBER @@ -808,8 +809,25 @@ sync_line: refreshtime | state_replication | cache_writethrough | destroy_timeout + | option_line ; +option_line: T_OPTIONS '{' options '}'; + +options: + | options option + ; + +option: T_TCP_WINDOW_TRACKING T_ON +{ + CONFIG(sync).tcp_window_tracking = 1; +}; + +option: T_TCP_WINDOW_TRACKING T_OFF +{ + CONFIG(sync).tcp_window_tracking = 0; +}; + sync_mode_alarm: T_SYNC_MODE T_ALARM '{' sync_mode_alarm_list '}' { conf.flags |= CTD_SYNC_ALARM; -- cgit v1.2.3 From 8c88b695289c1f3fca604a30e3ca59dd1c957377 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 31 Jan 2010 16:50:48 +0100 Subject: conntrackd: cleanup port addition in the message building path This patch move the ports addition to the layer 4 functions, instead of checking for the port attribute. It also add a function for UDP otherwise we break support for this protocol. Signed-off-by: Pablo Neira Ayuso --- src/build.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/build.c b/src/build.c index 0bfe8c1..a73476a 100644 --- a/src/build.c +++ b/src/build.c @@ -99,6 +99,9 @@ static enum nf_conntrack_attr nat_type[] = static void build_l4proto_tcp(const struct nf_conntrack *ct, struct nethdr *n) { + __build_group(ct, ATTR_GRP_ORIG_PORT, n, NTA_PORT, + sizeof(struct nfct_attr_grp_port)); + if (!nfct_attr_is_set(ct, ATTR_TCP_STATE)) return; @@ -111,6 +114,9 @@ static void build_l4proto_tcp(const struct nf_conntrack *ct, struct nethdr *n) static void build_l4proto_sctp(const struct nf_conntrack *ct, struct nethdr *n) { + __build_group(ct, ATTR_GRP_ORIG_PORT, n, NTA_PORT, + sizeof(struct nfct_attr_grp_port)); + if (!nfct_attr_is_set(ct, ATTR_SCTP_STATE)) return; @@ -121,6 +127,9 @@ static void build_l4proto_sctp(const struct nf_conntrack *ct, struct nethdr *n) static void build_l4proto_dccp(const struct nf_conntrack *ct, struct nethdr *n) { + __build_group(ct, ATTR_GRP_ORIG_PORT, n, NTA_PORT, + sizeof(struct nfct_attr_grp_port)); + if (!nfct_attr_is_set(ct, ATTR_DCCP_STATE)) return; @@ -135,6 +144,12 @@ static void build_l4proto_icmp(const struct nf_conntrack *ct, struct nethdr *n) __build_u16(ct, ATTR_ICMP_ID, n, NTA_ICMP_ID); } +static void build_l4proto_udp(const struct nf_conntrack *ct, struct nethdr *n) +{ + __build_group(ct, ATTR_GRP_ORIG_PORT, n, NTA_PORT, + sizeof(struct nfct_attr_grp_port)); +} + #ifndef IPPROTO_DCCP #define IPPROTO_DCCP 33 #endif @@ -146,6 +161,7 @@ static struct build_l4proto { [IPPROTO_SCTP] = { .build = build_l4proto_sctp }, [IPPROTO_DCCP] = { .build = build_l4proto_dccp }, [IPPROTO_ICMP] = { .build = build_l4proto_icmp }, + [IPPROTO_UDP] = { .build = build_l4proto_udp }, }; void build_payload(const struct nf_conntrack *ct, struct nethdr *n) @@ -160,13 +176,8 @@ void build_payload(const struct nf_conntrack *ct, struct nethdr *n) sizeof(struct nfct_attr_grp_ipv6)); } - __build_u8(ct, ATTR_L4PROTO, n, NTA_L4PROTO); - if (nfct_attr_grp_is_set(ct, ATTR_GRP_ORIG_PORT)) { - __build_group(ct, ATTR_GRP_ORIG_PORT, n, NTA_PORT, - sizeof(struct nfct_attr_grp_port)); - } - __build_u32(ct, ATTR_STATUS, n, NTA_STATUS); + __build_u8(ct, ATTR_L4PROTO, n, NTA_L4PROTO); if (l4proto_fcn[l4proto].build) l4proto_fcn[l4proto].build(ct, n); -- cgit v1.2.3 From 13c612efc51cf5f8d58423c59323df13739315d6 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 17 Feb 2010 00:39:44 +0100 Subject: conntrackd: fix `conntrackd -c' if external cache is disabled This patch fixes a hung that occurs if you invoke `conntrackd -c' and you have disabled the external cache. Note that `conntrackd -c' does nothing since there is no entries in the external cache to be committed. Signed-off-by: Pablo Neira Ayuso --- include/external.h | 2 +- src/external_cache.c | 4 +++- src/external_inject.c | 4 +++- src/sync-mode.c | 4 +--- 4 files changed, 8 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/include/external.h b/include/external.h index 938941a..6619967 100644 --- a/include/external.h +++ b/include/external.h @@ -13,7 +13,7 @@ struct external_handler { void (*dump)(int fd, int type); void (*flush)(void); - void (*commit)(struct nfct_handle *h, int fd); + int (*commit)(struct nfct_handle *h, int fd); void (*stats)(int fd); void (*stats_ext)(int fd); }; diff --git a/src/external_cache.c b/src/external_cache.c index c70c818..c1181dc 100644 --- a/src/external_cache.c +++ b/src/external_cache.c @@ -88,9 +88,11 @@ static void external_cache_dump(int fd, int type) cache_dump(external, fd, type); } -static void external_cache_commit(struct nfct_handle *h, int fd) +static int external_cache_commit(struct nfct_handle *h, int fd) { cache_commit(external, h, fd); + /* Keep the client socket open, we want synchronous commits. */ + return LOCAL_RET_STOLEN; } static void external_cache_flush(void) diff --git a/src/external_inject.c b/src/external_inject.c index a54bb13..56e24a3 100644 --- a/src/external_inject.c +++ b/src/external_inject.c @@ -145,8 +145,10 @@ static void external_inject_dump(int fd, int type) { } -static void external_inject_commit(struct nfct_handle *h, int fd) +static int external_inject_commit(struct nfct_handle *h, int fd) { + /* close the commit socket. */ + return LOCAL_RET_OK; } static void external_inject_flush(void) diff --git a/src/sync-mode.c b/src/sync-mode.c index ecc2f0d..c12a34a 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -497,9 +497,7 @@ static int local_handler_sync(int fd, int type, void *data) del_alarm(&STATE_SYNC(reset_cache_alarm)); dlog(LOG_NOTICE, "committing external cache"); - STATE_SYNC(external)->commit(STATE_SYNC(commit).h, fd); - /* Keep the client socket open, we want synchronous commits. */ - ret = LOCAL_RET_STOLEN; + ret = STATE_SYNC(external)->commit(STATE_SYNC(commit).h, fd); break; case RESET_TIMERS: if (!alarm_pending(&STATE_SYNC(reset_cache_alarm))) { -- cgit v1.2.3 From 58b363d32bf9b8b504c5664ae4d8b3bb1fab6ddb Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 28 Feb 2010 16:01:38 +0100 Subject: conntrackd: split __run() routine for poll and event-driven modes This patch splits the __run() routine into two functions, run_polling() and run_events() that are selected once in run-time. We save one branch in a loop that intensively executed. Signed-off-by: Pablo Neira Ayuso --- src/run.c | 176 +++++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 105 insertions(+), 71 deletions(-) (limited to 'src') diff --git a/src/run.c b/src/run.c index 803bbcc..f68dd91 100644 --- a/src/run.c +++ b/src/run.c @@ -451,7 +451,7 @@ init(void) return 0; } -static void __run(struct timeval *next_alarm) +static void run_events(struct timeval *next_alarm) { int ret; fd_set readfds = STATE(fds)->readfds; @@ -473,77 +473,102 @@ static void __run(struct timeval *next_alarm) if (FD_ISSET(STATE(local).fd, &readfds)) do_local_server_step(&STATE(local), NULL, local_handler); - if (!(CONFIG(flags) & CTD_POLL)) { - /* conntrack event has happened */ - if (FD_ISSET(nfct_fd(STATE(event)), &readfds)) { - ret = nfct_catch(STATE(event)); - /* reset event iteration limit counter */ - STATE(event_iterations_limit) = - CONFIG(event_iterations_limit); - if (ret == -1) { - switch(errno) { - case ENOBUFS: - /* We have hit ENOBUFS, it's likely that we are - * losing events. Two possible situations may - * trigger this error: - * - * 1) The netlink receiver buffer is too small: - * increasing the netlink buffer size should - * be enough. However, some event messages - * got lost. We have to resync ourselves - * with the kernel table conntrack table to - * resolve the inconsistency. - * - * 2) The receiver is too slow to process the - * netlink messages so that the queue gets - * full quickly. This generally happens - * if the system is under heavy workload - * (busy CPU). In this case, increasing the - * size of the netlink receiver buffer - * would not help anymore since we would - * be delaying the overrun. Moreover, we - * should avoid resynchronizations. We - * should do our best here and keep - * replicating as much states as possible. - * If workload lowers at some point, - * we resync ourselves. - */ - nl_resize_socket_buffer(STATE(event)); - if (CONFIG(nl_overrun_resync) > 0 && - STATE(mode)->internal->flags & - INTERNAL_F_RESYNC) { - add_alarm(&STATE(resync_alarm), - CONFIG(nl_overrun_resync),0); - } - STATE(stats).nl_catch_event_failed++; - STATE(stats).nl_overrun++; - break; - case ENOENT: - /* - * We received a message from another - * netfilter subsystem that we are not - * interested in. Just ignore it. - */ - break; - case EAGAIN: - break; - default: - STATE(stats).nl_catch_event_failed++; - break; - } + /* we have receive an event from ctnetlink */ + if (FD_ISSET(nfct_fd(STATE(event)), &readfds)) { + ret = nfct_catch(STATE(event)); + /* reset event iteration limit counter */ + STATE(event_iterations_limit) = CONFIG(event_iterations_limit); + if (ret == -1) { + switch(errno) { + case ENOBUFS: + /* We have hit ENOBUFS, it's likely that we are + * losing events. Two possible situations may + * trigger this error: + * + * 1) The netlink receiver buffer is too small: + * increasing the netlink buffer size should + * be enough. However, some event messages + * got lost. We have to resync ourselves + * with the kernel table conntrack table to + * resolve the inconsistency. + * + * 2) The receiver is too slow to process the + * netlink messages so that the queue gets + * full quickly. This generally happens + * if the system is under heavy workload + * (busy CPU). In this case, increasing the + * size of the netlink receiver buffer + * would not help anymore since we would + * be delaying the overrun. Moreover, we + * should avoid resynchronizations. We + * should do our best here and keep + * replicating as much states as possible. + * If workload lowers at some point, + * we resync ourselves. + */ + nl_resize_socket_buffer(STATE(event)); + if (CONFIG(nl_overrun_resync) > 0 && + STATE(mode)->internal->flags & INTERNAL_F_RESYNC) { + add_alarm(&STATE(resync_alarm), + CONFIG(nl_overrun_resync),0); } + STATE(stats).nl_catch_event_failed++; + STATE(stats).nl_overrun++; + break; + case ENOENT: + /* + * We received a message from another + * netfilter subsystem that we are not + * interested in. Just ignore it. + */ + break; + case EAGAIN: + /* No more events to receive, try later. */ + break; + default: + STATE(stats).nl_catch_event_failed++; + break; } - if (FD_ISSET(nfct_fd(STATE(resync)), &readfds)) { - nfct_catch(STATE(resync)); - if (STATE(mode)->internal->purge) - STATE(mode)->internal->purge(); - } - } else { - /* using polling mode */ - if (FD_ISSET(nfct_fd(STATE(resync)), &readfds)) { - nfct_catch(STATE(resync)); } } + /* we previously requested a resync due to buffer overrun. */ + if (FD_ISSET(nfct_fd(STATE(resync)), &readfds)) { + nfct_catch(STATE(resync)); + if (STATE(mode)->internal->purge) + STATE(mode)->internal->purge(); + } + + if (STATE(mode)->run) + STATE(mode)->run(&readfds); + + sigprocmask(SIG_UNBLOCK, &STATE(block), NULL); +} + +static void run_polling(struct timeval *next_alarm) +{ + int ret; + fd_set readfds = STATE(fds)->readfds; + + ret = select(STATE(fds)->maxfd + 1, &readfds, NULL, NULL, next_alarm); + if (ret == -1) { + /* interrupted syscall, retry */ + if (errno == EINTR) + return; + + STATE(stats).select_failed++; + return; + } + + /* signals are racy */ + sigprocmask(SIG_BLOCK, &STATE(block), NULL); + + /* order received via UNIX socket */ + if (FD_ISSET(STATE(local).fd, &readfds)) + do_local_server_step(&STATE(local), NULL, local_handler); + + /* we requested a dump from the kernel via polling_alarm */ + if (FD_ISSET(nfct_fd(STATE(resync)), &readfds)) + nfct_catch(STATE(resync)); if (STATE(mode)->run) STATE(mode)->run(&readfds); @@ -551,8 +576,8 @@ static void __run(struct timeval *next_alarm) sigprocmask(SIG_UNBLOCK, &STATE(block), NULL); } -void __attribute__((noreturn)) -run(void) +static void __attribute__((noreturn)) +do_run(void (*run_step)(struct timeval *next_alarm)) { struct timeval next_alarm; struct timeval *next = NULL; @@ -567,6 +592,15 @@ run(void) next = get_next_alarm_run(&next_alarm); sigprocmask(SIG_UNBLOCK, &STATE(block), NULL); - __run(next); + run_step(next); + } +} + +void run(void) +{ + if (CONFIG(flags) & CTD_POLL) { + do_run(run_polling); + } else { + do_run(run_events); } } -- cgit v1.2.3 From 0865d22af0ec5876f721d44c90ac898fdfa435aa Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 10 Jun 2010 14:12:42 +0200 Subject: conntrack: fix `-L --src-nat --dst-nat' Since > 0.9.6, the conntrack listing with the options --src-nat and --dst-nat does not work. This patch fixes the problem. Reported-by: Mohit Mehta Signed-off-by: Pablo Neira Ayuso --- src/conntrack.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index eec3868..7d413c7 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -635,27 +635,23 @@ filter_nat(const struct nf_conntrack *obj, const struct nf_conntrack *ct) uint32_t ip; if (options & CT_OPT_SRC_NAT) { - if (!nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) - return 1; - if (nfct_attr_is_set(obj, ATTR_SNAT_IPV4)) { ip = nfct_get_attr_u32(obj, ATTR_SNAT_IPV4); - if (ip != nfct_get_attr_u32(ct, ATTR_REPL_IPV4_DST)) - return 1; - } + if (ip == nfct_get_attr_u32(ct, ATTR_REPL_IPV4_DST)) + return 0; + } else if (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) + return 0; } if (options & CT_OPT_DST_NAT) { - if (!nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) - return 1; - if (nfct_attr_is_set(obj, ATTR_DNAT_IPV4)) { ip = nfct_get_attr_u32(obj, ATTR_DNAT_IPV4); - if (ip != nfct_get_attr_u32(ct, ATTR_REPL_IPV4_SRC)) - return 1; - } + if (ip == nfct_get_attr_u32(ct, ATTR_REPL_IPV4_SRC)) + return 0; + } else if (nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) + return 0; } - return 0; + return 1; } static int counter; -- cgit v1.2.3 From 09e2ff617c16e957e71b5d3b5769920d4d0aa536 Mon Sep 17 00:00:00 2001 From: Mohit Mehta Date: Tue, 15 Jun 2010 02:00:59 +0200 Subject: conntrackd: `-i -x' does not display internal cache in XML `conntrackd -i -x' does not display internal cache in XML, this patch fixes the problem. Signed-off-by: Mohit Mehta Signed-off-by: Pablo Neira Ayuso --- src/internal_cache.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/internal_cache.c b/src/internal_cache.c index daadfd6..e50e1db 100644 --- a/src/internal_cache.c +++ b/src/internal_cache.c @@ -40,7 +40,7 @@ static void _close(void) static void dump(int fd, int type) { - cache_dump(STATE(mode)->internal->data, fd, NFCT_O_PLAIN); + cache_dump(STATE(mode)->internal->data, fd, type); } static void flush(void) -- cgit v1.2.3 From d72d89846eecb156279d9c66740f8e022a126cae Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 17 Jun 2010 03:30:40 +0200 Subject: conntrack: revert fix `-L --src-nat --dst-nat' This patch reverts 0865d22af0ec5876f721d44c90ac898fdfa435aa since it breaks conntrack listing. Signed-off-by: Pablo Neira Ayuso --- src/conntrack.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index 7d413c7..eec3868 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -635,23 +635,27 @@ filter_nat(const struct nf_conntrack *obj, const struct nf_conntrack *ct) uint32_t ip; if (options & CT_OPT_SRC_NAT) { + if (!nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) + return 1; + if (nfct_attr_is_set(obj, ATTR_SNAT_IPV4)) { ip = nfct_get_attr_u32(obj, ATTR_SNAT_IPV4); - if (ip == nfct_get_attr_u32(ct, ATTR_REPL_IPV4_DST)) - return 0; - } else if (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) - return 0; + if (ip != nfct_get_attr_u32(ct, ATTR_REPL_IPV4_DST)) + return 1; + } } if (options & CT_OPT_DST_NAT) { + if (!nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) + return 1; + if (nfct_attr_is_set(obj, ATTR_DNAT_IPV4)) { ip = nfct_get_attr_u32(obj, ATTR_DNAT_IPV4); - if (ip == nfct_get_attr_u32(ct, ATTR_REPL_IPV4_SRC)) - return 0; - } else if (nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) - return 0; + if (ip != nfct_get_attr_u32(ct, ATTR_REPL_IPV4_SRC)) + return 1; + } } - return 1; + return 0; } static int counter; -- cgit v1.2.3 From 2e06d62d341fdf936dbc1fa944d5e03f761aaf0e Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 17 Jun 2010 03:38:30 +0200 Subject: conntrack: fix `conntrack -L --src-nat --dst-nat' (second try) This patch fixes the filtering with --src-nat and --dst-nat options. Signed-off-by: Pablo Neira Ayuso --- src/conntrack.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index eec3868..706fe50 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -635,27 +635,23 @@ filter_nat(const struct nf_conntrack *obj, const struct nf_conntrack *ct) uint32_t ip; if (options & CT_OPT_SRC_NAT) { - if (!nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) - return 1; - if (nfct_attr_is_set(obj, ATTR_SNAT_IPV4)) { ip = nfct_get_attr_u32(obj, ATTR_SNAT_IPV4); - if (ip != nfct_get_attr_u32(ct, ATTR_REPL_IPV4_DST)) - return 1; - } + if (ip == nfct_get_attr_u32(ct, ATTR_REPL_IPV4_DST)) + return 0; + } else if (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) + return 0; } if (options & CT_OPT_DST_NAT) { - if (!nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) - return 1; - if (nfct_attr_is_set(obj, ATTR_DNAT_IPV4)) { ip = nfct_get_attr_u32(obj, ATTR_DNAT_IPV4); - if (ip != nfct_get_attr_u32(ct, ATTR_REPL_IPV4_SRC)) - return 1; - } + if (ip == nfct_get_attr_u32(ct, ATTR_REPL_IPV4_SRC)) + return 0; + } else if (nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) + return 0; } - return 0; + return (options & (CT_OPT_SRC_NAT | CT_OPT_DST_NAT)) ? 1 : 0; } static int counter; -- cgit v1.2.3 From 85f94171a71880c744f265268f33ad58819caa74 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 17 Jun 2010 11:55:59 +0200 Subject: conntrack: `-L --src-nat --dst-nat' filter using AND, not OR logic The patch that I committed in 2e06d62d341fdf936dbc1fa944d5e03f761aaf0e was incomplete. With it, `-L --src-nat --dst-nat' shows source-natted OR destination-natted flows. This patch changes the behaviour to show source-natted AND destination-natted flows. This is the consistent behaviour that we expect from conntrack (this is how it works for other options indeed). Signed-off-by: Pablo Neira Ayuso --- src/conntrack.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index 706fe50..b8806bd 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -634,15 +634,29 @@ filter_nat(const struct nf_conntrack *obj, const struct nf_conntrack *ct) { uint32_t ip; - if (options & CT_OPT_SRC_NAT) { + if ((options & CT_OPT_SRC_NAT) && (options & CT_OPT_DST_NAT)) { + if (nfct_attr_is_set(obj, ATTR_SNAT_IPV4) && + nfct_attr_is_set(obj, ATTR_DNAT_IPV4)) { + uint32_t ip2; + + ip = nfct_get_attr_u32(obj, ATTR_SNAT_IPV4); + ip2 = nfct_get_attr_u32(obj, ATTR_DNAT_IPV4); + if (ip == nfct_get_attr_u32(ct, ATTR_REPL_IPV4_DST) && + ip2 == nfct_get_attr_u32(ct, ATTR_REPL_IPV4_SRC)) { + return 0; + } + } else if (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT) && + nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) { + return 0; + } + } else if (options & CT_OPT_SRC_NAT) { if (nfct_attr_is_set(obj, ATTR_SNAT_IPV4)) { ip = nfct_get_attr_u32(obj, ATTR_SNAT_IPV4); if (ip == nfct_get_attr_u32(ct, ATTR_REPL_IPV4_DST)) return 0; } else if (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) return 0; - } - if (options & CT_OPT_DST_NAT) { + } else if (options & CT_OPT_DST_NAT) { if (nfct_attr_is_set(obj, ATTR_DNAT_IPV4)) { ip = nfct_get_attr_u32(obj, ATTR_DNAT_IPV4); if (ip == nfct_get_attr_u32(ct, ATTR_REPL_IPV4_SRC)) -- cgit v1.2.3 From 8cc931c15b42a71ce0d28384ae03bfa8a0a06d32 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 12 Jun 2010 21:20:24 +0200 Subject: conntrackd: complete TCP window scale support In commit 56817d1c0cc30bcd65c56c2f73634b256603cc4d, I added the TCP window scale factor support but it was incomplete. We have to set the IP_CT_TCP_FLAG_WINDOW_SCALE flag to update the td_scale field via ctnetlink. Check nlattr_to_tcp(...) function in nf_conntrack_proto_tcp.c for more details. Signed-off-by: Pablo Neira Ayuso --- src/netlink.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/netlink.c b/src/netlink.c index 5b6452a..05a54bd 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -202,6 +202,8 @@ int nl_create_conntrack(struct nfct_handle *h, if (!CONFIG(sync).tcp_window_tracking) flags |= IP_CT_TCP_FLAG_BE_LIBERAL; + else + flags |= IP_CT_TCP_FLAG_WINDOW_SCALE; /* FIXME: workaround, we should send TCP flags in updates */ if (nfct_get_attr_u8(ct, ATTR_TCP_STATE) >= @@ -267,6 +269,8 @@ int nl_update_conntrack(struct nfct_handle *h, if (!CONFIG(sync).tcp_window_tracking) flags |= IP_CT_TCP_FLAG_BE_LIBERAL; + else + flags |= IP_CT_TCP_FLAG_WINDOW_SCALE; /* FIXME: workaround, we should send TCP flags in updates */ if (nfct_get_attr_u8(ct, ATTR_TCP_STATE) >= -- cgit v1.2.3 From ebff9f7226ec4077e88253991edf5e1260b98144 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 28 Feb 2010 18:21:09 +0100 Subject: conntrack: expand array that maps option-flags to option-names This patch is a cleanup, it expands an array that contains the correspondence between the option-flags and the option-names. Signed-off-by: Pablo Neira Ayuso --- src/conntrack.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index b8806bd..8006a60 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -59,9 +59,29 @@ #include static const char *optflags[NUMBER_OF_OPT] = { -"src","dst","reply-src","reply-dst","protonum","timeout","status","zero", -"event-mask","tuple-src","tuple-dst","mask-src","mask-dst","nat-range","mark", -"id","family","src-nat","dst-nat","output","secmark","buffersize"}; + [CT_OPT_ORIG_SRC_BIT] = "src", + [CT_OPT_ORIG_DST_BIT] = "dst", + [CT_OPT_REPL_SRC_BIT] = "reply-src", + [CT_OPT_REPL_DST_BIT] = "reply-dst", + [CT_OPT_PROTO_BIT] = "protonum", + [CT_OPT_TIMEOUT_BIT] = "timeout", + [CT_OPT_STATUS_BIT] = "status", + [CT_OPT_ZERO_BIT] = "zero", + [CT_OPT_EVENT_MASK_BIT] = "event-mask", + [CT_OPT_EXP_SRC_BIT] = "tuple-src", + [CT_OPT_EXP_DST_BIT] = "tuple-dst", + [CT_OPT_MASK_SRC_BIT] = "mask-src", + [CT_OPT_MASK_DST_BIT] = "mask-dst", + [CT_OPT_NATRANGE_BIT] = "nat-range", + [CT_OPT_MARK_BIT] = "mark", + [CT_OPT_ID_BIT] = "id", + [CT_OPT_FAMILY_BIT] = "family", + [CT_OPT_SRC_NAT_BIT] = "src-nat", + [CT_OPT_DST_NAT_BIT] = "dst-nat", + [CT_OPT_OUTPUT_BIT] = "output", + [CT_OPT_SECMARK_BIT] = "secmark", + [CT_OPT_BUFFERSIZE_BIT] = "buffer-size" +}; static struct option original_opts[] = { {"dump", 2, 0, 'L'}, -- cgit v1.2.3 From 0ca9676dd9e9bdd9382954d42e39c8bdd212f966 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 28 Feb 2010 18:12:57 +0100 Subject: conntrack: put all the commands and options code together This patch is a cleanup, it puts all the commands and options code together. This makes easier and less error-prone the task to add new commands and options. Signed-off-by: Pablo Neira Ayuso --- include/conntrack.h | 143 +------------------- src/conntrack.c | 383 ++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 264 insertions(+), 262 deletions(-) (limited to 'src') diff --git a/include/conntrack.h b/include/conntrack.h index 61e7581..d8112aa 100644 --- a/include/conntrack.h +++ b/include/conntrack.h @@ -9,149 +9,8 @@ #include -enum action { - CT_NONE = 0, - - CT_LIST_BIT = 0, - CT_LIST = (1 << CT_LIST_BIT), - - CT_CREATE_BIT = 1, - CT_CREATE = (1 << CT_CREATE_BIT), - - CT_UPDATE_BIT = 2, - CT_UPDATE = (1 << CT_UPDATE_BIT), - - CT_DELETE_BIT = 3, - CT_DELETE = (1 << CT_DELETE_BIT), - - CT_GET_BIT = 4, - CT_GET = (1 << CT_GET_BIT), - - CT_FLUSH_BIT = 5, - CT_FLUSH = (1 << CT_FLUSH_BIT), - - CT_EVENT_BIT = 6, - CT_EVENT = (1 << CT_EVENT_BIT), - - CT_VERSION_BIT = 7, - CT_VERSION = (1 << CT_VERSION_BIT), - - CT_HELP_BIT = 8, - CT_HELP = (1 << CT_HELP_BIT), - - EXP_LIST_BIT = 9, - EXP_LIST = (1 << EXP_LIST_BIT), - - EXP_CREATE_BIT = 10, - EXP_CREATE = (1 << EXP_CREATE_BIT), - - EXP_DELETE_BIT = 11, - EXP_DELETE = (1 << EXP_DELETE_BIT), - - EXP_GET_BIT = 12, - EXP_GET = (1 << EXP_GET_BIT), - - EXP_FLUSH_BIT = 13, - EXP_FLUSH = (1 << EXP_FLUSH_BIT), - - EXP_EVENT_BIT = 14, - EXP_EVENT = (1 << EXP_EVENT_BIT), - - CT_COUNT_BIT = 15, - CT_COUNT = (1 << CT_COUNT_BIT), - - EXP_COUNT_BIT = 16, - EXP_COUNT = (1 << EXP_COUNT_BIT), - - X_STATS_BIT = 17, - X_STATS = (1 << X_STATS_BIT), -}; #define NUMBER_OF_CMD 18 - -enum options { - CT_OPT_ORIG_SRC_BIT = 0, - CT_OPT_ORIG_SRC = (1 << CT_OPT_ORIG_SRC_BIT), - - CT_OPT_ORIG_DST_BIT = 1, - CT_OPT_ORIG_DST = (1 << CT_OPT_ORIG_DST_BIT), - - CT_OPT_ORIG = (CT_OPT_ORIG_SRC | CT_OPT_ORIG_DST), - - CT_OPT_REPL_SRC_BIT = 2, - CT_OPT_REPL_SRC = (1 << CT_OPT_REPL_SRC_BIT), - - CT_OPT_REPL_DST_BIT = 3, - CT_OPT_REPL_DST = (1 << CT_OPT_REPL_DST_BIT), - - CT_OPT_REPL = (CT_OPT_REPL_SRC | CT_OPT_REPL_DST), - - CT_OPT_PROTO_BIT = 4, - CT_OPT_PROTO = (1 << CT_OPT_PROTO_BIT), - - CT_OPT_TUPLE_ORIG = (CT_OPT_ORIG | CT_OPT_PROTO), - CT_OPT_TUPLE_REPL = (CT_OPT_REPL | CT_OPT_PROTO), - - CT_OPT_TIMEOUT_BIT = 5, - CT_OPT_TIMEOUT = (1 << CT_OPT_TIMEOUT_BIT), - - CT_OPT_STATUS_BIT = 6, - CT_OPT_STATUS = (1 << CT_OPT_STATUS_BIT), - - CT_OPT_ZERO_BIT = 7, - CT_OPT_ZERO = (1 << CT_OPT_ZERO_BIT), - - CT_OPT_EVENT_MASK_BIT = 8, - CT_OPT_EVENT_MASK = (1 << CT_OPT_EVENT_MASK_BIT), - - CT_OPT_EXP_SRC_BIT = 9, - CT_OPT_EXP_SRC = (1 << CT_OPT_EXP_SRC_BIT), - - CT_OPT_EXP_DST_BIT = 10, - CT_OPT_EXP_DST = (1 << CT_OPT_EXP_DST_BIT), - - CT_OPT_MASK_SRC_BIT = 11, - CT_OPT_MASK_SRC = (1 << CT_OPT_MASK_SRC_BIT), - - CT_OPT_MASK_DST_BIT = 12, - CT_OPT_MASK_DST = (1 << CT_OPT_MASK_DST_BIT), - - CT_OPT_NATRANGE_BIT = 13, - CT_OPT_NATRANGE = (1 << CT_OPT_NATRANGE_BIT), - - CT_OPT_MARK_BIT = 14, - CT_OPT_MARK = (1 << CT_OPT_MARK_BIT), - - CT_OPT_ID_BIT = 15, - CT_OPT_ID = (1 << CT_OPT_ID_BIT), - - CT_OPT_FAMILY_BIT = 16, - CT_OPT_FAMILY = (1 << CT_OPT_FAMILY_BIT), - - CT_OPT_SRC_NAT_BIT = 17, - CT_OPT_SRC_NAT = (1 << CT_OPT_SRC_NAT_BIT), - - CT_OPT_DST_NAT_BIT = 18, - CT_OPT_DST_NAT = (1 << CT_OPT_DST_NAT_BIT), - - CT_OPT_OUTPUT_BIT = 19, - CT_OPT_OUTPUT = (1 << CT_OPT_OUTPUT_BIT), - - CT_OPT_SECMARK_BIT = 20, - CT_OPT_SECMARK = (1 << CT_OPT_SECMARK_BIT), - - CT_OPT_BUFFERSIZE_BIT = 21, - CT_OPT_BUFFERSIZE = (1 << CT_OPT_BUFFERSIZE_BIT), - - CT_OPT_MAX = CT_OPT_BUFFERSIZE_BIT -}; -#define NUMBER_OF_OPT CT_OPT_MAX+1 - -enum { - _O_XML = (1 << 0), - _O_EXT = (1 << 1), - _O_TMS = (1 << 2), - _O_ID = (1 << 3), -}; +#define NUMBER_OF_OPT 22 struct ctproto_handler { struct list_head head; diff --git a/src/conntrack.c b/src/conntrack.c index 8006a60..99aed0f 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -58,6 +58,145 @@ #include #include +enum ct_command { + CT_NONE = 0, + + CT_LIST_BIT = 0, + CT_LIST = (1 << CT_LIST_BIT), + + CT_CREATE_BIT = 1, + CT_CREATE = (1 << CT_CREATE_BIT), + + CT_UPDATE_BIT = 2, + CT_UPDATE = (1 << CT_UPDATE_BIT), + + CT_DELETE_BIT = 3, + CT_DELETE = (1 << CT_DELETE_BIT), + + CT_GET_BIT = 4, + CT_GET = (1 << CT_GET_BIT), + + CT_FLUSH_BIT = 5, + CT_FLUSH = (1 << CT_FLUSH_BIT), + + CT_EVENT_BIT = 6, + CT_EVENT = (1 << CT_EVENT_BIT), + + CT_VERSION_BIT = 7, + CT_VERSION = (1 << CT_VERSION_BIT), + + CT_HELP_BIT = 8, + CT_HELP = (1 << CT_HELP_BIT), + + EXP_LIST_BIT = 9, + EXP_LIST = (1 << EXP_LIST_BIT), + + EXP_CREATE_BIT = 10, + EXP_CREATE = (1 << EXP_CREATE_BIT), + + EXP_DELETE_BIT = 11, + EXP_DELETE = (1 << EXP_DELETE_BIT), + + EXP_GET_BIT = 12, + EXP_GET = (1 << EXP_GET_BIT), + + EXP_FLUSH_BIT = 13, + EXP_FLUSH = (1 << EXP_FLUSH_BIT), + + EXP_EVENT_BIT = 14, + EXP_EVENT = (1 << EXP_EVENT_BIT), + + CT_COUNT_BIT = 15, + CT_COUNT = (1 << CT_COUNT_BIT), + + EXP_COUNT_BIT = 16, + EXP_COUNT = (1 << EXP_COUNT_BIT), + + X_STATS_BIT = 17, + X_STATS = (1 << X_STATS_BIT), +}; +/* If you add a new command, you have to update NUMBER_OF_CMD in conntrack.h */ + +enum ct_options { + CT_OPT_ORIG_SRC_BIT = 0, + CT_OPT_ORIG_SRC = (1 << CT_OPT_ORIG_SRC_BIT), + + CT_OPT_ORIG_DST_BIT = 1, + CT_OPT_ORIG_DST = (1 << CT_OPT_ORIG_DST_BIT), + + CT_OPT_ORIG = (CT_OPT_ORIG_SRC | CT_OPT_ORIG_DST), + + CT_OPT_REPL_SRC_BIT = 2, + CT_OPT_REPL_SRC = (1 << CT_OPT_REPL_SRC_BIT), + + CT_OPT_REPL_DST_BIT = 3, + CT_OPT_REPL_DST = (1 << CT_OPT_REPL_DST_BIT), + + CT_OPT_REPL = (CT_OPT_REPL_SRC | CT_OPT_REPL_DST), + + CT_OPT_PROTO_BIT = 4, + CT_OPT_PROTO = (1 << CT_OPT_PROTO_BIT), + + CT_OPT_TUPLE_ORIG = (CT_OPT_ORIG | CT_OPT_PROTO), + CT_OPT_TUPLE_REPL = (CT_OPT_REPL | CT_OPT_PROTO), + + CT_OPT_TIMEOUT_BIT = 5, + CT_OPT_TIMEOUT = (1 << CT_OPT_TIMEOUT_BIT), + + CT_OPT_STATUS_BIT = 6, + CT_OPT_STATUS = (1 << CT_OPT_STATUS_BIT), + + CT_OPT_ZERO_BIT = 7, + CT_OPT_ZERO = (1 << CT_OPT_ZERO_BIT), + + CT_OPT_EVENT_MASK_BIT = 8, + CT_OPT_EVENT_MASK = (1 << CT_OPT_EVENT_MASK_BIT), + + CT_OPT_EXP_SRC_BIT = 9, + CT_OPT_EXP_SRC = (1 << CT_OPT_EXP_SRC_BIT), + + CT_OPT_EXP_DST_BIT = 10, + CT_OPT_EXP_DST = (1 << CT_OPT_EXP_DST_BIT), + + CT_OPT_MASK_SRC_BIT = 11, + CT_OPT_MASK_SRC = (1 << CT_OPT_MASK_SRC_BIT), + + CT_OPT_MASK_DST_BIT = 12, + CT_OPT_MASK_DST = (1 << CT_OPT_MASK_DST_BIT), + + CT_OPT_NATRANGE_BIT = 13, + CT_OPT_NATRANGE = (1 << CT_OPT_NATRANGE_BIT), + + CT_OPT_MARK_BIT = 14, + CT_OPT_MARK = (1 << CT_OPT_MARK_BIT), + + CT_OPT_ID_BIT = 15, + CT_OPT_ID = (1 << CT_OPT_ID_BIT), + + CT_OPT_FAMILY_BIT = 16, + CT_OPT_FAMILY = (1 << CT_OPT_FAMILY_BIT), + + CT_OPT_SRC_NAT_BIT = 17, + CT_OPT_SRC_NAT = (1 << CT_OPT_SRC_NAT_BIT), + + CT_OPT_DST_NAT_BIT = 18, + CT_OPT_DST_NAT = (1 << CT_OPT_DST_NAT_BIT), + + CT_OPT_OUTPUT_BIT = 19, + CT_OPT_OUTPUT = (1 << CT_OPT_OUTPUT_BIT), + + CT_OPT_SECMARK_BIT = 20, + CT_OPT_SECMARK = (1 << CT_OPT_SECMARK_BIT), + + CT_OPT_BUFFERSIZE_BIT = 21, + CT_OPT_BUFFERSIZE = (1 << CT_OPT_BUFFERSIZE_BIT), +}; +/* If you add a new option, you have to update NUMBER_OF_OPT in conntrack.h */ + +/* Update this mask to allow to filter based on new options. */ +#define CT_COMPARISON (CT_OPT_PROTO | CT_OPT_ORIG | CT_OPT_REPL | CT_OPT_MARK |\ + CT_OPT_SECMARK | CT_OPT_STATUS | CT_OPT_ID) + static const char *optflags[NUMBER_OF_OPT] = { [CT_OPT_ORIG_SRC_BIT] = "src", [CT_OPT_ORIG_DST_BIT] = "dst", @@ -122,11 +261,9 @@ static struct option original_opts[] = { {0, 0, 0, 0} }; -#define OPTION_OFFSET 256 - -static struct nfct_handle *cth, *ith; -static struct option *opts = original_opts; -static unsigned int global_option_offset = 0; +static const char *getopt_str = "L::I::U::D::G::E::F::hVs:d:r:q:" + "p:t:u:e:a:z[:]:{:}:m:i:f:o:n::" + "g::c:b:C::S"; /* Table of legal combinations of commands and options. If any of the * given commands make an option legal, that option is legal (applies to @@ -162,6 +299,117 @@ static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = /*X_STATS*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, }; +static const int cmd2type[][2] = { + ['L'] = { CT_LIST, EXP_LIST }, + ['I'] = { CT_CREATE, EXP_CREATE }, + ['D'] = { CT_DELETE, EXP_DELETE }, + ['G'] = { CT_GET, EXP_GET }, + ['F'] = { CT_FLUSH, EXP_FLUSH }, + ['E'] = { CT_EVENT, EXP_EVENT }, + ['V'] = { CT_VERSION, CT_VERSION }, + ['h'] = { CT_HELP, CT_HELP }, + ['C'] = { CT_COUNT, EXP_COUNT }, +}; + +static const int opt2type[] = { + ['s'] = CT_OPT_ORIG_SRC, + ['d'] = CT_OPT_ORIG_DST, + ['r'] = CT_OPT_REPL_SRC, + ['q'] = CT_OPT_REPL_DST, + ['{'] = CT_OPT_MASK_SRC, + ['}'] = CT_OPT_MASK_DST, + ['['] = CT_OPT_EXP_SRC, + [']'] = CT_OPT_EXP_DST, + ['n'] = CT_OPT_SRC_NAT, + ['g'] = CT_OPT_DST_NAT, + ['m'] = CT_OPT_MARK, + ['c'] = CT_OPT_SECMARK, + ['i'] = CT_OPT_ID, +}; + +static const int opt2family_attr[][2] = { + ['s'] = { ATTR_ORIG_IPV4_SRC, ATTR_ORIG_IPV6_SRC }, + ['d'] = { ATTR_ORIG_IPV4_DST, ATTR_ORIG_IPV6_DST }, + ['r'] = { ATTR_REPL_IPV4_SRC, ATTR_REPL_IPV6_SRC }, + ['q'] = { ATTR_REPL_IPV4_DST, ATTR_REPL_IPV6_DST }, + ['{'] = { ATTR_ORIG_IPV4_SRC, ATTR_ORIG_IPV6_SRC }, + ['}'] = { ATTR_ORIG_IPV4_DST, ATTR_ORIG_IPV6_DST }, + ['['] = { ATTR_ORIG_IPV4_SRC, ATTR_ORIG_IPV6_SRC }, + [']'] = { ATTR_ORIG_IPV4_DST, ATTR_ORIG_IPV6_DST }, +}; + +static const int opt2attr[] = { + ['s'] = ATTR_ORIG_L3PROTO, + ['d'] = ATTR_ORIG_L3PROTO, + ['r'] = ATTR_REPL_L3PROTO, + ['q'] = ATTR_REPL_L3PROTO, + ['m'] = ATTR_MARK, + ['c'] = ATTR_SECMARK, + ['i'] = ATTR_ID, +}; + +static char exit_msg[NUMBER_OF_CMD][64] = { + [CT_LIST_BIT] = "%d flow entries have been shown.\n", + [CT_CREATE_BIT] = "%d flow entries have been created.\n", + [CT_UPDATE_BIT] = "%d flow entries have been updated.\n", + [CT_DELETE_BIT] = "%d flow entries have been deleted.\n", + [CT_GET_BIT] = "%d flow entries have been shown.\n", + [CT_EVENT_BIT] = "%d flow events have been shown.\n", + [EXP_LIST_BIT] = "%d expectations have been shown.\n", + [EXP_DELETE_BIT] = "%d expectations have been shown.\n", +}; + +static const char usage_commands[] = + "Commands:\n" + " -L [table] [options]\t\tList conntrack or expectation table\n" + " -G [table] parameters\t\tGet conntrack or expectation\n" + " -D [table] parameters\t\tDelete conntrack or expectation\n" + " -I [table] parameters\t\tCreate a conntrack or expectation\n" + " -U [table] parameters\t\tUpdate a conntrack\n" + " -E [table] [options]\t\tShow events\n" + " -F [table]\t\t\tFlush table\n" + " -C [table]\t\t\tShow counter\n" + " -S\t\t\t\tShow statistics\n"; + +static const char usage_tables[] = + "Tables: conntrack, expect\n"; + +static const char usage_conntrack_parameters[] = + "Conntrack parameters and options:\n" + " -n, --src-nat ip\t\t\tsource NAT ip\n" + " -g, --dst-nat ip\t\t\tdestination NAT ip\n" + " -m, --mark mark\t\t\tSet mark\n" + " -c, --secmark secmark\t\t\tSet selinux secmark\n" + " -e, --event-mask eventmask\t\tEvent mask, eg. NEW,DESTROY\n" + " -z, --zero \t\t\t\tZero counters while listing\n" + " -o, --output type[,...]\t\tOutput format, eg. xml\n"; + +static const char usage_expectation_parameters[] = + "Expectation parameters and options:\n" + " --tuple-src ip\tSource address in expect tuple\n" + " --tuple-dst ip\tDestination address in expect tuple\n" + " --mask-src ip\t\tSource mask address\n" + " --mask-dst ip\t\tDestination mask address\n"; + +static const char usage_parameters[] = + "Common parameters and options:\n" + " -s, --orig-src ip\t\tSource address from original direction\n" + " -d, --orig-dst ip\t\tDestination address from original direction\n" + " -r, --reply-src ip\t\tSource addres from reply direction\n" + " -q, --reply-dst ip\t\tDestination address from reply direction\n" + " -p, --protonum proto\t\tLayer 4 Protocol, eg. 'tcp'\n" + " -f, --family proto\t\tLayer 3 Protocol, eg. 'ipv6'\n" + " -t, --timeout timeout\t\tSet timeout\n" + " -u, --status status\t\tSet status, eg. ASSURED\n" + " -b, --buffer-size\t\tNetlink socket buffer size\n" + ; + +#define OPTION_OFFSET 256 + +static struct nfct_handle *cth, *ith; +static struct option *opts = original_opts; +static unsigned int global_option_offset = 0; + #define ADDR_VALID_FLAGS_MAX 2 static unsigned int addr_valid_flags[ADDR_VALID_FLAGS_MAX] = { CT_OPT_ORIG_SRC | CT_OPT_ORIG_DST, @@ -172,9 +420,6 @@ static LIST_HEAD(proto_list); static unsigned int options; -#define CT_COMPARISON (CT_OPT_PROTO | CT_OPT_ORIG | CT_OPT_REPL | CT_OPT_MARK |\ - CT_OPT_SECMARK | CT_OPT_STATUS | CT_OPT_ID) - void register_proto(struct ctproto_handler *h) { if (strcmp(h->version, VERSION) != 0) { @@ -368,11 +613,11 @@ merge_options(struct option *oldopts, const struct option *newopts, /* Translates errno numbers into more human-readable form than strerror. */ static const char * -err2str(int err, enum action command) +err2str(int err, enum ct_command command) { unsigned int i; struct table_struct { - enum action act; + enum ct_command act; int err; const char *message; } table [] = @@ -403,6 +648,13 @@ err2str(int err, enum action command) #define PARSE_OUTPUT 2 #define PARSE_MAX 3 +enum { + _O_XML = (1 << 0), + _O_EXT = (1 << 1), + _O_TMS = (1 << 2), + _O_ID = (1 << 3), +}; + static struct parse_parameter { const char *parameter[6]; size_t size; @@ -587,52 +839,6 @@ nat_parse(char *arg, int portok, struct nf_conntrack *obj, int type) nfct_set_attr_u32(obj, ATTR_DNAT_IPV4, parse.v4); } -static const char usage_commands[] = - "Commands:\n" - " -L [table] [options]\t\tList conntrack or expectation table\n" - " -G [table] parameters\t\tGet conntrack or expectation\n" - " -D [table] parameters\t\tDelete conntrack or expectation\n" - " -I [table] parameters\t\tCreate a conntrack or expectation\n" - " -U [table] parameters\t\tUpdate a conntrack\n" - " -E [table] [options]\t\tShow events\n" - " -F [table]\t\t\tFlush table\n" - " -C [table]\t\t\tShow counter\n" - " -S\t\t\t\tShow statistics\n"; - -static const char usage_tables[] = - "Tables: conntrack, expect\n"; - -static const char usage_conntrack_parameters[] = - "Conntrack parameters and options:\n" - " -n, --src-nat ip\t\t\tsource NAT ip\n" - " -g, --dst-nat ip\t\t\tdestination NAT ip\n" - " -m, --mark mark\t\t\tSet mark\n" - " -c, --secmark secmark\t\t\tSet selinux secmark\n" - " -e, --event-mask eventmask\t\tEvent mask, eg. NEW,DESTROY\n" - " -z, --zero \t\t\t\tZero counters while listing\n" - " -o, --output type[,...]\t\tOutput format, eg. xml\n"; - -static const char usage_expectation_parameters[] = - "Expectation parameters and options:\n" - " --tuple-src ip\tSource address in expect tuple\n" - " --tuple-dst ip\tDestination address in expect tuple\n" - " --mask-src ip\t\tSource mask address\n" - " --mask-dst ip\t\tDestination mask address\n"; - -static const char usage_parameters[] = - "Common parameters and options:\n" - " -s, --orig-src ip\t\tSource address from original direction\n" - " -d, --orig-dst ip\t\tDestination address from original direction\n" - " -r, --reply-src ip\t\tSource addres from reply direction\n" - " -q, --reply-dst ip\t\tDestination address from reply direction\n" - " -p, --protonum proto\t\tLayer 4 Protocol, eg. 'tcp'\n" - " -f, --family proto\t\tLayer 3 Protocol, eg. 'ipv6'\n" - " -t, --timeout timeout\t\tSet timeout\n" - " -u, --status status\t\tSet status, eg. ASSURED\n" - " -b, --buffer-size\t\tNetlink socket buffer size\n" - ; - - static void usage(char *prog) { @@ -994,66 +1200,6 @@ out_err: static struct ctproto_handler *h; -static const int cmd2type[][2] = { - ['L'] = { CT_LIST, EXP_LIST }, - ['I'] = { CT_CREATE, EXP_CREATE }, - ['D'] = { CT_DELETE, EXP_DELETE }, - ['G'] = { CT_GET, EXP_GET }, - ['F'] = { CT_FLUSH, EXP_FLUSH }, - ['E'] = { CT_EVENT, EXP_EVENT }, - ['V'] = { CT_VERSION, CT_VERSION }, - ['h'] = { CT_HELP, CT_HELP }, - ['C'] = { CT_COUNT, EXP_COUNT }, -}; - -static const int opt2type[] = { - ['s'] = CT_OPT_ORIG_SRC, - ['d'] = CT_OPT_ORIG_DST, - ['r'] = CT_OPT_REPL_SRC, - ['q'] = CT_OPT_REPL_DST, - ['{'] = CT_OPT_MASK_SRC, - ['}'] = CT_OPT_MASK_DST, - ['['] = CT_OPT_EXP_SRC, - [']'] = CT_OPT_EXP_DST, - ['n'] = CT_OPT_SRC_NAT, - ['g'] = CT_OPT_DST_NAT, - ['m'] = CT_OPT_MARK, - ['c'] = CT_OPT_SECMARK, - ['i'] = CT_OPT_ID, -}; - -static const int opt2family_attr[][2] = { - ['s'] = { ATTR_ORIG_IPV4_SRC, ATTR_ORIG_IPV6_SRC }, - ['d'] = { ATTR_ORIG_IPV4_DST, ATTR_ORIG_IPV6_DST }, - ['r'] = { ATTR_REPL_IPV4_SRC, ATTR_REPL_IPV6_SRC }, - ['q'] = { ATTR_REPL_IPV4_DST, ATTR_REPL_IPV6_DST }, - ['{'] = { ATTR_ORIG_IPV4_SRC, ATTR_ORIG_IPV6_SRC }, - ['}'] = { ATTR_ORIG_IPV4_DST, ATTR_ORIG_IPV6_DST }, - ['['] = { ATTR_ORIG_IPV4_SRC, ATTR_ORIG_IPV6_SRC }, - [']'] = { ATTR_ORIG_IPV4_DST, ATTR_ORIG_IPV6_DST }, -}; - -static const int opt2attr[] = { - ['s'] = ATTR_ORIG_L3PROTO, - ['d'] = ATTR_ORIG_L3PROTO, - ['r'] = ATTR_REPL_L3PROTO, - ['q'] = ATTR_REPL_L3PROTO, - ['m'] = ATTR_MARK, - ['c'] = ATTR_SECMARK, - ['i'] = ATTR_ID, -}; - -static char exit_msg[NUMBER_OF_CMD][64] = { - [CT_LIST_BIT] = "%d flow entries have been shown.\n", - [CT_CREATE_BIT] = "%d flow entries have been created.\n", - [CT_UPDATE_BIT] = "%d flow entries have been updated.\n", - [CT_DELETE_BIT] = "%d flow entries have been deleted.\n", - [CT_GET_BIT] = "%d flow entries have been shown.\n", - [CT_EVENT_BIT] = "%d flow events have been shown.\n", - [EXP_LIST_BIT] = "%d expectations have been shown.\n", - [EXP_DELETE_BIT] = "%d expectations have been shown.\n", -}; - int main(int argc, char *argv[]) { int c, cmd; @@ -1092,10 +1238,7 @@ int main(int argc, char *argv[]) /* disable explicit missing arguments error output from getopt_long */ opterr = 0; - while ((c = getopt_long(argc, argv, "L::I::U::D::G::E::F::hVs:d:r:q:" - "p:t:u:e:a:z[:]:{:}:m:i:f:o:n::" - "g::c:b:C::S", - opts, NULL)) != -1) { + while ((c = getopt_long(argc, argv, getopt_str, opts, NULL)) != -1) { switch(c) { /* commands */ case 'L': -- cgit v1.2.3 From 142606c60808b3ab0496155ac3d086765e6baef3 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 28 Jun 2010 12:47:16 +0200 Subject: conntrack: fix port filter with `--src-nat' and `--dst-nat' This patch allows the following command to filter port-based NAT: $ conntrack -L --dst-nat :9999 Signed-off-by: Pablo Neira Ayuso --- src/conntrack.c | 70 ++++++++++++++++++++++++++++++++------------------------- 1 file changed, 39 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index 99aed0f..611b179 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -775,8 +775,7 @@ parse_inetaddr(const char *cp, struct addr_parse *parse) else if (inet_pton(AF_INET6, cp, &parse->addr6) > 0) return AF_INET6; #endif - - exit_error(PARAMETER_PROBLEM, "Invalid IP address `%s'", cp); + return AF_UNSPEC; } union ct_address { @@ -825,12 +824,12 @@ nat_parse(char *arg, int portok, struct nf_conntrack *obj, int type) "Invalid port:port syntax"); if (type == CT_OPT_SRC_NAT) - nfct_set_attr_u16(obj, ATTR_SNAT_PORT, port); + nfct_set_attr_u16(obj, ATTR_SNAT_PORT, ntohs(port)); else if (type == CT_OPT_DST_NAT) - nfct_set_attr_u16(obj, ATTR_DNAT_PORT, port); + nfct_set_attr_u16(obj, ATTR_DNAT_PORT, ntohs(port)); } - if (parse_addr(arg, &parse) != AF_INET) + if (parse_addr(arg, &parse) == AF_UNSPEC) return; if (type == CT_OPT_SRC_NAT) @@ -859,39 +858,40 @@ static int filter_nat(const struct nf_conntrack *obj, const struct nf_conntrack *ct) { uint32_t ip; + uint16_t port; - if ((options & CT_OPT_SRC_NAT) && (options & CT_OPT_DST_NAT)) { - if (nfct_attr_is_set(obj, ATTR_SNAT_IPV4) && - nfct_attr_is_set(obj, ATTR_DNAT_IPV4)) { - uint32_t ip2; - - ip = nfct_get_attr_u32(obj, ATTR_SNAT_IPV4); - ip2 = nfct_get_attr_u32(obj, ATTR_DNAT_IPV4); - if (ip == nfct_get_attr_u32(ct, ATTR_REPL_IPV4_DST) && - ip2 == nfct_get_attr_u32(ct, ATTR_REPL_IPV4_SRC)) { - return 0; - } - } else if (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT) && - nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) { - return 0; - } - } else if (options & CT_OPT_SRC_NAT) { + if (options & CT_OPT_SRC_NAT) { if (nfct_attr_is_set(obj, ATTR_SNAT_IPV4)) { ip = nfct_get_attr_u32(obj, ATTR_SNAT_IPV4); - if (ip == nfct_get_attr_u32(ct, ATTR_REPL_IPV4_DST)) - return 0; - } else if (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) - return 0; - } else if (options & CT_OPT_DST_NAT) { + if (ip != nfct_get_attr_u32(ct, ATTR_REPL_IPV4_DST)) + return 1; + } + if (nfct_attr_is_set(obj, ATTR_SNAT_PORT)) { + port = nfct_get_attr_u16(obj, ATTR_SNAT_PORT); + if (port != nfct_get_attr_u16(ct, ATTR_REPL_PORT_DST)) + return 1; + } + if (!nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT) && + !nfct_getobjopt(ct, NFCT_GOPT_IS_SPAT)) + return 1; + } + if (options & CT_OPT_DST_NAT) { if (nfct_attr_is_set(obj, ATTR_DNAT_IPV4)) { ip = nfct_get_attr_u32(obj, ATTR_DNAT_IPV4); - if (ip == nfct_get_attr_u32(ct, ATTR_REPL_IPV4_SRC)) - return 0; - } else if (nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) - return 0; + if (ip != nfct_get_attr_u32(ct, ATTR_REPL_IPV4_SRC)) + return 1; + } + if (nfct_attr_is_set(obj, ATTR_DNAT_PORT)) { + port = nfct_get_attr_u16(obj, ATTR_DNAT_PORT); + if (port != nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC)) + return 1; + } + if (!nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT) && + !nfct_getobjopt(ct, NFCT_GOPT_IS_DPAT)) + return 1; } - return (options & (CT_OPT_SRC_NAT | CT_OPT_DST_NAT)) ? 1 : 0; + return 0; } static int counter; @@ -1272,6 +1272,10 @@ int main(int argc, char *argv[]) options |= opt2type[c]; l3protonum = parse_addr(optarg, &ad); + if (l3protonum == AF_UNSPEC) { + exit_error(PARAMETER_PROBLEM, + "Invalid IP address `%s'", optarg); + } set_family(&family, l3protonum); if (l3protonum == AF_INET) { nfct_set_attr_u32(obj, @@ -1290,6 +1294,10 @@ int main(int argc, char *argv[]) case ']': options |= opt2type[c]; l3protonum = parse_addr(optarg, &ad); + if (l3protonum == AF_UNSPEC) { + exit_error(PARAMETER_PROBLEM, + "Invalid IP address `%s'", optarg); + } set_family(&family, l3protonum); if (l3protonum == AF_INET) { nfct_set_attr_u32(mask, -- cgit v1.2.3 From ad33006a162fc6202de096a8f6d65a7c841da1ce Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 22 Jun 2010 11:52:27 +0200 Subject: conntrack: add `--any-nat' to filter any NATted flow This patch adds the --any-nat option that allows to display src-NATted OR dst-NATted flows. Signed-off-by: Pablo Neira Ayuso --- conntrack.8 | 3 ++ include/conntrack.h | 2 +- src/conntrack.c | 92 ++++++++++++++++++++++++++++++++++++++++------------- 3 files changed, 74 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/conntrack.8 b/conntrack.8 index 9b4d14b..fee3a8c 100644 --- a/conntrack.8 +++ b/conntrack.8 @@ -146,6 +146,9 @@ Filter source NAT connections. .BI "-g, --dst-nat " Filter destination NAT connections. .TP +.BI "-j, --any-nat " +Filter any NAT connections. +.TP .BI "--tuple-src " IP_ADDRESS Specify the tuple source address of an expectation. .TP diff --git a/include/conntrack.h b/include/conntrack.h index d8112aa..8e18e51 100644 --- a/include/conntrack.h +++ b/include/conntrack.h @@ -10,7 +10,7 @@ #include #define NUMBER_OF_CMD 18 -#define NUMBER_OF_OPT 22 +#define NUMBER_OF_OPT 23 struct ctproto_handler { struct list_head head; diff --git a/src/conntrack.c b/src/conntrack.c index 611b179..b839700 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -190,6 +190,9 @@ enum ct_options { CT_OPT_BUFFERSIZE_BIT = 21, CT_OPT_BUFFERSIZE = (1 << CT_OPT_BUFFERSIZE_BIT), + + CT_OPT_ANY_NAT_BIT = 22, + CT_OPT_ANY_NAT = (1 << CT_OPT_ANY_NAT_BIT), }; /* If you add a new option, you have to update NUMBER_OF_OPT in conntrack.h */ @@ -219,7 +222,8 @@ static const char *optflags[NUMBER_OF_OPT] = { [CT_OPT_DST_NAT_BIT] = "dst-nat", [CT_OPT_OUTPUT_BIT] = "output", [CT_OPT_SECMARK_BIT] = "secmark", - [CT_OPT_BUFFERSIZE_BIT] = "buffer-size" + [CT_OPT_BUFFERSIZE_BIT] = "buffer-size", + [CT_OPT_ANY_NAT_BIT] = "any-nat", }; static struct option original_opts[] = { @@ -258,12 +262,13 @@ static struct option original_opts[] = { {"dst-nat", 2, 0, 'g'}, {"output", 1, 0, 'o'}, {"buffer-size", 1, 0, 'b'}, + {"any-nat", 2, 0, 'j'}, {0, 0, 0, 0} }; static const char *getopt_str = "L::I::U::D::G::E::F::hVs:d:r:q:" "p:t:u:e:a:z[:]:{:}:m:i:f:o:n::" - "g::c:b:C::S"; + "g::c:b:C::Sj::"; /* Table of legal combinations of commands and options. If any of the * given commands make an option legal, that option is legal (applies to @@ -278,25 +283,25 @@ static const char *getopt_str = "L::I::U::D::G::E::F::hVs:d:r:q:" static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = /* Well, it's better than "Re: Linux vs FreeBSD" */ { - /* s d r q p t u z e [ ] { } a m i f n g o c b*/ -/*CT_LIST*/ {2,2,2,2,2,0,2,2,0,0,0,0,0,0,2,0,2,2,2,2,2,0}, -/*CT_CREATE*/ {3,3,3,3,1,1,2,0,0,0,0,0,0,2,2,0,0,2,2,0,0,0}, -/*CT_UPDATE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0}, -/*CT_DELETE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0}, -/*CT_GET*/ {3,3,3,3,1,0,0,0,0,0,0,0,0,0,0,2,0,0,0,2,0,0}, -/*CT_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*CT_EVENT*/ {2,2,2,2,2,0,0,0,2,0,0,0,0,0,2,0,0,2,2,2,2,2}, -/*VERSION*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*HELP*/ {0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*EXP_LIST*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0}, -/*EXP_CREATE*/{1,1,2,2,1,1,2,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0}, -/*EXP_DELETE*/{1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*EXP_GET*/ {1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*EXP_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*EXP_EVENT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*CT_COUNT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*EXP_COUNT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*X_STATS*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + /* s d r q p t u z e [ ] { } a m i f n g o c b j*/ +/*CT_LIST*/ {2,2,2,2,2,0,2,2,0,0,0,0,0,0,2,0,2,2,2,2,2,0,2}, +/*CT_CREATE*/ {3,3,3,3,1,1,2,0,0,0,0,0,0,2,2,0,0,2,2,0,0,0,0}, +/*CT_UPDATE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0}, +/*CT_DELETE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0}, +/*CT_GET*/ {3,3,3,3,1,0,0,0,0,0,0,0,0,0,0,2,0,0,0,2,0,0,0}, +/*CT_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*CT_EVENT*/ {2,2,2,2,2,0,0,0,2,0,0,0,0,0,2,0,0,2,2,2,2,2,2}, +/*VERSION*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*HELP*/ {0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*EXP_LIST*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0}, +/*EXP_CREATE*/{1,1,2,2,1,1,2,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0}, +/*EXP_DELETE*/{1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*EXP_GET*/ {1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*EXP_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*EXP_EVENT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*CT_COUNT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*EXP_COUNT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*X_STATS*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, }; static const int cmd2type[][2] = { @@ -325,6 +330,7 @@ static const int opt2type[] = { ['m'] = CT_OPT_MARK, ['c'] = CT_OPT_SECMARK, ['i'] = CT_OPT_ID, + ['j'] = CT_OPT_ANY_NAT, }; static const int opt2family_attr[][2] = { @@ -378,6 +384,7 @@ static const char usage_conntrack_parameters[] = "Conntrack parameters and options:\n" " -n, --src-nat ip\t\t\tsource NAT ip\n" " -g, --dst-nat ip\t\t\tdestination NAT ip\n" + " -j, --any-nat ip\t\t\tsource or destination NAT ip\n" " -m, --mark mark\t\t\tSet mark\n" " -c, --secmark secmark\t\t\tSet selinux secmark\n" " -e, --event-mask eventmask\t\tEvent mask, eg. NEW,DESTROY\n" @@ -827,6 +834,10 @@ nat_parse(char *arg, int portok, struct nf_conntrack *obj, int type) nfct_set_attr_u16(obj, ATTR_SNAT_PORT, ntohs(port)); else if (type == CT_OPT_DST_NAT) nfct_set_attr_u16(obj, ATTR_DNAT_PORT, ntohs(port)); + else if (type == CT_OPT_ANY_NAT) { + nfct_set_attr_u16(obj, ATTR_SNAT_PORT, ntohs(port)); + nfct_set_attr_u16(obj, ATTR_DNAT_PORT, ntohs(port)); + } } if (parse_addr(arg, &parse) == AF_UNSPEC) @@ -890,6 +901,36 @@ filter_nat(const struct nf_conntrack *obj, const struct nf_conntrack *ct) !nfct_getobjopt(ct, NFCT_GOPT_IS_DPAT)) return 1; } + if (options & CT_OPT_ANY_NAT) { + if (nfct_attr_is_set(obj, ATTR_SNAT_IPV4) && + nfct_attr_is_set(obj, ATTR_DNAT_IPV4)) { + uint32_t ip2; + + ip = nfct_get_attr_u32(obj, ATTR_SNAT_IPV4); + ip2 = nfct_get_attr_u32(obj, ATTR_DNAT_IPV4); + if (ip != nfct_get_attr_u32(ct, ATTR_REPL_IPV4_DST) && + ip2 != nfct_get_attr_u32(ct, ATTR_REPL_IPV4_SRC)) { + return 1; + } + } + if (nfct_attr_is_set(obj, ATTR_SNAT_PORT) && + nfct_attr_is_set(obj, ATTR_DNAT_PORT)) { + uint16_t p1, p2; + + p1 = nfct_get_attr_u16(obj, ATTR_SNAT_PORT); + p2 = nfct_get_attr_u16(obj, ATTR_DNAT_PORT); + if (p1 != nfct_get_attr_u16(ct, ATTR_REPL_PORT_DST) && + p2 != nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC)) { + return 1; + } + } + if (!nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT) && + !nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT) && + !nfct_getobjopt(ct, NFCT_GOPT_IS_SPAT) && + !nfct_getobjopt(ct, NFCT_GOPT_IS_DPAT)) { + return 1; + } + } return 0; } @@ -1346,7 +1387,8 @@ int main(int argc, char *argv[]) options |= CT_OPT_ZERO; break; case 'n': - case 'g': { + case 'g': + case 'j': { char *tmp = NULL; options |= opt2type[c]; @@ -1414,6 +1456,12 @@ int main(int argc, char *argv[]) if (family == AF_UNSPEC) family = AF_INET; + /* we cannot check this combination with generic_opt_check. */ + if (options & CT_OPT_ANY_NAT && + ((options & CT_OPT_SRC_NAT) || (options & CT_OPT_DST_NAT))) { + exit_error(PARAMETER_PROBLEM, "cannot specify `--src-nat' or " + "`--dst-nat' with `--any-nat'"); + } cmd = bit2cmd(command); res = generic_opt_check(options, NUMBER_OF_OPT, commands_v_options[cmd], optflags, -- cgit v1.2.3 From dfbc66f375e1945e7f65a0478cd25f851efae355 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 1 Jul 2010 14:26:37 +0200 Subject: conntrack: re-fix inconsistent display with `--src-nat' and `--dst-nat' In 142606c60808b3ab0496155ac3d086765e6baef3, I re-introduced the inconsistent behaviour that I described in 85f94171a71880c744f265268f33ad58819caa74. Great. This patch fixes this again. Signed-off-by: Pablo Neira Ayuso --- src/conntrack.c | 76 +++++++++++++++++++++++---------------------------------- 1 file changed, 30 insertions(+), 46 deletions(-) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index b839700..7a06519 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -868,69 +868,53 @@ static unsigned int output_mask; static int filter_nat(const struct nf_conntrack *obj, const struct nf_conntrack *ct) { + int check_srcnat = options & CT_OPT_SRC_NAT ? 1 : 0; + int check_dstnat = options & CT_OPT_DST_NAT ? 1 : 0; + int has_srcnat = 0, has_dstnat = 0; uint32_t ip; uint16_t port; - if (options & CT_OPT_SRC_NAT) { + if (options & CT_OPT_ANY_NAT) + check_srcnat = check_dstnat = 1; + + if (check_srcnat) { if (nfct_attr_is_set(obj, ATTR_SNAT_IPV4)) { ip = nfct_get_attr_u32(obj, ATTR_SNAT_IPV4); - if (ip != nfct_get_attr_u32(ct, ATTR_REPL_IPV4_DST)) - return 1; + if (ip == nfct_get_attr_u32(ct, ATTR_REPL_IPV4_DST)) + has_srcnat = 1; } if (nfct_attr_is_set(obj, ATTR_SNAT_PORT)) { port = nfct_get_attr_u16(obj, ATTR_SNAT_PORT); - if (port != nfct_get_attr_u16(ct, ATTR_REPL_PORT_DST)) - return 1; + if (port == nfct_get_attr_u16(ct, ATTR_REPL_PORT_DST)) + has_srcnat = 1; } - if (!nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT) && - !nfct_getobjopt(ct, NFCT_GOPT_IS_SPAT)) - return 1; + if (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT) || + nfct_getobjopt(ct, NFCT_GOPT_IS_SPAT)) + has_srcnat = 1; } - if (options & CT_OPT_DST_NAT) { + if (check_dstnat) { if (nfct_attr_is_set(obj, ATTR_DNAT_IPV4)) { ip = nfct_get_attr_u32(obj, ATTR_DNAT_IPV4); - if (ip != nfct_get_attr_u32(ct, ATTR_REPL_IPV4_SRC)) - return 1; + if (ip == nfct_get_attr_u32(ct, ATTR_REPL_IPV4_SRC)) + has_dstnat = 1; } if (nfct_attr_is_set(obj, ATTR_DNAT_PORT)) { port = nfct_get_attr_u16(obj, ATTR_DNAT_PORT); - if (port != nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC)) - return 1; - } - if (!nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT) && - !nfct_getobjopt(ct, NFCT_GOPT_IS_DPAT)) - return 1; - } - if (options & CT_OPT_ANY_NAT) { - if (nfct_attr_is_set(obj, ATTR_SNAT_IPV4) && - nfct_attr_is_set(obj, ATTR_DNAT_IPV4)) { - uint32_t ip2; - - ip = nfct_get_attr_u32(obj, ATTR_SNAT_IPV4); - ip2 = nfct_get_attr_u32(obj, ATTR_DNAT_IPV4); - if (ip != nfct_get_attr_u32(ct, ATTR_REPL_IPV4_DST) && - ip2 != nfct_get_attr_u32(ct, ATTR_REPL_IPV4_SRC)) { - return 1; - } - } - if (nfct_attr_is_set(obj, ATTR_SNAT_PORT) && - nfct_attr_is_set(obj, ATTR_DNAT_PORT)) { - uint16_t p1, p2; - - p1 = nfct_get_attr_u16(obj, ATTR_SNAT_PORT); - p2 = nfct_get_attr_u16(obj, ATTR_DNAT_PORT); - if (p1 != nfct_get_attr_u16(ct, ATTR_REPL_PORT_DST) && - p2 != nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC)) { - return 1; - } - } - if (!nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT) && - !nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT) && - !nfct_getobjopt(ct, NFCT_GOPT_IS_SPAT) && - !nfct_getobjopt(ct, NFCT_GOPT_IS_DPAT)) { - return 1; + if (port == nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC)) + has_dstnat = 1; } + if (nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT) || + nfct_getobjopt(ct, NFCT_GOPT_IS_DPAT)) + has_dstnat = 1; } + if (options & CT_OPT_ANY_NAT) + return !(has_srcnat || has_dstnat); + else if ((options & CT_OPT_SRC_NAT) && (options & CT_OPT_DST_NAT)) + return !(has_srcnat && has_dstnat); + else if (options & CT_OPT_SRC_NAT) + return !has_srcnat; + else if (options & CT_OPT_DST_NAT) + return !has_dstnat; return 0; } -- cgit v1.2.3 From f29be5ece1f9a0381afc9d58027b0bc4509ba479 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 1 Jul 2010 15:11:47 +0200 Subject: conntrack: fix bogus NATted flows in filtering With this patch, conntrack does not show bogus entries that have no NAT applied due to a relaxed checking. conntrack -L --src-nat :80 tcp 6 342824 ESTABLISHED src=XX.214.188.80 dst=66.XX.7.180 sport=80 dport=13749 packets=4 bytes=6000 [UNREPLIED] src=66.XX.7.180 dst=XX.214.188.80 sport=13749 dport=80 packets=0 bytes=0 mark=0 secmark=0 use=1 conntrack v0.9.14 (conntrack-tools): 1 flow entries have been shown. Signed-off-by: Pablo Neira Ayuso --- src/conntrack.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index 7a06519..0c23657 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -880,12 +880,14 @@ filter_nat(const struct nf_conntrack *obj, const struct nf_conntrack *ct) if (check_srcnat) { if (nfct_attr_is_set(obj, ATTR_SNAT_IPV4)) { ip = nfct_get_attr_u32(obj, ATTR_SNAT_IPV4); - if (ip == nfct_get_attr_u32(ct, ATTR_REPL_IPV4_DST)) + if (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT) && + ip == nfct_get_attr_u32(ct, ATTR_REPL_IPV4_DST)) has_srcnat = 1; } if (nfct_attr_is_set(obj, ATTR_SNAT_PORT)) { port = nfct_get_attr_u16(obj, ATTR_SNAT_PORT); - if (port == nfct_get_attr_u16(ct, ATTR_REPL_PORT_DST)) + if (nfct_getobjopt(ct, NFCT_GOPT_IS_SPAT) && + port == nfct_get_attr_u16(ct, ATTR_REPL_PORT_DST)) has_srcnat = 1; } if (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT) || @@ -895,12 +897,14 @@ filter_nat(const struct nf_conntrack *obj, const struct nf_conntrack *ct) if (check_dstnat) { if (nfct_attr_is_set(obj, ATTR_DNAT_IPV4)) { ip = nfct_get_attr_u32(obj, ATTR_DNAT_IPV4); - if (ip == nfct_get_attr_u32(ct, ATTR_REPL_IPV4_SRC)) + if (nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT) && + ip == nfct_get_attr_u32(ct, ATTR_REPL_IPV4_SRC)) has_dstnat = 1; } if (nfct_attr_is_set(obj, ATTR_DNAT_PORT)) { port = nfct_get_attr_u16(obj, ATTR_DNAT_PORT); - if (port == nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC)) + if (nfct_getobjopt(ct, NFCT_GOPT_IS_DPAT) && + port == nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC)) has_dstnat = 1; } if (nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT) || -- cgit v1.2.3 From fb41cec58a9428d834aa5c14e6614d2abc585e6b Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 1 Jul 2010 15:23:37 +0200 Subject: conntrack: fix `conntrack --src-nat 3.3.3.3' and similar Signed-off-by: Pablo Neira Ayuso --- src/conntrack.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index 0c23657..af6adf2 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -878,37 +878,47 @@ filter_nat(const struct nf_conntrack *obj, const struct nf_conntrack *ct) check_srcnat = check_dstnat = 1; if (check_srcnat) { + int check_address = 0, check_port = 0; + if (nfct_attr_is_set(obj, ATTR_SNAT_IPV4)) { + check_address = 1; ip = nfct_get_attr_u32(obj, ATTR_SNAT_IPV4); if (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT) && ip == nfct_get_attr_u32(ct, ATTR_REPL_IPV4_DST)) has_srcnat = 1; } if (nfct_attr_is_set(obj, ATTR_SNAT_PORT)) { + check_port = 1; port = nfct_get_attr_u16(obj, ATTR_SNAT_PORT); if (nfct_getobjopt(ct, NFCT_GOPT_IS_SPAT) && port == nfct_get_attr_u16(ct, ATTR_REPL_PORT_DST)) has_srcnat = 1; } - if (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT) || - nfct_getobjopt(ct, NFCT_GOPT_IS_SPAT)) + if (!check_address && nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) + has_srcnat = 1; + if (!check_port && nfct_getobjopt(ct, NFCT_GOPT_IS_SPAT)) has_srcnat = 1; } if (check_dstnat) { + int check_address = 0, check_port = 0; + if (nfct_attr_is_set(obj, ATTR_DNAT_IPV4)) { + check_address = 1; ip = nfct_get_attr_u32(obj, ATTR_DNAT_IPV4); if (nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT) && ip == nfct_get_attr_u32(ct, ATTR_REPL_IPV4_SRC)) has_dstnat = 1; } if (nfct_attr_is_set(obj, ATTR_DNAT_PORT)) { + check_port = 1; port = nfct_get_attr_u16(obj, ATTR_DNAT_PORT); if (nfct_getobjopt(ct, NFCT_GOPT_IS_DPAT) && port == nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC)) has_dstnat = 1; } - if (nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT) || - nfct_getobjopt(ct, NFCT_GOPT_IS_DPAT)) + if (!check_address && nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) + has_dstnat = 1; + if (!check_port && nfct_getobjopt(ct, NFCT_GOPT_IS_DPAT)) has_dstnat = 1; } if (options & CT_OPT_ANY_NAT) -- cgit v1.2.3 From 6c0096535ea7900c190d8456eeb2307a26776141 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 1 Jul 2010 16:22:52 +0200 Subject: conntrack: fix `conntrack --src-nat 1.1.1.1' if PAT applied This patch fixes another scenario in which the flow has some PAT mangling and we passed the src-nat address that we want to use to perform the filtering. Signed-off-by: Pablo Neira Ayuso --- src/conntrack.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index af6adf2..93844c5 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -894,9 +894,9 @@ filter_nat(const struct nf_conntrack *obj, const struct nf_conntrack *ct) port == nfct_get_attr_u16(ct, ATTR_REPL_PORT_DST)) has_srcnat = 1; } - if (!check_address && nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) - has_srcnat = 1; - if (!check_port && nfct_getobjopt(ct, NFCT_GOPT_IS_SPAT)) + if (!check_address && !check_port && + (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT) || + nfct_getobjopt(ct, NFCT_GOPT_IS_SPAT))) has_srcnat = 1; } if (check_dstnat) { @@ -916,9 +916,9 @@ filter_nat(const struct nf_conntrack *obj, const struct nf_conntrack *ct) port == nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC)) has_dstnat = 1; } - if (!check_address && nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) - has_dstnat = 1; - if (!check_port && nfct_getobjopt(ct, NFCT_GOPT_IS_DPAT)) + if (!check_address && !check_port && + (nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT) || + nfct_getobjopt(ct, NFCT_GOPT_IS_DPAT))) has_dstnat = 1; } if (options & CT_OPT_ANY_NAT) -- cgit v1.2.3 From fd3827bc74b6d9e5acb7f5fcf79e6e1cb326640d Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 1 Jul 2010 16:34:17 +0200 Subject: conntrack: fix `conntrack --any-nat 1.1.1.1' filtering This patch adds the missing bits to allow to filter with --any-nat based on the IP address. Signed-off-by: Pablo Neira Ayuso --- src/conntrack.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index 93844c5..82fe844 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -843,9 +843,9 @@ nat_parse(char *arg, int portok, struct nf_conntrack *obj, int type) if (parse_addr(arg, &parse) == AF_UNSPEC) return; - if (type == CT_OPT_SRC_NAT) + if (type == CT_OPT_SRC_NAT || type == CT_OPT_ANY_NAT) nfct_set_attr_u32(obj, ATTR_SNAT_IPV4, parse.v4); - else if (type == CT_OPT_DST_NAT) + else if (type == CT_OPT_DST_NAT || type == CT_OPT_ANY_NAT) nfct_set_attr_u32(obj, ATTR_DNAT_IPV4, parse.v4); } -- cgit v1.2.3 From c4413a601ba46e336e624b035a1b69f7aa1a9318 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 1 Jul 2010 16:45:26 +0200 Subject: conntrack: --[src|dst|any]-nat requires IP:PORT as argument This patch restricts the behaviour that we previously introduced in 142606c60808b3ab0496155ac3d086765e6baef3. Signed-off-by: Pablo Neira Ayuso --- qa/testsuite/03nat | 4 ++-- src/conntrack.c | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/qa/testsuite/03nat b/qa/testsuite/03nat index 8043af6..69fbff7 100644 --- a/qa/testsuite/03nat +++ b/qa/testsuite/03nat @@ -29,8 +29,8 @@ # create -I -s 1.1.1.1 -d 2.2.2.2 --dst-nat 3.3.3.3:80 -p tcp --sport 10 --dport 20 --state LISTEN -u SEEN_REPLY -t 50 ; OK # show --L --dst-nat :80 ; OK +-L --dst-nat 3.3.3.3:80 ; OK # show --L --any-nat :80 ; OK +-L --any-nat 3.3.3.3:80 ; OK # delete -D -s 1.1.1.1 ; OK diff --git a/src/conntrack.c b/src/conntrack.c index 82fe844..a5b49dd 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -816,6 +816,8 @@ nat_parse(char *arg, int portok, struct nf_conntrack *obj, int type) if (colon) { uint16_t port; + *colon = '\0'; + if (!portok) exit_error(PARAMETER_PROBLEM, "Need TCP or UDP with port specification"); @@ -841,7 +843,7 @@ nat_parse(char *arg, int portok, struct nf_conntrack *obj, int type) } if (parse_addr(arg, &parse) == AF_UNSPEC) - return; + exit_error(PARAMETER_PROBLEM, "Invalid IP address `%s'", arg); if (type == CT_OPT_SRC_NAT || type == CT_OPT_ANY_NAT) nfct_set_attr_u32(obj, ATTR_SNAT_IPV4, parse.v4); -- cgit v1.2.3 From 0b3f6c9538da47d546a0bc12c8bf5d8dd8fc2fa7 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 1 Jul 2010 16:52:41 +0200 Subject: conntrack: fix `conntrack --[src|dst|any]-nat IP:PORT' if port mismatches This patch fixes the filtering if the IP matches an entry but the PORT does not matches. Without this patch, the entry is shown when it should be not. Signed-off-by: Pablo Neira Ayuso --- qa/testsuite/03nat | 4 ++++ src/conntrack.c | 16 ++++++++++++++++ 2 files changed, 20 insertions(+) (limited to 'src') diff --git a/qa/testsuite/03nat b/qa/testsuite/03nat index 69fbff7..f94e8ff 100644 --- a/qa/testsuite/03nat +++ b/qa/testsuite/03nat @@ -32,5 +32,9 @@ -L --dst-nat 3.3.3.3:80 ; OK # show -L --any-nat 3.3.3.3:80 ; OK +# show +-L --dst-nat 3.3.3.3:81 ; OK +# show +-L --dst-nat 1.1.1.1:80 ; OK # delete -D -s 1.1.1.1 ; OK diff --git a/src/conntrack.c b/src/conntrack.c index a5b49dd..6fdd1b4 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -890,10 +890,18 @@ filter_nat(const struct nf_conntrack *obj, const struct nf_conntrack *ct) has_srcnat = 1; } if (nfct_attr_is_set(obj, ATTR_SNAT_PORT)) { + int ret = 0; + check_port = 1; port = nfct_get_attr_u16(obj, ATTR_SNAT_PORT); if (nfct_getobjopt(ct, NFCT_GOPT_IS_SPAT) && port == nfct_get_attr_u16(ct, ATTR_REPL_PORT_DST)) + ret = 1; + + /* the address matches but the port does not. */ + if (check_address && has_srcnat && !ret) + has_srcnat = 0; + if (!check_address && ret) has_srcnat = 1; } if (!check_address && !check_port && @@ -912,10 +920,18 @@ filter_nat(const struct nf_conntrack *obj, const struct nf_conntrack *ct) has_dstnat = 1; } if (nfct_attr_is_set(obj, ATTR_DNAT_PORT)) { + int ret = 0; + check_port = 1; port = nfct_get_attr_u16(obj, ATTR_DNAT_PORT); if (nfct_getobjopt(ct, NFCT_GOPT_IS_DPAT) && port == nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC)) + ret = 1; + + /* the address matches but the port does not. */ + if (check_address && has_dstnat && !ret) + has_dstnat = 0; + if (!check_address && ret) has_dstnat = 1; } if (!check_address && !check_port && -- cgit v1.2.3 From 8ece5d657d98727797f374a248c3c442e0aaa87a Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 1 Jul 2010 17:09:49 +0200 Subject: conntrack: cleanup parsing of the NAT arguments This patch cleans up nat_parse() and it also displays nicer error message for malformed arguments. % conntrack -L --src-nat :80 conntrack v0.9.14 (conntrack-tools): No IP specified Try `conntrack -h' or 'conntrack --help' for more information. % conntrack -L --src-nat 1.1.1.1: conntrack v0.9.14 (conntrack-tools): No port specified after `:' Try `conntrack -h' or 'conntrack --help' for more information. Signed-off-by: Pablo Neira Ayuso --- src/conntrack.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index 6fdd1b4..dd129c9 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -804,9 +804,8 @@ parse_addr(const char *cp, union ct_address *address) return ret; } -/* Shamelessly stolen from libipt_DNAT ;). Ranges expected in network order. */ static void -nat_parse(char *arg, int portok, struct nf_conntrack *obj, int type) +nat_parse(char *arg, struct nf_conntrack *obj, int type) { char *colon, *error; union ct_address parse; @@ -818,14 +817,16 @@ nat_parse(char *arg, int portok, struct nf_conntrack *obj, int type) *colon = '\0'; - if (!portok) - exit_error(PARAMETER_PROBLEM, - "Need TCP or UDP with port specification"); - port = (uint16_t)atoi(colon+1); - if (port == 0) - exit_error(PARAMETER_PROBLEM, - "Port `%s' not valid", colon+1); + if (port == 0) { + if (strlen(colon+1) == 0) { + exit_error(PARAMETER_PROBLEM, + "No port specified after `:'"); + } else { + exit_error(PARAMETER_PROBLEM, + "Port `%s' not valid", colon+1); + } + } error = strchr(colon+1, ':'); if (error) @@ -842,8 +843,14 @@ nat_parse(char *arg, int portok, struct nf_conntrack *obj, int type) } } - if (parse_addr(arg, &parse) == AF_UNSPEC) - exit_error(PARAMETER_PROBLEM, "Invalid IP address `%s'", arg); + if (parse_addr(arg, &parse) == AF_UNSPEC) { + if (strlen(arg) == 0) { + exit_error(PARAMETER_PROBLEM, "No IP specified"); + } else { + exit_error(PARAMETER_PROBLEM, + "Invalid IP address `%s'", arg); + } + } if (type == CT_OPT_SRC_NAT || type == CT_OPT_ANY_NAT) nfct_set_attr_u32(obj, ATTR_SNAT_IPV4, parse.v4); @@ -1419,7 +1426,7 @@ int main(int argc, char *argv[]) continue; set_family(&family, AF_INET); - nat_parse(tmp, 1, obj, opt2type[c]); + nat_parse(tmp, obj, opt2type[c]); break; } case 'i': -- cgit v1.2.3 From 70018069df0397a738498dfacf3a6130f732f0bc Mon Sep 17 00:00:00 2001 From: Mohit Mehta Date: Thu, 1 Jul 2010 17:26:55 +0200 Subject: conntrackd: update error message for max netlink socket size reached It must refer to NetlinkBufferSize[*] instead of "SocketBufferSize[*]. Signed-off-by: Mohit Mehta Signed-off-by: Pablo Neira Ayuso --- src/netlink.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/netlink.c b/src/netlink.c index 05a54bd..d145204 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -124,8 +124,8 @@ void nl_resize_socket_buffer(struct nfct_handle *h) "be losing events, this may lead to " "unsynchronized replicas. Please, consider " "increasing netlink socket buffer size via " - "SocketBufferSize and " - "SocketBufferSizeMaxGrowth clauses in " + "NetlinkBufferSize and " + "NetlinkBufferSizeMaxGrowth clauses in " "conntrackd.conf"); s = CONFIG(netlink_buffer_size_max_grown); warned = 1; -- cgit v1.2.3 From c93ff79c70e1595af94abbadce685087f702c39b Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 1 Jul 2010 17:38:07 +0200 Subject: conntrackd: fix ICMPv6 support This patch fixes several minor nitpicks to support IPv6 failover: * ICMPv6 type/code/id were missing in synchronization messages. * The use of '-' as string in the configuration file was not allowed. * Include example in configuration file under doc/. Reported-by: Mohit Mehta Signed-off-by: Pablo Neira Ayuso --- doc/sync/alarm/conntrackd.conf | 1 + doc/sync/ftfw/conntrackd.conf | 1 + doc/sync/notrack/conntrackd.conf | 1 + src/build.c | 1 + src/read_config_lex.l | 2 +- 5 files changed, 5 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/doc/sync/alarm/conntrackd.conf b/doc/sync/alarm/conntrackd.conf index 65c8715..ed36c32 100644 --- a/doc/sync/alarm/conntrackd.conf +++ b/doc/sync/alarm/conntrackd.conf @@ -345,6 +345,7 @@ General { DCCP # UDP # ICMP # This requires a Linux kernel >= 2.6.31 + # IPv6-ICMP # This requires a Linux kernel >= 2.6.31 } # diff --git a/doc/sync/ftfw/conntrackd.conf b/doc/sync/ftfw/conntrackd.conf index 481fe8b..103f9eb 100644 --- a/doc/sync/ftfw/conntrackd.conf +++ b/doc/sync/ftfw/conntrackd.conf @@ -369,6 +369,7 @@ General { DCCP # UDP # ICMP # This requires a Linux kernel >= 2.6.31 + # IPv6-ICMP # This requires a Linux kernel >= 2.6.31 } # diff --git a/doc/sync/notrack/conntrackd.conf b/doc/sync/notrack/conntrackd.conf index 430ca25..cc17fe5 100644 --- a/doc/sync/notrack/conntrackd.conf +++ b/doc/sync/notrack/conntrackd.conf @@ -407,6 +407,7 @@ General { DCCP # UDP # ICMP # This requires a Linux kernel >= 2.6.31 + # IPv6-ICMP # This requires a Linux kernel >= 2.6.31 } # diff --git a/src/build.c b/src/build.c index a73476a..a495872 100644 --- a/src/build.c +++ b/src/build.c @@ -161,6 +161,7 @@ static struct build_l4proto { [IPPROTO_SCTP] = { .build = build_l4proto_sctp }, [IPPROTO_DCCP] = { .build = build_l4proto_dccp }, [IPPROTO_ICMP] = { .build = build_l4proto_icmp }, + [IPPROTO_ICMPV6] = { .build = build_l4proto_icmp }, [IPPROTO_UDP] = { .build = build_l4proto_udp }, }; diff --git a/src/read_config_lex.l b/src/read_config_lex.l index f005099..be6bf8b 100644 --- a/src/read_config_lex.l +++ b/src/read_config_lex.l @@ -47,7 +47,7 @@ ip6_part {hex_255}":"? ip6_form1 {ip6_part}{0,16}"::"{ip6_part}{0,16} ip6_form2 ({hex_255}":"){16}{hex_255} ip6 {ip6_form1}{ip6_cidr}?|{ip6_form2}{ip6_cidr}? -string [a-zA-Z][a-zA-Z0-9\.]* +string [a-zA-Z][a-zA-Z0-9\.\-]* persistent [P|p][E|e][R|r][S|s][I|i][S|s][T|t][E|e][N|n][T|T] nack [N|n][A|a][C|c][K|k] alarm [A|a][L|l][A|a][R|r][M|m] -- cgit v1.2.3 From 3562ca2e16cac2af2ac6f344ba462b40a05d370f Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 5 Jul 2010 17:58:45 +0200 Subject: conntrack: add zone support This patch adds `--zone' to the command line tool. This adds the missing user-space support for Patrick's McHardy iptables CT target. Signed-off-by: Pablo Neira Ayuso --- conntrack.8 | 5 ++++- include/conntrack.h | 2 +- qa/testsuite/04zone | 8 ++++++++ src/conntrack.c | 59 +++++++++++++++++++++++++++++++++-------------------- 4 files changed, 50 insertions(+), 24 deletions(-) create mode 100644 qa/testsuite/04zone (limited to 'src') diff --git a/conntrack.8 b/conntrack.8 index fee3a8c..fb4336f 100644 --- a/conntrack.8 +++ b/conntrack.8 @@ -1,4 +1,4 @@ -.TH CONNTRACK 8 "Apr 11, 2009" "" "" +.TH CONNTRACK 8 "Jul 5, 2010" "" "" .\" Man page written by Harald Welte #define NUMBER_OF_CMD 18 -#define NUMBER_OF_OPT 23 +#define NUMBER_OF_OPT 24 struct ctproto_handler { struct list_head head; diff --git a/qa/testsuite/04zone b/qa/testsuite/04zone new file mode 100644 index 0000000..4ff3d34 --- /dev/null +++ b/qa/testsuite/04zone @@ -0,0 +1,8 @@ +# create dummy +-I -s 1.1.1.1 -d 2.2.2.2 -p tcp --sport 10 --dport 20 --state LISTEN -u SEEN_REPLY -t 50 --zone 1; OK +# display dummy +-L --zone 1; OK +# display dummy +-L --zone 0; OK +# delete dummy +-D --zone 1; OK diff --git a/src/conntrack.c b/src/conntrack.c index dd129c9..51ea472 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -193,12 +193,16 @@ enum ct_options { CT_OPT_ANY_NAT_BIT = 22, CT_OPT_ANY_NAT = (1 << CT_OPT_ANY_NAT_BIT), + + CT_OPT_ZONE_BIT = 23, + CT_OPT_ZONE = (1 << CT_OPT_ZONE_BIT), }; /* If you add a new option, you have to update NUMBER_OF_OPT in conntrack.h */ /* Update this mask to allow to filter based on new options. */ -#define CT_COMPARISON (CT_OPT_PROTO | CT_OPT_ORIG | CT_OPT_REPL | CT_OPT_MARK |\ - CT_OPT_SECMARK | CT_OPT_STATUS | CT_OPT_ID) +#define CT_COMPARISON (CT_OPT_PROTO | CT_OPT_ORIG | CT_OPT_REPL | \ + CT_OPT_MARK | CT_OPT_SECMARK | CT_OPT_STATUS | \ + CT_OPT_ID | CT_OPT_ZONE) static const char *optflags[NUMBER_OF_OPT] = { [CT_OPT_ORIG_SRC_BIT] = "src", @@ -224,6 +228,7 @@ static const char *optflags[NUMBER_OF_OPT] = { [CT_OPT_SECMARK_BIT] = "secmark", [CT_OPT_BUFFERSIZE_BIT] = "buffer-size", [CT_OPT_ANY_NAT_BIT] = "any-nat", + [CT_OPT_ZONE_BIT] = "zone", }; static struct option original_opts[] = { @@ -263,12 +268,13 @@ static struct option original_opts[] = { {"output", 1, 0, 'o'}, {"buffer-size", 1, 0, 'b'}, {"any-nat", 2, 0, 'j'}, + {"zone", 1, 0, 'w'}, {0, 0, 0, 0} }; static const char *getopt_str = "L::I::U::D::G::E::F::hVs:d:r:q:" "p:t:u:e:a:z[:]:{:}:m:i:f:o:n::" - "g::c:b:C::Sj::"; + "g::c:b:C::Sj::w:"; /* Table of legal combinations of commands and options. If any of the * given commands make an option legal, that option is legal (applies to @@ -283,25 +289,25 @@ static const char *getopt_str = "L::I::U::D::G::E::F::hVs:d:r:q:" static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = /* Well, it's better than "Re: Linux vs FreeBSD" */ { - /* s d r q p t u z e [ ] { } a m i f n g o c b j*/ -/*CT_LIST*/ {2,2,2,2,2,0,2,2,0,0,0,0,0,0,2,0,2,2,2,2,2,0,2}, -/*CT_CREATE*/ {3,3,3,3,1,1,2,0,0,0,0,0,0,2,2,0,0,2,2,0,0,0,0}, -/*CT_UPDATE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0}, -/*CT_DELETE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0}, -/*CT_GET*/ {3,3,3,3,1,0,0,0,0,0,0,0,0,0,0,2,0,0,0,2,0,0,0}, -/*CT_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*CT_EVENT*/ {2,2,2,2,2,0,0,0,2,0,0,0,0,0,2,0,0,2,2,2,2,2,2}, -/*VERSION*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*HELP*/ {0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*EXP_LIST*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0}, -/*EXP_CREATE*/{1,1,2,2,1,1,2,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0}, -/*EXP_DELETE*/{1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*EXP_GET*/ {1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*EXP_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*EXP_EVENT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*CT_COUNT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*EXP_COUNT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*X_STATS*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + /* s d r q p t u z e [ ] { } a m i f n g o c b j w*/ +/*CT_LIST*/ {2,2,2,2,2,0,2,2,0,0,0,0,0,0,2,0,2,2,2,2,2,0,2,2}, +/*CT_CREATE*/ {3,3,3,3,1,1,2,0,0,0,0,0,0,2,2,0,0,2,2,0,0,0,0,2}, +/*CT_UPDATE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,0}, +/*CT_DELETE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,2}, +/*CT_GET*/ {3,3,3,3,1,0,0,0,0,0,0,0,0,0,0,2,0,0,0,2,0,0,0,0}, +/*CT_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*CT_EVENT*/ {2,2,2,2,2,0,0,0,2,0,0,0,0,0,2,0,0,2,2,2,2,2,2,2}, +/*VERSION*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*HELP*/ {0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*EXP_LIST*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0}, +/*EXP_CREATE*/{1,1,2,2,1,1,2,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0}, +/*EXP_DELETE*/{1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*EXP_GET*/ {1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*EXP_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*EXP_EVENT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*CT_COUNT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*EXP_COUNT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*X_STATS*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, }; static const int cmd2type[][2] = { @@ -331,6 +337,7 @@ static const int opt2type[] = { ['c'] = CT_OPT_SECMARK, ['i'] = CT_OPT_ID, ['j'] = CT_OPT_ANY_NAT, + ['w'] = CT_OPT_ZONE, }; static const int opt2family_attr[][2] = { @@ -352,6 +359,7 @@ static const int opt2attr[] = { ['m'] = ATTR_MARK, ['c'] = ATTR_SECMARK, ['i'] = ATTR_ID, + ['w'] = ATTR_ZONE, }; static char exit_msg[NUMBER_OF_CMD][64] = { @@ -408,6 +416,7 @@ static const char usage_parameters[] = " -f, --family proto\t\tLayer 3 Protocol, eg. 'ipv6'\n" " -t, --timeout timeout\t\tSet timeout\n" " -u, --status status\t\tSet status, eg. ASSURED\n" + " -w, --zone value\t\tSet conntrack zone\n" " -b, --buffer-size\t\tNetlink socket buffer size\n" ; @@ -1429,6 +1438,12 @@ int main(int argc, char *argv[]) nat_parse(tmp, obj, opt2type[c]); break; } + case 'w': + options |= opt2type[c]; + nfct_set_attr_u16(obj, + opt2attr[c], + strtoul(optarg, NULL, 0)); + break; case 'i': case 'm': case 'c': -- cgit v1.2.3 From 5fe142121d73e7e261f9da532288f1857d25897b Mon Sep 17 00:00:00 2001 From: Mohit Mehta Date: Wed, 7 Jul 2010 12:39:48 +0200 Subject: conntrackd: enforce strict logic for NetlinkBufferSize[*] clauses - NetlinkBufferSize value passed to the kernel gets doubled [see SO_RCVBUF in net/core/sock.c]; it's halved now before it gets sent to the kernel. This ensures that daemon starts up with a netlink socket buffer size equal to the value set for NetlinkBufferSize in configuration file. - Previously, netlink socket buffer size would only stop increasing after it had increased beyond NetlinkBufferSizeMaxGrowth value. With this commit netlink socket buffer size increases as long as it is less than or equal to NetlinkBufferSizeMaxGrowth value. Signed-off-by: Mohit Mehta Signed-off-by: Pablo Neira Ayuso --- src/netlink.c | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/netlink.c b/src/netlink.c index d145204..f564436 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -53,10 +53,18 @@ struct nfct_handle *nl_init_event_handler(void) fcntl(nfct_fd(h), F_SETFL, O_NONBLOCK); /* set up socket buffer size */ - if (CONFIG(netlink_buffer_size)) { - CONFIG(netlink_buffer_size) = - nfnl_rcvbufsiz(nfct_nfnlh(h), CONFIG(netlink_buffer_size)); + if (CONFIG(netlink_buffer_size) && + CONFIG(netlink_buffer_size) <= + CONFIG(netlink_buffer_size_max_grown)) { + /* we divide netlink_buffer_size by 2 here since value passed + to kernel gets doubled in SO_RCVBUF; see net/core/sock.c */ + CONFIG(netlink_buffer_size) = + nfnl_rcvbufsiz(nfct_nfnlh(h), CONFIG(netlink_buffer_size)/2); } else { + dlog(LOG_NOTICE, "NetlinkBufferSize is either not set or " + "is greater than NetlinkBufferSizeMaxGrowth. " + "Using current system buffer size"); + socklen_t socklen = sizeof(unsigned int); unsigned int read_size; @@ -70,11 +78,6 @@ struct nfct_handle *nl_init_event_handler(void) dlog(LOG_NOTICE, "netlink event socket buffer size has been set " "to %u bytes", CONFIG(netlink_buffer_size)); - /* ensure that maximum grown size is >= than maximum size */ - if (CONFIG(netlink_buffer_size_max_grown) < CONFIG(netlink_buffer_size)) - CONFIG(netlink_buffer_size_max_grown) = - CONFIG(netlink_buffer_size); - if (CONFIG(netlink).events_reliable) { int on = 1; @@ -110,31 +113,34 @@ static int warned = 0; void nl_resize_socket_buffer(struct nfct_handle *h) { - /* sock_setsockopt in net/core/sock.c doubles the size of the buffer */ unsigned int s = CONFIG(netlink_buffer_size); /* already warned that we have reached the maximum buffer size */ if (warned) return; - if (s > CONFIG(netlink_buffer_size_max_grown)) { + /* since sock_setsockopt in net/core/sock.c doubles the size of socket + buffer passed to it using nfnl_rcvbufsiz, only call nfnl_rcvbufsiz + if new value is not greater than netlink_buffer_size_max_grown */ + if (s*2 > CONFIG(netlink_buffer_size_max_grown)) { dlog(LOG_WARNING, - "maximum netlink socket buffer " - "size has been reached. We are likely to " + "netlink event socket buffer size cannot " + "be doubled further since it will exceed " + "NetlinkBufferSizeMaxGrowth. We are likely to " "be losing events, this may lead to " "unsynchronized replicas. Please, consider " "increasing netlink socket buffer size via " "NetlinkBufferSize and " "NetlinkBufferSizeMaxGrowth clauses in " "conntrackd.conf"); - s = CONFIG(netlink_buffer_size_max_grown); warned = 1; + return; } CONFIG(netlink_buffer_size) = nfnl_rcvbufsiz(nfct_nfnlh(h), s); /* notify the sysadmin */ - dlog(LOG_NOTICE, "netlink socket buffer size has been increased " + dlog(LOG_NOTICE, "netlink event socket buffer size has been doubled " "to %u bytes", CONFIG(netlink_buffer_size)); } -- cgit v1.2.3 From a5c2a83f907a6a82912165bf2ef67ded13e84bc1 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 31 Dec 2009 19:10:41 +0100 Subject: conntrackd: open event handler once cache has been populated With this patch, we open the event handler once the internal cache (if any) is populated. This reduces the chances of a possible premature overrun if we lauch conntrackd in a busy firewall. However, we may still start with an internal cache that may differ a bit from the once in the kernel. This patch has no impact in setups where conntrackd is started in a spare firewall. Signed-off-by: Pablo Neira Ayuso --- src/run.c | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/run.c b/src/run.c index f68dd91..5781939 100644 --- a/src/run.c +++ b/src/run.c @@ -355,19 +355,6 @@ init(void) } register_fd(STATE(local).fd, STATE(fds)); - if (!(CONFIG(flags) & CTD_POLL)) { - STATE(event) = nl_init_event_handler(); - if (STATE(event) == NULL) { - dlog(LOG_ERR, "can't open netlink handler: %s", - strerror(errno)); - dlog(LOG_ERR, "no ctnetlink kernel support?"); - return -1; - } - nfct_callback_register2(STATE(event), NFCT_T_ALL, - event_handler, NULL); - register_fd(nfct_fd(STATE(event)), STATE(fds)); - } - /* resynchronize (like 'dump' socket) but it also purges old entries */ STATE(resync) = nfct_open(CONNTRACK, 0); if (STATE(resync)== NULL) { @@ -423,6 +410,24 @@ init(void) dlog(LOG_NOTICE, "running in polling mode"); } else { init_alarm(&STATE(resync_alarm), NULL, do_overrun_resync_alarm); + /* + * The last nfct handler that we register is the event handler. + * The reason to do this is that we may receive events while + * populating the internal cache. Thus, we hit ENOBUFS + * prematurely. However, if we open the event handler before + * populating the internal cache, we may still lose events + * that have occured during the population. + */ + STATE(event) = nl_init_event_handler(); + if (STATE(event) == NULL) { + dlog(LOG_ERR, "can't open netlink handler: %s", + strerror(errno)); + dlog(LOG_ERR, "no ctnetlink kernel support?"); + return -1; + } + nfct_callback_register2(STATE(event), NFCT_T_ALL, + event_handler, NULL); + register_fd(nfct_fd(STATE(event)), STATE(fds)); } /* Signals handling */ -- cgit v1.2.3 From 5bec6c7dbc3bafd5befa60381d2e6b743b7b4b98 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 7 Jul 2010 14:42:22 +0200 Subject: conntrackd: setup event reliability after handler creation This patch enables the event reliability in an early stage of the event handler initialization. Signed-off-by: Pablo Neira Ayuso --- src/netlink.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/netlink.c b/src/netlink.c index f564436..1810f4a 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -36,6 +36,19 @@ struct nfct_handle *nl_init_event_handler(void) if (h == NULL) return NULL; + if (CONFIG(netlink).events_reliable) { + int on = 1; + + setsockopt(nfct_fd(h), SOL_NETLINK, + NETLINK_BROADCAST_SEND_ERROR, &on, sizeof(int)); + + setsockopt(nfct_fd(h), SOL_NETLINK, + NETLINK_NO_ENOBUFS, &on, sizeof(int)); + + dlog(LOG_NOTICE, "reliable ctnetlink event delivery " + "is ENABLED."); + } + if (STATE(filter)) { if (CONFIG(filter_from_kernelspace)) { if (nfct_filter_attach(nfct_fd(h), @@ -78,18 +91,6 @@ struct nfct_handle *nl_init_event_handler(void) dlog(LOG_NOTICE, "netlink event socket buffer size has been set " "to %u bytes", CONFIG(netlink_buffer_size)); - if (CONFIG(netlink).events_reliable) { - int on = 1; - - setsockopt(nfct_fd(h), SOL_NETLINK, - NETLINK_BROADCAST_SEND_ERROR, &on, sizeof(int)); - - setsockopt(nfct_fd(h), SOL_NETLINK, - NETLINK_NO_ENOBUFS, &on, sizeof(int)); - - dlog(LOG_NOTICE, "reliable ctnetlink event delivery " - "is ENABLED."); - } return h; } -- cgit v1.2.3 From 2e4b408ab7dd76bfaefd6cb5ea69fdff381a4b76 Mon Sep 17 00:00:00 2001 From: Mohit Mehta Date: Fri, 9 Jul 2010 16:45:48 +0200 Subject: conntrackd: replace cryptic `mfrm' by `malformed' in `-s' Looking at the output of `conntrackd -s`; I didn't know what 'mfrm' meant under the 'message sequence tracking' section so I had to look up the code for this. While doing so, I replaced 'mfrm' with 'malformed' in the output since I thought other users might be confused as well as I was looking at that word. Signed-off-by: Mohit Mehta Signed-off-by: Pablo Neira Ayuso --- src/sync-mode.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/sync-mode.c b/src/sync-mode.c index c12a34a..96379f6 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -414,9 +414,9 @@ static void dump_stats_sync(int fd) char buf[512]; int size; - size = sprintf(buf, "message sequence tracking:\n" - "%20llu Msgs mfrm " - "%20llu Msgs lost\n\n", + size = sprintf(buf, "message tracking:\n" + "%20llu Malformed msgs " + "%20llu Lost msgs\n\n", (unsigned long long)STATE_SYNC(error).msg_rcv_malformed, (unsigned long long)STATE_SYNC(error).msg_rcv_lost); -- cgit v1.2.3 From 1f3c6df4f8984fce347718cca09dd0e2fa138ce1 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 13 Jul 2010 11:30:08 +0200 Subject: conntrackd: fix parsing of NAT sequence adjustment in synchronization messages This patch fixes a bug that results in an incorrect parsing of the NAT sequence adjustment in synchronization messages. Spotted by Adam Gundy in the following message that was sent to the netfilter ML: http://marc.info/?l=netfilter&m=127894708222913&w=2 Signed-off-by: Pablo Neira Ayuso --- src/parse.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/parse.c b/src/parse.c index 3eb7f44..7e60597 100644 --- a/src/parse.c +++ b/src/parse.c @@ -207,15 +207,15 @@ parse_nat_seq_adj(struct nf_conntrack *ct, int attr, void *data) nfct_set_attr_u32(ct, ATTR_ORIG_NAT_SEQ_CORRECTION_POS, ntohl(this->orig_seq_correction_pos)); nfct_set_attr_u32(ct, ATTR_ORIG_NAT_SEQ_OFFSET_BEFORE, - ntohl(this->orig_seq_correction_pos)); + ntohl(this->orig_seq_offset_before)); nfct_set_attr_u32(ct, ATTR_ORIG_NAT_SEQ_OFFSET_AFTER, - ntohl(this->orig_seq_correction_pos)); + ntohl(this->orig_seq_offset_after)); nfct_set_attr_u32(ct, ATTR_REPL_NAT_SEQ_CORRECTION_POS, - ntohl(this->orig_seq_correction_pos)); + ntohl(this->repl_seq_correction_pos)); nfct_set_attr_u32(ct, ATTR_REPL_NAT_SEQ_OFFSET_BEFORE, - ntohl(this->orig_seq_correction_pos)); + ntohl(this->repl_seq_offset_before)); nfct_set_attr_u32(ct, ATTR_REPL_NAT_SEQ_OFFSET_AFTER, - ntohl(this->orig_seq_correction_pos)); + ntohl(this->repl_seq_offset_after)); } int parse_payload(struct nf_conntrack *ct, struct nethdr *net, size_t remain) -- cgit v1.2.3 From 31ae56a2af1381459e4ec38c31ab810ffa410cf9 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 8 Oct 2010 20:59:14 +0200 Subject: conntrack: allow to listen to all kind of expectation events So far, conntrack only allows to listen to events of new expectations. With this patch, we can listen to events of destroyed expectations. Signed-off-by: Pablo Neira Ayuso --- src/conntrack.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 55 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index 51ea472..2527953 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -671,6 +671,13 @@ enum { _O_ID = (1 << 3), }; +enum { + CT_EVENT_F_NEW = (1 << 0), + CT_EVENT_F_UPD = (1 << 1), + CT_EVENT_F_DEL = (1 << 2), + CT_EVENT_F_ALL = CT_EVENT_F_NEW | CT_EVENT_F_UPD | CT_EVENT_F_DEL, +}; + static struct parse_parameter { const char *parameter[6]; size_t size; @@ -679,8 +686,7 @@ static struct parse_parameter { { {"ASSURED", "SEEN_REPLY", "UNSET", "FIXED_TIMEOUT", "EXPECTED"}, 5, { IPS_ASSURED, IPS_SEEN_REPLY, 0, IPS_FIXED_TIMEOUT, IPS_EXPECTED} }, { {"ALL", "NEW", "UPDATES", "DESTROY"}, 4, - {~0U, NF_NETLINK_CONNTRACK_NEW, NF_NETLINK_CONNTRACK_UPDATE, - NF_NETLINK_CONNTRACK_DESTROY} }, + { CT_EVENT_F_ALL, CT_EVENT_F_NEW, CT_EVENT_F_UPD, CT_EVENT_F_DEL } }, { {"xml", "extended", "timestamp", "id" }, 4, { _O_XML, _O_EXT, _O_TMS, _O_ID }, }, @@ -1194,6 +1200,18 @@ static int dump_exp_cb(enum nf_conntrack_msg_type type, return NFCT_CB_CONTINUE; } +static int event_exp_cb(enum nf_conntrack_msg_type type, + struct nf_expect *exp, void *data) +{ + char buf[1024]; + + nfexp_snprintf(buf,sizeof(buf), exp, type, NFCT_O_DEFAULT, 0); + printf("%s\n", buf); + counter++; + + return NFCT_CB_CONTINUE; +} + static int count_exp_cb(enum nf_conntrack_msg_type type, struct nf_expect *exp, void *data) @@ -1667,11 +1685,23 @@ int main(int argc, char *argv[]) break; case CT_EVENT: - if (options & CT_OPT_EVENT_MASK) + if (options & CT_OPT_EVENT_MASK) { + unsigned int nl_events = 0; + + if (event_mask & CT_EVENT_F_NEW) + nl_events |= NF_NETLINK_CONNTRACK_NEW; + if (event_mask & CT_EVENT_F_UPD) + nl_events |= NF_NETLINK_CONNTRACK_UPDATE; + if (event_mask & CT_EVENT_F_DEL) + nl_events |= NF_NETLINK_CONNTRACK_DESTROY; + + cth = nfct_open(CONNTRACK, nl_events); + } else { cth = nfct_open(CONNTRACK, - event_mask & NFCT_ALL_CT_GROUPS); - else - cth = nfct_open(CONNTRACK, NFCT_ALL_CT_GROUPS); + NF_NETLINK_CONNTRACK_NEW | + NF_NETLINK_CONNTRACK_UPDATE | + NF_NETLINK_CONNTRACK_DESTROY); + } if (!cth) exit_error(OTHER_PROBLEM, "Can't open handler"); @@ -1701,12 +1731,29 @@ int main(int argc, char *argv[]) break; case EXP_EVENT: - cth = nfct_open(EXPECT, NF_NETLINK_CONNTRACK_EXP_NEW); + if (options & CT_OPT_EVENT_MASK) { + unsigned int nl_events = 0; + + if (event_mask & CT_EVENT_F_NEW) + nl_events |= NF_NETLINK_CONNTRACK_EXP_NEW; + if (event_mask & CT_EVENT_F_UPD) + nl_events |= NF_NETLINK_CONNTRACK_EXP_UPDATE; + if (event_mask & CT_EVENT_F_DEL) + nl_events |= NF_NETLINK_CONNTRACK_EXP_DESTROY; + + cth = nfct_open(CONNTRACK, nl_events); + } else { + cth = nfct_open(EXPECT, + NF_NETLINK_CONNTRACK_EXP_NEW | + NF_NETLINK_CONNTRACK_EXP_UPDATE | + NF_NETLINK_CONNTRACK_EXP_DESTROY); + } + if (!cth) exit_error(OTHER_PROBLEM, "Can't open handler"); signal(SIGINT, event_sighandler); signal(SIGTERM, event_sighandler); - nfexp_callback_register(cth, NFCT_T_ALL, dump_exp_cb, NULL); + nfexp_callback_register(cth, NFCT_T_ALL, event_exp_cb, NULL); res = nfexp_catch(cth); nfct_close(cth); break; -- cgit v1.2.3 From 6ef83f8c7ff52adaa6f50fc9017975a379f4c78e Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Sun, 31 Oct 2010 00:39:48 +0200 Subject: build: remove unused $(all_libraries) Signed-off-by: Jan Engelhardt --- src/Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 76f0e73..0e9af2e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -8,7 +8,7 @@ sbin_PROGRAMS = conntrack conntrackd conntrack_SOURCES = conntrack.c conntrack_LDADD = ../extensions/libct_proto_tcp.la ../extensions/libct_proto_udp.la ../extensions/libct_proto_udplite.la ../extensions/libct_proto_icmp.la ../extensions/libct_proto_icmpv6.la ../extensions/libct_proto_sctp.la ../extensions/libct_proto_dccp.la ../extensions/libct_proto_gre.la ../extensions/libct_proto_unknown.la -conntrack_LDFLAGS = $(all_libraries) @LIBNETFILTER_CONNTRACK_LIBS@ +conntrack_LDFLAGS = @LIBNETFILTER_CONNTRACK_LIBS@ conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c rbtree.c \ local.c log.c mcast.c udp.c netlink.c vector.c \ @@ -28,6 +28,6 @@ conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c rbtree.c \ # yacc and lex generate dirty code read_config_yy.o read_config_lex.o: AM_CFLAGS += -Wno-missing-prototypes -Wno-missing-declarations -Wno-implicit-function-declaration -Wno-nested-externs -Wno-undef -Wno-redundant-decls -conntrackd_LDFLAGS = $(all_libraries) @LIBNETFILTER_CONNTRACK_LIBS@ +conntrackd_LDFLAGS = @LIBNETFILTER_CONNTRACK_LIBS@ EXTRA_DIST = read_config_yy.h -- cgit v1.2.3 From 39db4adb8932166a2fcb1143f512d2e212e6de8b Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Sun, 31 Oct 2010 00:44:12 +0200 Subject: build: no need for error message in PKG_CHECK_MODULES PKG_CHECK_MODULES already produces its own (and more verbose) messsage when a module cannot be found. Mucking around with CFLAGS and LIBS is also not needed since pkgconfig takes care of providing variables, so let's use them in Makefile.am. Signed-off-by: Jan Engelhardt --- Make_global.am | 3 ++- configure.ac | 25 ++----------------------- src/Makefile.am | 5 ++--- 3 files changed, 6 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/Make_global.am b/Make_global.am index 4e9794e..e8f603a 100644 --- a/Make_global.am +++ b/Make_global.am @@ -2,4 +2,5 @@ AM_CPPFLAGS = -I$(top_srcdir)/include AM_CFLAGS = -std=gnu99 -W -Wall \ -Wmissing-prototypes -Wwrite-strings -Wcast-qual -Wfloat-equal -Wshadow -Wpointer-arith -Wbad-function-cast -Wsign-compare -Waggregate-return -Wmissing-declarations -Wredundant-decls -Wnested-externs -Winline -Wstrict-prototypes -Wundef \ - -Wno-unused-parameter + -Wno-unused-parameter ${LIBNFNETLINK_CFLAGS} \ + ${LIBNETFILTER_CONNTRACK_CFLAGS} diff --git a/configure.ac b/configure.ac index e068798..37fbeee 100644 --- a/configure.ac +++ b/configure.ac @@ -18,22 +18,8 @@ case "$host" in esac dnl Dependencies -LIBNFNETLINK_REQUIRED=1.0.0 -LIBNETFILTER_CONNTRACK_REQUIRED=0.0.102 - -AC_CHECK_PROG(HAVE_PKG_CONFIG, pkg-config, yes) -if test "x$HAVE_PKG_CONFIG" = "x" -then - echo "*** Error: No suitable pkg-config found. ***" - echo " Please install the 'pkg-config' package." - exit 1 -fi - -PKG_CHECK_MODULES(LIBNFNETLINK, libnfnetlink >= $LIBNFNETLINK_REQUIRED,, - AC_MSG_ERROR(Cannot find libnfnetlink >= $LIBNFNETLINK_REQUIRED)) - -PKG_CHECK_MODULES(LIBNETFILTER_CONNTRACK, libnetfilter_conntrack >= $LIBNETFILTER_CONNTRACK_REQUIRED,, - AC_MSG_ERROR(Cannot find libnetfilter_conntrack >= $LIBNETFILTER_CONNTRACK_REQUIRED)) +PKG_CHECK_MODULES([LIBNFNETLINK], [libnfnetlink >= 1.0.0]) +PKG_CHECK_MODULES([LIBNETFILTER_CONNTRACK], [libnetfilter_conntrack >= 0.0.102]) AC_CHECK_PROGS(XYACC,$YACC bison yacc,none) if test "$XYACC" = "none" @@ -72,9 +58,6 @@ AC_CHECK_HEADERS([linux/capability.h],, [AC_MSG_ERROR([Cannot find linux/capabib dnl AC_CHECK_LIB([c], [main]) # FIXME: Replace `main' with a function in `-ldl': -AC_CHECK_LIB([nfnetlink], [nfnl_query] ,,,[-lnfnetlink]) -AC_CHECK_LIB([netfilter_conntrack], [nfct_query] ,,,[-lnetfilter_conntrack]) - AC_CHECK_HEADERS(arpa/inet.h) dnl check for inet_pton AC_CHECK_FUNCS(inet_pton) @@ -127,9 +110,5 @@ dnl debug/src/Makefile dnl extensions/Makefile dnl src/Makefile]) -CFLAGS="$CFLAGS $LIBNETFILTER_CONNTRACK_CFLAGS" - -AC_SUBST(LIBNETFILTER_CONNTRACK_LIBS) - AC_CONFIG_FILES([Makefile src/Makefile include/Makefile extensions/Makefile]) AC_OUTPUT diff --git a/src/Makefile.am b/src/Makefile.am index 0e9af2e..a85a56f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -7,8 +7,7 @@ CLEANFILES = read_config_yy.c read_config_lex.c sbin_PROGRAMS = conntrack conntrackd conntrack_SOURCES = conntrack.c -conntrack_LDADD = ../extensions/libct_proto_tcp.la ../extensions/libct_proto_udp.la ../extensions/libct_proto_udplite.la ../extensions/libct_proto_icmp.la ../extensions/libct_proto_icmpv6.la ../extensions/libct_proto_sctp.la ../extensions/libct_proto_dccp.la ../extensions/libct_proto_gre.la ../extensions/libct_proto_unknown.la -conntrack_LDFLAGS = @LIBNETFILTER_CONNTRACK_LIBS@ +conntrack_LDADD = ../extensions/libct_proto_tcp.la ../extensions/libct_proto_udp.la ../extensions/libct_proto_udplite.la ../extensions/libct_proto_icmp.la ../extensions/libct_proto_icmpv6.la ../extensions/libct_proto_sctp.la ../extensions/libct_proto_dccp.la ../extensions/libct_proto_gre.la ../extensions/libct_proto_unknown.la ${LIBNETFILTER_CONNTRACK_LIBS} conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c rbtree.c \ local.c log.c mcast.c udp.c netlink.c vector.c \ @@ -28,6 +27,6 @@ conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c rbtree.c \ # yacc and lex generate dirty code read_config_yy.o read_config_lex.o: AM_CFLAGS += -Wno-missing-prototypes -Wno-missing-declarations -Wno-implicit-function-declaration -Wno-nested-externs -Wno-undef -Wno-redundant-decls -conntrackd_LDFLAGS = @LIBNETFILTER_CONNTRACK_LIBS@ +conntrackd_LDADD = ${LIBNETFILTER_CONNTRACK_LIBS} EXTRA_DIST = read_config_yy.h -- cgit v1.2.3 From 89189d0799a158cab83c564f57aaa9942a4cc19e Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Sun, 31 Oct 2010 00:39:05 +0200 Subject: Add .gitignore files Signed-off-by: Jan Engelhardt --- .gitignore | 18 ++++++++++++++++++ src/.gitignore | 6 ++++++ 2 files changed, 24 insertions(+) create mode 100644 .gitignore create mode 100644 src/.gitignore (limited to 'src') diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..444c4b3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,18 @@ +.deps +.libs +Makefile +Makefile.in +*.o +*.la +*.lo + +/aclocal.m4 +/autom4te.cache +/config.* +/configure +/depcomp +/install-sh +/libtool +/ltmain.sh +/missing +/ylwrap diff --git a/src/.gitignore b/src/.gitignore new file mode 100644 index 0000000..6e6763d --- /dev/null +++ b/src/.gitignore @@ -0,0 +1,6 @@ +/conntrack +/conntrackd + +/read_config_lex.c +/read_config_yy.c +/read_config_yy.h -- cgit v1.2.3 From cb35643f408d70cff406c95c4951e0edc28a0648 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Fri, 5 Nov 2010 18:35:35 +0100 Subject: build: resolve automake warning src/Makefile.am:24: whitespace following trailing backslash Signed-off-by: Jan Engelhardt --- src/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index a85a56f..10b3467 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -21,7 +21,7 @@ conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c rbtree.c \ channel.c multichannel.c channel_mcast.c channel_udp.c \ tcp.c channel_tcp.c \ external_cache.c external_inject.c \ - internal_cache.c internal_bypass.c \ + internal_cache.c internal_bypass.c \ read_config_yy.y read_config_lex.l # yacc and lex generate dirty code -- cgit v1.2.3 From 38d01668739df60471baedc9084a7d118aca778e Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Fri, 5 Nov 2010 18:42:25 +0100 Subject: build: use AM_YFLAGS instead of overriding YACC Signed-off-by: Jan Engelhardt --- src/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 10b3467..70e496d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,6 +1,6 @@ include $(top_srcdir)/Make_global.am -YACC=@YACC@ -d +AM_YFLAGS = -d CLEANFILES = read_config_yy.c read_config_lex.c -- cgit v1.2.3 From c6a4bdb9ea086ba48b000777f35090559f86c962 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 13 Feb 2011 21:48:26 +0100 Subject: local: don't override initial return value The return initial value is overriden after the initial read. Don't override this value, instead we check the return value of the read() operation. This patch also changes the error statistics accounting since we consider that a request with no data is an error. Signed-off-by: Pablo Neira Ayuso --- src/run.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'src') diff --git a/src/run.c b/src/run.c index 5781939..d96ff6c 100644 --- a/src/run.c +++ b/src/run.c @@ -191,14 +191,10 @@ static int local_handler(int fd, void *data) int ret = LOCAL_RET_OK; int type; - ret = read(fd, &type, sizeof(type)); - if (ret == -1) { + if (read(fd, &type, sizeof(type)) <= 0) { STATE(stats).local_read_failed++; return LOCAL_RET_OK; } - if (ret == 0) - return LOCAL_RET_OK; - switch(type) { case FLUSH_MASTER: STATE(stats).nl_kernel_table_flush++; -- cgit v1.2.3 From 9173be30c4716ce6c1a4c9b73a3657bb8fc3327a Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 13 Feb 2011 21:40:20 +0100 Subject: sync: don't override initial return value of local handler Signed-off-by: Pablo Neira Ayuso --- src/sync-mode.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/sync-mode.c b/src/sync-mode.c index 96379f6..1250a08 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -465,29 +465,25 @@ static int local_handler_sync(int fd, int type, void *data) switch(type) { case DUMP_INTERNAL: - ret = fork_process_new(CTD_PROC_ANY, 0, NULL, NULL); - if (ret == 0) { + if (fork_process_new(CTD_PROC_ANY, 0, NULL, NULL) == 0) { STATE(mode)->internal->dump(fd, NFCT_O_PLAIN); exit(EXIT_SUCCESS); } break; case DUMP_EXTERNAL: - ret = fork_process_new(CTD_PROC_ANY, 0, NULL, NULL); - if (ret == 0) { + if (fork_process_new(CTD_PROC_ANY, 0, NULL, NULL) == 0) { STATE_SYNC(external)->dump(fd, NFCT_O_PLAIN); exit(EXIT_SUCCESS); } break; case DUMP_INT_XML: - ret = fork_process_new(CTD_PROC_ANY, 0, NULL, NULL); - if (ret == 0) { + if (fork_process_new(CTD_PROC_ANY, 0, NULL, NULL) == 0) { STATE(mode)->internal->dump(fd, NFCT_O_XML); exit(EXIT_SUCCESS); } break; case DUMP_EXT_XML: - ret = fork_process_new(CTD_PROC_ANY, 0, NULL, NULL); - if (ret == 0) { + if (fork_process_new(CTD_PROC_ANY, 0, NULL, NULL) == 0) { STATE_SYNC(external)->dump(fd, NFCT_O_XML); exit(EXIT_SUCCESS); } -- cgit v1.2.3 From 98756c2608f0879a2322919c7441973216565272 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 13 Feb 2011 22:38:01 +0100 Subject: cache: close commit request if we already have one in progress We close a commit request if there's already one in progress. This patch fixes a problem that may be triggered if two consecutive commit requests are received. Signed-off-by: Pablo Neira Ayuso --- src/cache_iterators.c | 6 ++++++ src/sync-mode.c | 1 + 2 files changed, 7 insertions(+) (limited to 'src') diff --git a/src/cache_iterators.c b/src/cache_iterators.c index c7183fd..2707366 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -184,6 +184,11 @@ void cache_commit(struct cache *c, struct nfct_handle *h, int clientfd) }; struct timeval commit_stop, res; + /* we already have one commit in progress, close this request. */ + if (clientfd && STATE_SYNC(commit).clientfd != -1) { + close(clientfd); + return; + } switch(STATE_SYNC(commit).state) { case COMMIT_STATE_INACTIVE: gettimeofday(&STATE_SYNC(commit).stats.start, NULL); @@ -241,6 +246,7 @@ void cache_commit(struct cache *c, struct nfct_handle *h, int clientfd) /* Close the client socket now that we're done. */ close(STATE_SYNC(commit).clientfd); + STATE_SYNC(commit).clientfd = -1; } } diff --git a/src/sync-mode.c b/src/sync-mode.c index 1250a08..4b48449 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -346,6 +346,7 @@ static int init_sync(void) STATE(fds)) == -1) { return -1; } + STATE_SYNC(commit).clientfd = -1; init_alarm(&STATE_SYNC(reset_cache_alarm), NULL, do_reset_cache_alarm); -- cgit v1.2.3 From c2acb11453fc75519862240298e106ac79274780 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 15 Feb 2011 01:51:11 +0100 Subject: cache: log if we received a commit request while already one in progress This patch improves the case in which we receive a commit request but we are already performing one. This behaviour is suspicious since the HA manager should not trigger a double master transition. Otherwise, something probably is not configured appropriately. This improves 98756c2608f0879a2322919c7441973216565272 "cache: close commit request if we already have one in progress". Signed-off-by: Pablo Neira Ayuso --- include/cache.h | 2 +- src/cache_iterators.c | 17 +++++++++-------- src/external_cache.c | 5 ++++- 3 files changed, 14 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/include/cache.h b/include/cache.h index 28917f2..ddf2049 100644 --- a/include/cache.h +++ b/include/cache.h @@ -121,7 +121,7 @@ void cache_iterate_limit(struct cache *c, void *data, uint32_t from, uint32_t st struct nfct_handle; void cache_dump(struct cache *c, int fd, int type); -void cache_commit(struct cache *c, struct nfct_handle *h, int clientfd); +int cache_commit(struct cache *c, struct nfct_handle *h, int clientfd); void cache_flush(struct cache *c); void cache_bulk(struct cache *c); diff --git a/src/cache_iterators.c b/src/cache_iterators.c index 2707366..3248c70 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -175,7 +175,7 @@ static int do_commit_master(void *data, void *n) return 0; } -void cache_commit(struct cache *c, struct nfct_handle *h, int clientfd) +int cache_commit(struct cache *c, struct nfct_handle *h, int clientfd) { unsigned int commit_ok, commit_fail; struct __commit_container tmp = { @@ -184,11 +184,11 @@ void cache_commit(struct cache *c, struct nfct_handle *h, int clientfd) }; struct timeval commit_stop, res; - /* we already have one commit in progress, close this request. */ - if (clientfd && STATE_SYNC(commit).clientfd != -1) { - close(clientfd); - return; - } + /* we already have one commit in progress, skip this. The clientfd + * descriptor has to be closed by the caller. */ + if (clientfd && STATE_SYNC(commit).clientfd != -1) + return 0; + switch(STATE_SYNC(commit).state) { case COMMIT_STATE_INACTIVE: gettimeofday(&STATE_SYNC(commit).stats.start, NULL); @@ -205,7 +205,7 @@ void cache_commit(struct cache *c, struct nfct_handle *h, int clientfd) STATE_SYNC(commit).state = COMMIT_STATE_MASTER; /* give it another step as soon as possible */ write_evfd(STATE_SYNC(commit).evfd); - return; + return 1; } STATE_SYNC(commit).current = 0; STATE_SYNC(commit).state = COMMIT_STATE_RELATED; @@ -219,7 +219,7 @@ void cache_commit(struct cache *c, struct nfct_handle *h, int clientfd) STATE_SYNC(commit).state = COMMIT_STATE_RELATED; /* give it another step as soon as possible */ write_evfd(STATE_SYNC(commit).evfd); - return; + return 1; } /* calculate the time that commit has taken */ gettimeofday(&commit_stop, NULL); @@ -248,6 +248,7 @@ void cache_commit(struct cache *c, struct nfct_handle *h, int clientfd) close(STATE_SYNC(commit).clientfd); STATE_SYNC(commit).clientfd = -1; } + return 1; } static int do_flush(void *data, void *n) diff --git a/src/external_cache.c b/src/external_cache.c index c1181dc..59c706a 100644 --- a/src/external_cache.c +++ b/src/external_cache.c @@ -90,7 +90,10 @@ static void external_cache_dump(int fd, int type) static int external_cache_commit(struct nfct_handle *h, int fd) { - cache_commit(external, h, fd); + if (!cache_commit(external, h, fd)) { + dlog(LOG_NOTICE, "commit already in progress, skipping"); + return LOCAL_RET_OK; + } /* Keep the client socket open, we want synchronous commits. */ return LOCAL_RET_STOLEN; } -- cgit v1.2.3 From dd24e2da2feaacc63e10a375e1909f035ea02543 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 16 Feb 2011 14:25:18 +0100 Subject: conntrackd: event iteration limiter is already reset in main select loop This patch removes an unnecessary reset of the event iteration limiter that is already done in the main select loop. Signed-off-by: Pablo Neira Ayuso --- src/run.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/run.c b/src/run.c index d96ff6c..6dfc8d4 100644 --- a/src/run.c +++ b/src/run.c @@ -282,10 +282,10 @@ static int event_handler(const struct nlmsghdr *nlh, } out: - if (STATE(event_iterations_limit)-- <= 0) { - STATE(event_iterations_limit) = CONFIG(event_iterations_limit); + /* we reset the iteration limiter in the main select loop. */ + if (STATE(event_iterations_limit)-- <= 0) return NFCT_CB_STOP; - } else + else return NFCT_CB_CONTINUE; } -- cgit v1.2.3 From 016bfd317d0984331e53fa71d042af39d3049162 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 16 Feb 2011 17:28:41 +0100 Subject: conntrackd: rise number of committed entries per step This patch rises the number of committed entries per step from 64 to 8192. Experimental results in active-active setups here show that we reduce the commit time with this value significantly. This deserves some more study, it can be a good idea to remove this commit per step completely. I leave this for the future. Signed-off-by: Pablo Neira Ayuso --- src/read_config_yy.y | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/read_config_yy.y b/src/read_config_yy.y index bc76e92..68a83f7 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -1636,7 +1636,7 @@ init_config(char *filename) /* default number of bucket of the hashtable that are committed in one run loop. XXX: no option available to tune this value yet. */ if (CONFIG(general).commit_steps == 0) - CONFIG(general).commit_steps = 64; + CONFIG(general).commit_steps = 8192; /* if overrun, automatically resync with kernel after 30 seconds */ if (CONFIG(nl_overrun_resync) == 0) -- cgit v1.2.3 From 2bbb1655e38646d9a9a6f839d6ca22e4e554d2f2 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 17 Feb 2011 16:46:05 +0100 Subject: conntrack: add -o ktimestamp option (it requires linux >= 2.6.38) This option requires Linux kernel >= 2.6.38, you have to enable conntrack timestamping with: echo 1 > /proc/sys/net/netfilter/nf_conntrack_timestamp # conntrack -L -o ktimestamp udp 17 59 src=192.168.1.128 dst=192.168.1.1 sport=52050 dport=53 src=192.168.1.1 dst=192.168.1.128 sport=53 dport=52050 [ASSURED] mark=0 delta-time=121 [start=Thu Feb 17 17:41:18 2011] use=1 # conntrack -L conntrack v0.9.15 (conntrack-tools): 20 flow entries have been shown. udp 17 31 src=192.168.1.128 dst=192.168.1.1 sport=52050 dport=53 src=192.168.1.1 dst=192.168.1.128 sport=53 dport=52050 [ASSURED] mark=0 delta-time=149 use=1 # conntrack -E -o ktimestamp ... [DESTROY] udp 17 src=192.168.1.128 dst=192.168.1.1 sport=40162 dport=53 src=192.168.1.1 dst=192.168.1.128 sport=53 dport=40162 [ASSURED] delta-time=3 [start=Thu Feb 17 17:44:57 2011] [stop=Thu Feb 17 17:45:00 2011] # conntrack -E [DESTROY] udp 17 src=192.168.1.128 dst=77.226.252.14 sport=123 dport=123 src=77.226.252.14 dst=192.168.1.128 sport=123 dport=123 delta-time=8 Signed-off-by: Pablo Neira Ayuso --- conntrack.8 | 7 +++++-- src/conntrack.c | 9 +++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/conntrack.8 b/conntrack.8 index f485619..0565907 100644 --- a/conntrack.8 +++ b/conntrack.8 @@ -88,8 +88,11 @@ Show the in-kernel connection tracking system statistics. Atomically zero counters after reading them. This option is only valid in combination with the "-L, --dump" command options. .TP -.BI "-o, --output [extended,xml,timestamp,id] " -Display output in a certain format. +.BI "-o, --output [extended,xml,timestamp,id,ktimestamp] " +Display output in a certain format. With the extended output option, this tool +displays the layer 3 information. With ktimestamp, it displays the in-kernel +timestamp available since 2.6.38 (you can enable it via echo 1 > +/proc/sys/net/netfilter/nf_conntrack_timestamp). .TP .BI "-e, --event-mask " "[ALL|NEW|UPDATES|DESTROY][,...]" Set the bitmask of events that are to be generated by the in-kernel ctnetlink diff --git a/src/conntrack.c b/src/conntrack.c index 2527953..9565ee4 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -669,6 +669,7 @@ enum { _O_EXT = (1 << 1), _O_TMS = (1 << 2), _O_ID = (1 << 3), + _O_KTMS = (1 << 4), }; enum { @@ -687,8 +688,8 @@ static struct parse_parameter { { IPS_ASSURED, IPS_SEEN_REPLY, 0, IPS_FIXED_TIMEOUT, IPS_EXPECTED} }, { {"ALL", "NEW", "UPDATES", "DESTROY"}, 4, { CT_EVENT_F_ALL, CT_EVENT_F_NEW, CT_EVENT_F_UPD, CT_EVENT_F_DEL } }, - { {"xml", "extended", "timestamp", "id" }, 4, - { _O_XML, _O_EXT, _O_TMS, _O_ID }, + { {"xml", "extended", "timestamp", "id", "ktimestamp"}, 5, + { _O_XML, _O_EXT, _O_TMS, _O_ID, _O_KTMS }, }, }; @@ -1024,6 +1025,8 @@ static int event_cb(enum nf_conntrack_msg_type type, } else op_flags |= NFCT_OF_TIME; } + if (output_mask & _O_KTMS) + op_flags |= NFCT_OF_TIMESTAMP; if (output_mask & _O_ID) op_flags |= NFCT_OF_ID; @@ -1063,6 +1066,8 @@ static int dump_cb(enum nf_conntrack_msg_type type, } if (output_mask & _O_EXT) op_flags = NFCT_OF_SHOW_LAYER3; + if (output_mask & _O_KTMS) + op_flags |= NFCT_OF_TIMESTAMP; if (output_mask & _O_ID) op_flags |= NFCT_OF_ID; -- cgit v1.2.3 From 6c4ec15505b9fe878ade0b3e7cdbc8f0a26861cd Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 17 Feb 2011 18:29:26 +0100 Subject: conntrackd: use nfct_copy() with override flag in cache_object_new() Using memcpy() is not safe, it breaks secctx and it may break more things in the future. Moreover, nfct_size*() functions will be deprecated soon, they are evil since they open the window to memcpy(). Signed-off-by: Pablo Neira Ayuso --- src/cache.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/cache.c b/src/cache.c index 74c5c4b..f411121 100644 --- a/src/cache.c +++ b/src/cache.c @@ -193,7 +193,7 @@ struct cache_object *cache_object_new(struct cache *c, struct nf_conntrack *ct) c->stats.add_fail_enomem++; return NULL; } - memcpy(obj->ct, ct, nfct_sizeof(ct)); + nfct_copy(obj->ct, ct, NFCT_CP_OVERRIDE); obj->status = C_OBJ_NONE; c->stats.objects++; -- cgit v1.2.3 From 3bb13acbff0983960e06eb33e0daa98c3dab472c Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 17 Feb 2011 19:05:32 +0100 Subject: conntrack: allocate template objects in the heap With this patch, we don't abuse the stack anymore, instead we allocate the template objects that are used in the heap. We stop using nfct_maxsize() which is now deprecated in libnetfilter_conntrack. Signed-off-by: Pablo Neira Ayuso --- src/conntrack.c | 150 +++++++++++++++++++++++++++++++++----------------------- 1 file changed, 89 insertions(+), 61 deletions(-) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index 9565ee4..fe4cbf0 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -58,6 +58,37 @@ #include #include +/* These are the template objects that are used to send commands. */ +static struct { + struct nf_conntrack *ct; + struct nf_expect *exp; + /* Expectations require the expectation tuple and the mask. */ + struct nf_conntrack *exptuple, *mask; +} tmpl; + +static int alloc_tmpl_objects(void) +{ + tmpl.ct = nfct_new(); + tmpl.exptuple = nfct_new(); + tmpl.mask = nfct_new(); + tmpl.exp = nfexp_new(); + + return tmpl.ct != NULL && tmpl.exptuple != NULL && + tmpl.mask != NULL && tmpl.exp != NULL; +} + +static void free_tmpl_objects(void) +{ + if (tmpl.ct) + nfct_destroy(tmpl.ct); + if (tmpl.exptuple) + nfct_destroy(tmpl.exptuple); + if (tmpl.mask) + nfct_destroy(tmpl.mask); + if (tmpl.exp) + nfexp_destroy(tmpl.exp); +} + enum ct_command { CT_NONE = 0, @@ -534,6 +565,8 @@ exit_error(enum exittype status, const char *msg, ...) va_end(args); if (status == PARAMETER_PROBLEM) exit_tryhelp(status); + /* release template objects that were allocated in the setup stage. */ + free_tmpl_objects(); exit(status); } @@ -850,12 +883,12 @@ nat_parse(char *arg, struct nf_conntrack *obj, int type) "Invalid port:port syntax"); if (type == CT_OPT_SRC_NAT) - nfct_set_attr_u16(obj, ATTR_SNAT_PORT, ntohs(port)); + nfct_set_attr_u16(tmpl.ct, ATTR_SNAT_PORT, ntohs(port)); else if (type == CT_OPT_DST_NAT) - nfct_set_attr_u16(obj, ATTR_DNAT_PORT, ntohs(port)); + nfct_set_attr_u16(tmpl.ct, ATTR_DNAT_PORT, ntohs(port)); else if (type == CT_OPT_ANY_NAT) { - nfct_set_attr_u16(obj, ATTR_SNAT_PORT, ntohs(port)); - nfct_set_attr_u16(obj, ATTR_DNAT_PORT, ntohs(port)); + nfct_set_attr_u16(tmpl.ct, ATTR_SNAT_PORT, ntohs(port)); + nfct_set_attr_u16(tmpl.ct, ATTR_DNAT_PORT, ntohs(port)); } } @@ -869,9 +902,9 @@ nat_parse(char *arg, struct nf_conntrack *obj, int type) } if (type == CT_OPT_SRC_NAT || type == CT_OPT_ANY_NAT) - nfct_set_attr_u32(obj, ATTR_SNAT_IPV4, parse.v4); + nfct_set_attr_u32(tmpl.ct, ATTR_SNAT_IPV4, parse.v4); else if (type == CT_OPT_DST_NAT || type == CT_OPT_ANY_NAT) - nfct_set_attr_u32(obj, ATTR_DNAT_IPV4, parse.v4); + nfct_set_attr_u32(tmpl.ct, ATTR_DNAT_IPV4, parse.v4); } static void @@ -1143,11 +1176,7 @@ static int update_cb(enum nf_conntrack_msg_type type, void *data) { int res; - struct nf_conntrack *obj = data; - char __tmp[nfct_maxsize()]; - struct nf_conntrack *tmp = (struct nf_conntrack *) (void *)__tmp; - - memset(tmp, 0, sizeof(__tmp)); + struct nf_conntrack *obj = data, *tmp; if (filter_nat(obj, ct)) return NFCT_CB_CONTINUE; @@ -1161,30 +1190,35 @@ static int update_cb(enum nf_conntrack_msg_type type, if (options & CT_OPT_TUPLE_REPL && !nfct_cmp(obj, ct, NFCT_CMP_REPL)) return NFCT_CB_CONTINUE; + tmp = nfct_new(); + if (tmp == NULL) + exit_error(OTHER_PROBLEM, "out of memory"); + nfct_copy(tmp, ct, NFCT_CP_ORIG); nfct_copy(tmp, obj, NFCT_CP_META); res = nfct_query(ith, NFCT_Q_UPDATE, tmp); - if (res < 0) + if (res < 0) { + nfct_destroy(tmp); exit_error(OTHER_PROBLEM, "Operation failed: %s", err2str(errno, CT_UPDATE)); - + } nfct_callback_register(ith, NFCT_T_ALL, print_cb, NULL); res = nfct_query(ith, NFCT_Q_GET, tmp); if (res < 0) { + nfct_destroy(tmp); /* the entry has vanish in middle of the update */ if (errno == ENOENT) { nfct_callback_unregister(ith); return NFCT_CB_CONTINUE; } - exit_error(OTHER_PROBLEM, "Operation failed: %s", err2str(errno, CT_UPDATE)); } - + nfct_destroy(tmp); nfct_callback_unregister(ith); counter++; @@ -1303,23 +1337,13 @@ int main(int argc, char *argv[]) int res = 0, partial; size_t socketbuffersize = 0; int family = AF_UNSPEC; - char __obj[nfct_maxsize()]; - char __exptuple[nfct_maxsize()]; - char __mask[nfct_maxsize()]; - struct nf_conntrack *obj = (struct nf_conntrack *)(void*) __obj; - struct nf_conntrack *exptuple = - (struct nf_conntrack *)(void*) __exptuple; - struct nf_conntrack *mask = (struct nf_conntrack *)(void*) __mask; - char __exp[nfexp_maxsize()]; - struct nf_expect *exp = (struct nf_expect *)(void*) __exp; int l3protonum, protonum = 0; union ct_address ad; unsigned int command = 0; - memset(__obj, 0, sizeof(__obj)); - memset(__exptuple, 0, sizeof(__exptuple)); - memset(__mask, 0, sizeof(__mask)); - memset(__exp, 0, sizeof(__exp)); + /* we release these objects in the exit_error() path. */ + if (!alloc_tmpl_objects()) + exit_error(OTHER_PROBLEM, "out of memory"); register_tcp(); register_udp(); @@ -1374,15 +1398,15 @@ int main(int argc, char *argv[]) } set_family(&family, l3protonum); if (l3protonum == AF_INET) { - nfct_set_attr_u32(obj, + nfct_set_attr_u32(tmpl.ct, opt2family_attr[c][0], ad.v4); } else if (l3protonum == AF_INET6) { - nfct_set_attr(obj, + nfct_set_attr(tmpl.ct, opt2family_attr[c][1], &ad.v6); } - nfct_set_attr_u8(obj, opt2attr[c], l3protonum); + nfct_set_attr_u8(tmpl.ct, opt2attr[c], l3protonum); break; case '{': case '}': @@ -1396,15 +1420,16 @@ int main(int argc, char *argv[]) } set_family(&family, l3protonum); if (l3protonum == AF_INET) { - nfct_set_attr_u32(mask, + nfct_set_attr_u32(tmpl.mask, opt2family_attr[c][0], ad.v4); } else if (l3protonum == AF_INET6) { - nfct_set_attr(mask, + nfct_set_attr(tmpl.mask, opt2family_attr[c][1], &ad.v6); } - nfct_set_attr_u8(mask, ATTR_ORIG_L3PROTO, l3protonum); + nfct_set_attr_u8(tmpl.mask, + ATTR_ORIG_L3PROTO, l3protonum); break; case 'p': options |= CT_OPT_PROTO; @@ -1418,17 +1443,18 @@ int main(int argc, char *argv[]) if (opts == NULL) exit_error(OTHER_PROBLEM, "out of memory"); - nfct_set_attr_u8(obj, ATTR_L4PROTO, protonum); + nfct_set_attr_u8(tmpl.ct, ATTR_L4PROTO, protonum); break; case 't': options |= CT_OPT_TIMEOUT; - nfct_set_attr_u32(obj, ATTR_TIMEOUT, atol(optarg)); - nfexp_set_attr_u32(exp, ATTR_EXP_TIMEOUT, atol(optarg)); + nfct_set_attr_u32(tmpl.ct, ATTR_TIMEOUT, atol(optarg)); + nfexp_set_attr_u32(tmpl.exp, + ATTR_EXP_TIMEOUT, atol(optarg)); break; case 'u': options |= CT_OPT_STATUS; parse_parameter(optarg, &status, PARSE_STATUS); - nfct_set_attr_u32(obj, ATTR_STATUS, status); + nfct_set_attr_u32(tmpl.ct, ATTR_STATUS, status); break; case 'e': options |= CT_OPT_EVENT_MASK; @@ -1458,12 +1484,12 @@ int main(int argc, char *argv[]) continue; set_family(&family, AF_INET); - nat_parse(tmp, obj, opt2type[c]); + nat_parse(tmp, tmpl.ct, opt2type[c]); break; } case 'w': options |= opt2type[c]; - nfct_set_attr_u16(obj, + nfct_set_attr_u16(tmpl.ct, opt2attr[c], strtoul(optarg, NULL, 0)); break; @@ -1471,7 +1497,7 @@ int main(int argc, char *argv[]) case 'm': case 'c': options |= opt2type[c]; - nfct_set_attr_u32(obj, + nfct_set_attr_u32(tmpl.ct, opt2attr[c], strtoul(optarg, NULL, 0)); break; @@ -1506,8 +1532,9 @@ int main(int argc, char *argv[]) break; default: if (h && h->parse_opts - &&!h->parse_opts(c - h->option_offset, obj, - exptuple, mask, &l4flags)) + &&!h->parse_opts(c - h->option_offset, tmpl.ct, + tmpl.exptuple, tmpl.mask, + &l4flags)) exit_error(PARAMETER_PROBLEM, "parse error"); break; } @@ -1543,7 +1570,7 @@ int main(int argc, char *argv[]) } } if (!(command & CT_HELP) && h && h->final_check) - h->final_check(l4flags, cmd, obj); + h->final_check(l4flags, cmd, tmpl.ct); switch(command) { @@ -1557,7 +1584,7 @@ int main(int argc, char *argv[]) exit_error(PARAMETER_PROBLEM, "Can't use -z with " "filtering parameters"); - nfct_callback_register(cth, NFCT_T_ALL, dump_cb, obj); + nfct_callback_register(cth, NFCT_T_ALL, dump_cb, tmpl.ct); if (options & CT_OPT_ZERO) res = nfct_query(cth, NFCT_Q_DUMP_RESET, &family); @@ -1584,30 +1611,30 @@ int main(int argc, char *argv[]) case CT_CREATE: if ((options & CT_OPT_ORIG) && !(options & CT_OPT_REPL)) - nfct_setobjopt(obj, NFCT_SOPT_SETUP_REPLY); + nfct_setobjopt(tmpl.ct, NFCT_SOPT_SETUP_REPLY); else if (!(options & CT_OPT_ORIG) && (options & CT_OPT_REPL)) - nfct_setobjopt(obj, NFCT_SOPT_SETUP_ORIGINAL); + nfct_setobjopt(tmpl.ct, NFCT_SOPT_SETUP_ORIGINAL); cth = nfct_open(CONNTRACK, 0); if (!cth) exit_error(OTHER_PROBLEM, "Can't open handler"); - res = nfct_query(cth, NFCT_Q_CREATE, obj); + res = nfct_query(cth, NFCT_Q_CREATE, tmpl.ct); if (res != -1) counter++; nfct_close(cth); break; case EXP_CREATE: - nfexp_set_attr(exp, ATTR_EXP_MASTER, obj); - nfexp_set_attr(exp, ATTR_EXP_EXPECTED, exptuple); - nfexp_set_attr(exp, ATTR_EXP_MASK, mask); + nfexp_set_attr(tmpl.exp, ATTR_EXP_MASTER, tmpl.ct); + nfexp_set_attr(tmpl.exp, ATTR_EXP_EXPECTED, tmpl.exptuple); + nfexp_set_attr(tmpl.exp, ATTR_EXP_MASK, tmpl.mask); cth = nfct_open(EXPECT, 0); if (!cth) exit_error(OTHER_PROBLEM, "Can't open handler"); - res = nfexp_query(cth, NFCT_Q_CREATE, exp); + res = nfexp_query(cth, NFCT_Q_CREATE, tmpl.exp); nfct_close(cth); break; @@ -1618,7 +1645,7 @@ int main(int argc, char *argv[]) if (!cth || !ith) exit_error(OTHER_PROBLEM, "Can't open handler"); - nfct_callback_register(cth, NFCT_T_ALL, update_cb, obj); + nfct_callback_register(cth, NFCT_T_ALL, update_cb, tmpl.ct); res = nfct_query(cth, NFCT_Q_DUMP, &family); nfct_close(ith); @@ -1631,7 +1658,7 @@ int main(int argc, char *argv[]) if (!cth || !ith) exit_error(OTHER_PROBLEM, "Can't open handler"); - nfct_callback_register(cth, NFCT_T_ALL, delete_cb, obj); + nfct_callback_register(cth, NFCT_T_ALL, delete_cb, tmpl.ct); res = nfct_query(cth, NFCT_Q_DUMP, &family); nfct_close(ith); @@ -1639,13 +1666,13 @@ int main(int argc, char *argv[]) break; case EXP_DELETE: - nfexp_set_attr(exp, ATTR_EXP_EXPECTED, obj); + nfexp_set_attr(tmpl.exp, ATTR_EXP_EXPECTED, tmpl.ct); cth = nfct_open(EXPECT, 0); if (!cth) exit_error(OTHER_PROBLEM, "Can't open handler"); - res = nfexp_query(cth, NFCT_Q_DESTROY, exp); + res = nfexp_query(cth, NFCT_Q_DESTROY, tmpl.exp); nfct_close(cth); break; @@ -1654,20 +1681,20 @@ int main(int argc, char *argv[]) if (!cth) exit_error(OTHER_PROBLEM, "Can't open handler"); - nfct_callback_register(cth, NFCT_T_ALL, dump_cb, obj); - res = nfct_query(cth, NFCT_Q_GET, obj); + nfct_callback_register(cth, NFCT_T_ALL, dump_cb, tmpl.ct); + res = nfct_query(cth, NFCT_Q_GET, tmpl.ct); nfct_close(cth); break; case EXP_GET: - nfexp_set_attr(exp, ATTR_EXP_MASTER, obj); + nfexp_set_attr(tmpl.exp, ATTR_EXP_MASTER, tmpl.ct); cth = nfct_open(EXPECT, 0); if (!cth) exit_error(OTHER_PROBLEM, "Can't open handler"); nfexp_callback_register(cth, NFCT_T_ALL, dump_exp_cb, NULL); - res = nfexp_query(cth, NFCT_Q_GET, exp); + res = nfexp_query(cth, NFCT_Q_GET, tmpl.exp); nfct_close(cth); break; @@ -1719,7 +1746,7 @@ int main(int argc, char *argv[]) } signal(SIGINT, event_sighandler); signal(SIGTERM, event_sighandler); - nfct_callback_register(cth, NFCT_T_ALL, event_cb, obj); + nfct_callback_register(cth, NFCT_T_ALL, event_cb, tmpl.ct); res = nfct_catch(cth); if (res == -1) { if (errno == ENOBUFS) { @@ -1810,6 +1837,7 @@ int main(int argc, char *argv[]) exit_error(OTHER_PROBLEM, "Operation failed: %s", err2str(errno, command)); + free_tmpl_objects(); free_options(); if (command && exit_msg[cmd][0]) { -- cgit v1.2.3 From 4dd7a3c15830aa21548716798171e67cb14bca49 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 18 Feb 2011 12:15:52 +0100 Subject: conntrackd: remove use of deprecated nfct_maxsize() This patch removes the use of nfct_maxsize() and several abusive stack-based allocations. Signed-off-by: Pablo Neira Ayuso --- src/netlink.c | 17 +++++++++-------- src/sync-mode.c | 10 +++++++--- 2 files changed, 16 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/netlink.c b/src/netlink.c index 1810f4a..60274f3 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -164,20 +164,21 @@ int nl_send_resync(struct nfct_handle *h) /* if the handle has no callback, check for existence, otherwise, update */ int nl_get_conntrack(struct nfct_handle *h, const struct nf_conntrack *ct) { - int ret; - char __tmp[nfct_maxsize()]; - struct nf_conntrack *tmp = (struct nf_conntrack *) (void *)__tmp; + int ret = 1; + struct nf_conntrack *tmp; - memset(__tmp, 0, sizeof(__tmp)); + tmp = nfct_new(); + if (tmp == NULL) + return -1; /* use the original tuple to check if it is there */ nfct_copy(tmp, ct, NFCT_CP_ORIG); - ret = nfct_query(h, NFCT_Q_GET, tmp); - if (ret == -1) - return errno == ENOENT ? 0 : -1; + if (nfct_query(h, NFCT_Q_GET, tmp) == -1) + ret = (errno == ENOENT) ? 0 : -1; - return 1; + nfct_destroy(tmp); + return ret; } int nl_create_conntrack(struct nfct_handle *h, diff --git a/src/sync-mode.c b/src/sync-mode.c index 4b48449..5351110 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -43,8 +43,7 @@ static void do_channel_handler_step(int i, struct nethdr *net, size_t remain) { - char __ct[nfct_maxsize()]; - struct nf_conntrack *ct = (struct nf_conntrack *)(void*) __ct; + struct nf_conntrack *ct; if (net->version != CONNTRACKD_PROTOCOL_VERSION) { STATE_SYNC(error).msg_rcv_malformed++; @@ -74,11 +73,15 @@ do_channel_handler_step(int i, struct nethdr *net, size_t remain) STATE_SYNC(error).msg_rcv_bad_type++; return; } - memset(ct, 0, sizeof(__ct)); + /* TODO: add stats on ENOMEM errors in the future. */ + ct = nfct_new(); + if (ct == NULL) + return; if (parse_payload(ct, net, remain) == -1) { STATE_SYNC(error).msg_rcv_malformed++; STATE_SYNC(error).msg_rcv_bad_payload++; + nfct_destroy(ct); return; } @@ -97,6 +100,7 @@ do_channel_handler_step(int i, struct nethdr *net, size_t remain) STATE_SYNC(error).msg_rcv_bad_type++; break; } + nfct_destroy(ct); } static char __net[65536]; /* XXX: maximum MTU for IPv4 */ -- cgit v1.2.3 From 88fd3dc90716e9d252cedcd668371743730acdcb Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 22 Feb 2011 15:34:59 +0100 Subject: conntrack: display informative message if expectation table is flushed With this patch, we display the following message after: # conntrack -F expect conntrack v0.9.15 (conntrack-tools): expectation table has been emptied. To make it consistent with the message displayed with conntrack -F. Signed-off-by: Pablo Neira Ayuso --- src/conntrack.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index fe4cbf0..aca36eb 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -1714,6 +1714,8 @@ int main(int argc, char *argv[]) exit_error(OTHER_PROBLEM, "Can't open handler"); res = nfexp_query(cth, NFCT_Q_FLUSH, &family); nfct_close(cth); + fprintf(stderr, "%s v%s (conntrack-tools): ",PROGNAME,VERSION); + fprintf(stderr,"expectation table has been emptied.\n"); break; case CT_EVENT: -- cgit v1.2.3 From 147ed522f52a62ab0d854ddc443d27d97dbf6cdf Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Wed, 15 Jun 2011 14:13:39 +0200 Subject: conntrack: add support for mark mask Extend --mark option to optionally take a mask, seperated by '/', e.g. --mark 0x80/0xf0. When used with -L, only test those bits of the mark that are in the mask range (behaves like iptables like -m mark). When used with -U, zero out those bits indicated by the mask and XOR the new mark into the result (behaves like iptables -j MARK --set-xmark). Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- conntrack.8 | 8 +++++-- src/conntrack.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 73 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/conntrack.8 b/conntrack.8 index 0565907..6525123 100644 --- a/conntrack.8 +++ b/conntrack.8 @@ -135,8 +135,12 @@ This option is only required in conjunction with "-L, --dump". If this option is .BI "-t, --timeout " "TIMEOUT" Specify the timeout. .TP -.BI "-m, --mark " "MARK" -Specify the conntrack mark. +.BI "-m, --mark " "MARK[/MASK]" +Specify the conntrack mark. Optionally, a mask value can be specified. +In "--update" mode, this mask specifies the bits that should be zeroed before XORing +the MARK value into the ctmark. +Otherwise, the mask is logically ANDed with the existing mark before the comparision. +In "--create" mode, the mask is ignored. .TP .BI "-c, --secmark " "SECMARK" Specify the conntrack selinux security mark. diff --git a/src/conntrack.c b/src/conntrack.c index aca36eb..fb133f1 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -58,12 +58,20 @@ #include #include +struct u32_mask { + uint32_t value; + uint32_t mask; +}; + /* These are the template objects that are used to send commands. */ static struct { struct nf_conntrack *ct; struct nf_expect *exp; /* Expectations require the expectation tuple and the mask. */ struct nf_conntrack *exptuple, *mask; + + /* Allows filtering/setting specific bits in the ctmark */ + struct u32_mask mark; } tmpl; static int alloc_tmpl_objects(void) @@ -73,6 +81,8 @@ static int alloc_tmpl_objects(void) tmpl.mask = nfct_new(); tmpl.exp = nfexp_new(); + memset(&tmpl.mark, 0, sizeof(tmpl.mark)); + return tmpl.ct != NULL && tmpl.exptuple != NULL && tmpl.mask != NULL && tmpl.exp != NULL; } @@ -692,6 +702,12 @@ err2str(int err, enum ct_command command) return strerror(err); } +static int mark_cmp(const struct u32_mask *m, const struct nf_conntrack *ct) +{ + return nfct_attr_is_set(ct, ATTR_MARK) && + (nfct_get_attr_u32(ct, ATTR_MARK) & m->mask) == m->value; +} + #define PARSE_STATUS 0 #define PARSE_EVENT 1 #define PARSE_OUTPUT 2 @@ -773,6 +789,19 @@ parse_parameter(const char *arg, unsigned int *status, int parse_type) exit_error(PARAMETER_PROBLEM, "Bad parameter `%s'", arg); } +static void +parse_u32_mask(const char *arg, struct u32_mask *m) +{ + char *end; + + m->value = (uint32_t) strtoul(arg, &end, 0); + + if (*end == '/') + m->mask = (uint32_t) strtoul(end+1, NULL, 0); + else + m->mask = ~0; +} + static void add_command(unsigned int *cmd, const int newcmd) { @@ -923,6 +952,17 @@ usage(char *prog) static unsigned int output_mask; + +static int +filter_mark(const struct nf_conntrack *ct) +{ + if ((options & CT_OPT_MARK) && + !mark_cmp(&tmpl.mark, ct)) + return 1; + return 0; +} + + static int filter_nat(const struct nf_conntrack *obj, const struct nf_conntrack *ct) { @@ -1036,6 +1076,9 @@ static int event_cb(enum nf_conntrack_msg_type type, if (filter_nat(obj, ct)) return NFCT_CB_CONTINUE; + if (filter_mark(ct)) + return NFCT_CB_CONTINUE; + if (options & CT_COMPARISON && !nfct_cmp(obj, ct, NFCT_CMP_ALL | NFCT_CMP_MASK)) return NFCT_CB_CONTINUE; @@ -1085,6 +1128,9 @@ static int dump_cb(enum nf_conntrack_msg_type type, if (filter_nat(obj, ct)) return NFCT_CB_CONTINUE; + if (filter_mark(ct)) + return NFCT_CB_CONTINUE; + if (options & CT_COMPARISON && !nfct_cmp(obj, ct, NFCT_CMP_ALL | NFCT_CMP_MASK)) return NFCT_CB_CONTINUE; @@ -1125,6 +1171,9 @@ static int delete_cb(enum nf_conntrack_msg_type type, if (filter_nat(obj, ct)) return NFCT_CB_CONTINUE; + if (filter_mark(ct)) + return NFCT_CB_CONTINUE; + if (options & CT_COMPARISON && !nfct_cmp(obj, ct, NFCT_CMP_ALL | NFCT_CMP_MASK)) return NFCT_CB_CONTINUE; @@ -1171,6 +1220,17 @@ static int print_cb(enum nf_conntrack_msg_type type, return NFCT_CB_CONTINUE; } +static void copy_mark(struct nf_conntrack *tmp, + const struct nf_conntrack *ct, + const struct u32_mask *m) +{ + if (options & CT_OPT_MARK) { + uint32_t mark = nfct_get_attr_u32(ct, ATTR_MARK); + mark = (mark & ~m->mask) ^ m->value; + nfct_set_attr_u32(tmp, ATTR_MARK, mark); + } +} + static int update_cb(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data) @@ -1196,6 +1256,7 @@ static int update_cb(enum nf_conntrack_msg_type type, nfct_copy(tmp, ct, NFCT_CP_ORIG); nfct_copy(tmp, obj, NFCT_CP_META); + copy_mark(tmp, ct, &tmpl.mark); res = nfct_query(ith, NFCT_Q_UPDATE, tmp); if (res < 0) { @@ -1494,12 +1555,14 @@ int main(int argc, char *argv[]) strtoul(optarg, NULL, 0)); break; case 'i': - case 'm': case 'c': options |= opt2type[c]; nfct_set_attr_u32(tmpl.ct, opt2attr[c], strtoul(optarg, NULL, 0)); + case 'm': + options |= opt2type[c]; + parse_u32_mask(optarg, &tmpl.mark); break; case 'a': fprintf(stderr, "WARNING: ignoring -%c, " @@ -1615,6 +1678,9 @@ int main(int argc, char *argv[]) else if (!(options & CT_OPT_ORIG) && (options & CT_OPT_REPL)) nfct_setobjopt(tmpl.ct, NFCT_SOPT_SETUP_ORIGINAL); + if (options & CT_OPT_MARK) + nfct_set_attr_u32(tmpl.ct, ATTR_MARK, tmpl.mark.value); + cth = nfct_open(CONNTRACK, 0); if (!cth) exit_error(OTHER_PROBLEM, "Can't open handler"); -- cgit v1.2.3 From 6428f54328a433a86bdc0d7154ff3a7d322e0fb4 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Wed, 15 Jun 2011 14:13:40 +0200 Subject: conntrack: skip sending update message to kernel if conntrack is unchanged This speeds up operation when a lot of conntracks exist, but only a few of them have to be altered. This change is user-visible because the exit message ("%d flow entries have been updated") will now print the number of entries that have been altered instead of the total number of conntracks seen. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- src/conntrack.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index fb133f1..3e1cb11 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -1258,6 +1258,12 @@ static int update_cb(enum nf_conntrack_msg_type type, nfct_copy(tmp, obj, NFCT_CP_META); copy_mark(tmp, ct, &tmpl.mark); + /* do not send NFCT_Q_UPDATE if ct appears unchanged */ + if (nfct_cmp(tmp, ct, NFCT_CMP_ALL | NFCT_CMP_MASK)) { + nfct_destroy(tmp); + return NFCT_CB_CONTINUE; + } + res = nfct_query(ith, NFCT_Q_UPDATE, tmp); if (res < 0) { nfct_destroy(tmp); -- cgit v1.2.3 From 4904bbeff9b575d17678ff839583662c9f7b12c4 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 22 Jun 2011 11:21:01 +0200 Subject: conntrack: remove unused variable with -S Error: UNUSED_VALUE: conntrack-tools-1.0.0/src/conntrack.c:1297: returned_pointer: Pointer "nl" returned by "strchr(buf, 10)" is never used. Reported-by: Jiri Popelka Signed-off-by: Pablo Neira Ayuso --- src/conntrack.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index 3e1cb11..b695da4 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -1359,10 +1359,9 @@ static int display_proc_conntrack_stats(void) /* trim off trailing \n */ nl = strchr(buf, '\n'); - if (nl != NULL) { + if (nl != NULL) *nl = '\0'; - nl = strchr(buf, '\n'); - } + token = strtok(buf, " "); for (i=0; token != NULL && i Date: Wed, 15 Jun 2011 23:39:07 +0200 Subject: conntrack: add missing break when parsing --id/--secmark options commit 147ed522f52a62ab0d854ddc443d27d97dbf6cdf (conntrack: add support for mark mask) failed to add a break after secmark/id option parsing. Results in '-m 42 -c 1' to search for mark 1 instead of 42. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- src/conntrack.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index b695da4..5364eaa 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -1565,6 +1565,7 @@ int main(int argc, char *argv[]) nfct_set_attr_u32(tmpl.ct, opt2attr[c], strtoul(optarg, NULL, 0)); + break; case 'm': options |= opt2type[c]; parse_u32_mask(optarg, &tmpl.mark); -- cgit v1.2.3 From 482c167dffd033915f693c13eb3c47e6f6f77a27 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 24 Oct 2011 12:01:26 +0200 Subject: conntrackd: add missing initial caching of gettimeofday() Thus, we fix conntrackd -i for flows that were just retrieved from the kernel: tcp 6 ESTABLISHED src=192.168.1.135 dst=208.68.163.220 sport=42179 dport=5222 src=208.68.163.220 dst=192.168.1.135 sport=5222 dport=42179 [ASSURED] mark=0 [active since 1319450515s] Note the wrong "active since" value. Signed-off-by: Pablo Neira Ayuso --- src/run.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/run.c b/src/run.c index 6dfc8d4..265a949 100644 --- a/src/run.c +++ b/src/run.c @@ -321,6 +321,8 @@ static int get_handler(enum nf_conntrack_msg_type type, int init(void) { + do_gettimeofday(); + if (CONFIG(flags) & CTD_STATS_MODE) STATE(mode) = &stats_mode; else if (CONFIG(flags) & CTD_SYNC_MODE) -- cgit v1.2.3 From 6612fe8d073bf292f5dc7f6271c76f714e81d9d1 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 19 Dec 2011 18:52:31 +0100 Subject: conntrackd: fix filtering of dump output if internal cache is disabled Signed-off-by: Pablo Neira Ayuso --- src/internal_bypass.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/internal_bypass.c b/src/internal_bypass.c index 4caaf4f..1e1478f 100644 --- a/src/internal_bypass.c +++ b/src/internal_bypass.c @@ -31,6 +31,9 @@ static int dump_cb(enum nf_conntrack_msg_type type, char buf[1024]; int size, *fd = data; + if (ct_filter_conntrack(ct, 1)) + return NFCT_CB_CONTINUE; + size = nfct_snprintf(buf, 1024, ct, NFCT_T_UNKNOWN, NFCT_O_DEFAULT, 0); if (size < 1024) { buf[size] = '\n'; -- cgit v1.2.3 From 8da00687d65f06160827e4cd469c330d3a73a9d9 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 4 Jan 2012 14:16:57 +0100 Subject: conntrackd: fix checking of return value of queue_add() Most callers of queue_add() assume that it returns != 0 in case of success. However, it may return -1 in case that the queue gets full. In that case, most callers have to: - release the object that they want to enqueue. - decrement the refcount, in case they have bumped it. However, most of these callers are using the tx_queue which currently has no limit in size at all. This fix is necessary in case that I decide to limit the size of the transmission queue in the future (which makes a lot of sense indeed). Signed-off-by: Pablo Neira Ayuso --- src/sync-alarm.c | 2 +- src/sync-ftfw.c | 10 ++++++---- src/sync-notrack.c | 10 ++++++---- 3 files changed, 13 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/sync-alarm.c b/src/sync-alarm.c index 0fc7943..b555dd5 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -111,7 +111,7 @@ static void alarm_enqueue(struct cache_object *obj, int query) { struct cache_alarm *ca = cache_get_extra(STATE(mode)->internal->data, obj); - if (queue_add(STATE_SYNC(tx_queue), &ca->qnode)) + if (queue_add(STATE_SYNC(tx_queue), &ca->qnode) > 0) cache_object_get(obj); } diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 86edeab..581b5ca 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -107,7 +107,8 @@ static void tx_queue_add_ctlmsg(uint32_t flags, uint32_t from, uint32_t to) ack->from = from; ack->to = to; - queue_add(STATE_SYNC(tx_queue), &qobj->qnode); + if (queue_add(STATE_SYNC(tx_queue), &qobj->qnode) < 0) + queue_object_free(qobj); } static void tx_queue_add_ctlmsg2(uint32_t flags) @@ -123,7 +124,8 @@ static void tx_queue_add_ctlmsg2(uint32_t flags) ctl->type = NET_T_CTL; ctl->flags = flags; - queue_add(STATE_SYNC(tx_queue), &qobj->qnode); + if (queue_add(STATE_SYNC(tx_queue), &qobj->qnode) < 0) + queue_object_free(qobj); } /* this function is called from the alarm framework */ @@ -173,7 +175,7 @@ static int do_cache_to_tx(void *data1, void *data2) queue_del(&cn->qnode); queue_add(STATE_SYNC(tx_queue), &cn->qnode); } else { - if (queue_add(STATE_SYNC(tx_queue), &cn->qnode)) + if (queue_add(STATE_SYNC(tx_queue), &cn->qnode) > 0) cache_object_get(obj); } return 0; @@ -554,7 +556,7 @@ static void ftfw_enqueue(struct cache_object *obj, int type) queue_del(&cn->qnode); queue_add(STATE_SYNC(tx_queue), &cn->qnode); } else { - if (queue_add(STATE_SYNC(tx_queue), &cn->qnode)) + if (queue_add(STATE_SYNC(tx_queue), &cn->qnode) > 0) cache_object_get(obj); } } diff --git a/src/sync-notrack.c b/src/sync-notrack.c index c4ad941..06af58b 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -68,7 +68,8 @@ static void tx_queue_add_ctlmsg(uint32_t flags, uint32_t from, uint32_t to) ack->from = from; ack->to = to; - queue_add(STATE_SYNC(tx_queue), &qobj->qnode); + if (queue_add(STATE_SYNC(tx_queue), &qobj->qnode) < 0) + queue_object_free(qobj); } static int do_cache_to_tx(void *data1, void *data2) @@ -76,7 +77,7 @@ static int do_cache_to_tx(void *data1, void *data2) struct cache_object *obj = data2; struct cache_notrack *cn = cache_get_extra(STATE(mode)->internal->data, obj); - if (queue_add(STATE_SYNC(tx_queue), &cn->qnode)) + if (queue_add(STATE_SYNC(tx_queue), &cn->qnode) > 0) cache_object_get(obj); return 0; } @@ -219,7 +220,7 @@ static void notrack_enqueue(struct cache_object *obj, int query) { struct cache_notrack *cn = cache_get_extra(STATE(mode)->internal->data, obj); - if (queue_add(STATE_SYNC(tx_queue), &cn->qnode)) + if (queue_add(STATE_SYNC(tx_queue), &cn->qnode) > 0) cache_object_get(obj); } @@ -236,7 +237,8 @@ static void tx_queue_add_ctlmsg2(uint32_t flags) ctl->type = NET_T_CTL; ctl->flags = flags; - queue_add(STATE_SYNC(tx_queue), &qobj->qnode); + if (queue_add(STATE_SYNC(tx_queue), &qobj->qnode) < 0) + queue_object_free(qobj); } static void do_alive_alarm(struct alarm_block *a, void *data) -- cgit v1.2.3 From 65be3d49b0f4350a227dedd70ac17c7c9cf6274e Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 4 Jan 2012 14:28:50 +0100 Subject: conntrackd: generalize caching infrastructure This patch generalizes the caching infrastructure to store different object types. This patch is the first in the series to prepare support for the synchronization of expectations. Signed-off-by: Pablo Neira Ayuso --- include/cache.h | 57 +++++++- include/internal.h | 27 ++-- src/Makefile.am | 2 +- src/cache-ct.c | 358 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/cache.c | 154 +++++++++------------- src/cache_iterators.c | 268 ------------------------------------- src/external_cache.c | 4 +- src/internal_bypass.c | 67 +++++----- src/internal_cache.c | 104 ++++++++------- src/run.c | 23 ++-- src/stats-mode.c | 42 +++--- src/sync-alarm.c | 11 +- src/sync-ftfw.c | 23 ++-- src/sync-mode.c | 19 +-- src/sync-notrack.c | 12 +- 15 files changed, 647 insertions(+), 524 deletions(-) create mode 100644 src/cache-ct.c delete mode 100644 src/cache_iterators.c (limited to 'src') diff --git a/include/cache.h b/include/cache.h index ddf2049..a42e395 100644 --- a/include/cache.h +++ b/include/cache.h @@ -27,7 +27,7 @@ enum { struct cache; struct cache_object { struct hashtable_node hashnode; - struct nf_conntrack *ct; + void *ptr; struct cache *cache; int status; int refcnt; @@ -48,14 +48,22 @@ extern struct cache_feature timer_feature; #define CACHE_MAX_NAMELEN 32 +enum cache_type { + CACHE_T_NONE = 0, + CACHE_T_CT, + CACHE_T_MAX +}; + struct cache { char name[CACHE_MAX_NAMELEN]; + enum cache_type type; struct hashtable *h; unsigned int num_features; struct cache_feature **features; unsigned int feature_type[CACHE_MAX_FEATURE]; unsigned int *feature_offset; + struct cache_ops *ops; struct cache_extra *extra; unsigned int extra_offset; size_t object_size; @@ -94,22 +102,48 @@ struct cache_extra { void (*destroy)(struct cache_object *obj, void *data); }; +struct nfct_handle; + +/* cache options depends on the object type: conntrack or expectation. */ +struct cache_ops { + /* hashing and comparison of objects. */ + uint32_t (*hash)(const void *data, const struct hashtable *table); + int (*cmp)(const void *data1, const void *data2); + + /* object allocation, copy and release. */ + void *(*alloc)(void); + void (*copy)(void *dst, void *src, unsigned int flags); + void (*free)(void *ptr); + + /* dump and commit. */ + int (*dump_step)(void *data1, void *n); + int (*commit)(struct cache *c, struct nfct_handle *h, int clientfd); + + /* build network message from object. */ + struct nethdr *(*build_msg)(const struct cache_object *obj, int type); +}; + +/* templates to configure conntrack caching. */ +extern struct cache_ops cache_sync_internal_ct_ops; +extern struct cache_ops cache_sync_external_ct_ops; +extern struct cache_ops cache_stats_ct_ops; + struct nf_conntrack; -struct cache *cache_create(const char *name, unsigned int features, struct cache_extra *extra); +struct cache *cache_create(const char *name, enum cache_type type, unsigned int features, struct cache_extra *extra, struct cache_ops *ops); void cache_destroy(struct cache *e); -struct cache_object *cache_object_new(struct cache *c, struct nf_conntrack *ct); +struct cache_object *cache_object_new(struct cache *c, void *ptr); void cache_object_free(struct cache_object *obj); void cache_object_get(struct cache_object *obj); int cache_object_put(struct cache_object *obj); void cache_object_set_status(struct cache_object *obj, int status); int cache_add(struct cache *c, struct cache_object *obj, int id); -void cache_update(struct cache *c, struct cache_object *obj, int id, struct nf_conntrack *ct); -struct cache_object *cache_update_force(struct cache *c, struct nf_conntrack *ct); +void cache_update(struct cache *c, struct cache_object *obj, int id, void *ptr); +struct cache_object *cache_update_force(struct cache *c, void *ptr); void cache_del(struct cache *c, struct cache_object *obj); -struct cache_object *cache_find(struct cache *c, struct nf_conntrack *ct, int *pos); +struct cache_object *cache_find(struct cache *c, void *ptr, int *pos); void cache_stats(const struct cache *c, int fd); void cache_stats_extended(const struct cache *c, int fd); struct cache_object *cache_data_get_object(struct cache *c, void *data); @@ -120,7 +154,18 @@ void cache_iterate_limit(struct cache *c, void *data, uint32_t from, uint32_t st /* iterators */ struct nfct_handle; +struct __dump_container { + int fd; + int type; +}; + void cache_dump(struct cache *c, int fd, int type); + +struct __commit_container { + struct nfct_handle *h; + struct cache *c; +}; + int cache_commit(struct cache *c, struct nfct_handle *h, int clientfd); void cache_flush(struct cache *c); void cache_bulk(struct cache *c); diff --git a/include/internal.h b/include/internal.h index 1f11340..f50eb79 100644 --- a/include/internal.h +++ b/include/internal.h @@ -12,25 +12,28 @@ enum { }; struct internal_handler { - void *data; unsigned int flags; int (*init)(void); void (*close)(void); - void (*new)(struct nf_conntrack *ct, int origin_type); - void (*update)(struct nf_conntrack *ct, int origin_type); - int (*destroy)(struct nf_conntrack *ct, int origin_type); + struct { + void *data; - void (*dump)(int fd, int type); - void (*populate)(struct nf_conntrack *ct); - void (*purge)(void); - int (*resync)(enum nf_conntrack_msg_type type, - struct nf_conntrack *ct, void *data); - void (*flush)(void); + void (*new)(struct nf_conntrack *ct, int origin_type); + void (*upd)(struct nf_conntrack *ct, int origin_type); + int (*del)(struct nf_conntrack *ct, int origin_type); - void (*stats)(int fd); - void (*stats_ext)(int fd); + void (*dump)(int fd, int type); + void (*populate)(struct nf_conntrack *ct); + void (*purge)(void); + int (*resync)(enum nf_conntrack_msg_type type, + struct nf_conntrack *ct, void *data); + void (*flush)(void); + + void (*stats)(int fd); + void (*stats_ext)(int fd); + } ct; }; extern struct internal_handler internal_cache; diff --git a/src/Makefile.am b/src/Makefile.am index 70e496d..a0abeee 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -12,7 +12,7 @@ conntrack_LDADD = ../extensions/libct_proto_tcp.la ../extensions/libct_proto_udp conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c rbtree.c \ local.c log.c mcast.c udp.c netlink.c vector.c \ filter.c fds.c event.c process.c origin.c date.c \ - cache.c cache_iterators.c \ + cache.c cache-ct.c \ cache_timer.c \ sync-mode.c sync-alarm.c sync-ftfw.c sync-notrack.c \ traffic_stats.c stats-mode.c \ diff --git a/src/cache-ct.c b/src/cache-ct.c new file mode 100644 index 0000000..2c6fd4e --- /dev/null +++ b/src/cache-ct.c @@ -0,0 +1,358 @@ +/* + * (C) 2006-2011 by Pablo Neira Ayuso + * (C) 2011 by Vyatta Inc. + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "cache.h" +#include "hash.h" +#include "log.h" +#include "conntrackd.h" +#include "netlink.h" +#include "event.h" +#include "jhash.h" +#include "network.h" + +#include +#include +#include +#include + +static uint32_t +cache_hash4_ct(const struct nf_conntrack *ct, const struct hashtable *table) +{ + uint32_t a[4] = { + [0] = nfct_get_attr_u32(ct, ATTR_IPV4_SRC), + [1] = nfct_get_attr_u32(ct, ATTR_IPV4_DST), + [2] = nfct_get_attr_u8(ct, ATTR_L3PROTO) << 16 | + nfct_get_attr_u8(ct, ATTR_L4PROTO), + [3] = nfct_get_attr_u16(ct, ATTR_PORT_SRC) << 16 | + nfct_get_attr_u16(ct, ATTR_PORT_DST), + }; + + /* + * Instead of returning hash % table->hashsize (implying a divide) + * we return the high 32 bits of the (hash * table->hashsize) that will + * give results between [0 and hashsize-1] and same hash distribution, + * but using a multiply, less expensive than a divide. See: + * http://www.mail-archive.com/netdev@vger.kernel.org/msg56623.html + */ + return ((uint64_t)jhash2(a, 4, 0) * table->hashsize) >> 32; +} + +static uint32_t +cache_hash6_ct(const struct nf_conntrack *ct, const struct hashtable *table) +{ + uint32_t a[10]; + + memcpy(&a[0], nfct_get_attr(ct, ATTR_IPV6_SRC), sizeof(uint32_t)*4); + memcpy(&a[4], nfct_get_attr(ct, ATTR_IPV6_SRC), sizeof(uint32_t)*4); + a[8] = nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO) << 16 | + nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO); + a[9] = nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC) << 16 | + nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST); + + return ((uint64_t)jhash2(a, 10, 0) * table->hashsize) >> 32; +} + +static uint32_t +cache_ct_hash(const void *data, const struct hashtable *table) +{ + int ret = 0; + const struct nf_conntrack *ct = data; + + switch(nfct_get_attr_u8(ct, ATTR_L3PROTO)) { + case AF_INET: + ret = cache_hash4_ct(ct, table); + break; + case AF_INET6: + ret = cache_hash6_ct(ct, table); + break; + default: + dlog(LOG_ERR, "unknown layer 3 proto in hash"); + break; + } + return ret; +} + +static int cache_ct_cmp(const void *data1, const void *data2) +{ + const struct cache_object *obj = data1; + const struct nf_conntrack *ct = data2; + + return nfct_cmp(obj->ptr, ct, NFCT_CMP_ORIG) && + nfct_get_attr_u32(obj->ptr, ATTR_ID) == + nfct_get_attr_u32(ct, ATTR_ID); +} + +static void *cache_ct_alloc(void) +{ + return nfct_new(); +} + +static void cache_ct_free(void *ptr) +{ + nfct_destroy(ptr); +} + +static void cache_ct_copy(void *dst, void *src, unsigned int flags) +{ + nfct_copy(dst, src, flags); +} + +static int cache_ct_dump_step(void *data1, void *n) +{ + char buf[1024]; + int size; + struct __dump_container *container = data1; + struct cache_object *obj = n; + char *data = obj->data; + unsigned i; + + /* + * XXX: Do not dump the entries that are scheduled to expire. + * These entries talk about already destroyed connections + * that we keep for some time just in case that we have to + * resent some lost messages. We do not show them to the + * user as he may think that the firewall replicas are not + * in sync. The branch below is a hack as it is quite + * specific and it breaks conntrackd modularity. Probably + * there's a nicer way to do this but until I come up with it... + */ + if (CONFIG(flags) & CTD_SYNC_FTFW && obj->status == C_OBJ_DEAD) + return 0; + + /* do not show cached timeout, this may confuse users */ + if (nfct_attr_is_set(obj->ptr, ATTR_TIMEOUT)) + nfct_attr_unset(obj->ptr, ATTR_TIMEOUT); + + memset(buf, 0, sizeof(buf)); + size = nfct_snprintf(buf, + sizeof(buf), + obj->ptr, + NFCT_T_UNKNOWN, + container->type, + 0); + + for (i = 0; i < obj->cache->num_features; i++) { + if (obj->cache->features[i]->dump) { + size += obj->cache->features[i]->dump(obj, + data, + buf+size, + container->type); + data += obj->cache->features[i]->size; + } + } + if (container->type != NFCT_O_XML) { + long tm = time(NULL); + size += sprintf(buf+size, " [active since %lds]", + tm - obj->lifetime); + } + size += sprintf(buf+size, "\n"); + if (send(container->fd, buf, size, 0) == -1) { + if (errno != EPIPE) + return -1; + } + + return 0; +} + +static void +cache_ct_commit_step(struct __commit_container *tmp, struct cache_object *obj) +{ + int ret, retry = 1, timeout; + struct nf_conntrack *ct = obj->ptr; + + if (CONFIG(commit_timeout)) { + timeout = CONFIG(commit_timeout); + } else { + timeout = time(NULL) - obj->lastupdate; + if (timeout < 0) { + /* XXX: Arbitrarily set the timer to one minute, how + * can this happen? For example, an adjustment due to + * daylight-saving. Probably other situations can + * trigger this. */ + timeout = 60; + } + /* calculate an estimation of the current timeout */ + timeout = nfct_get_attr_u32(ct, ATTR_TIMEOUT) - timeout; + if (timeout < 0) { + timeout = 60; + } + } + +retry: + if (nl_create_conntrack(tmp->h, ct, timeout) == -1) { + if (errno == EEXIST && retry == 1) { + ret = nl_destroy_conntrack(tmp->h, ct); + if (ret == 0 || (ret == -1 && errno == ENOENT)) { + if (retry) { + retry = 0; + goto retry; + } + } + dlog(LOG_ERR, "commit-destroy: %s", strerror(errno)); + dlog_ct(STATE(log), ct, NFCT_O_PLAIN); + tmp->c->stats.commit_fail++; + } else { + dlog(LOG_ERR, "commit-create: %s", strerror(errno)); + dlog_ct(STATE(log), ct, NFCT_O_PLAIN); + tmp->c->stats.commit_fail++; + } + } else { + tmp->c->stats.commit_ok++; + } +} + +static int cache_ct_commit_related(void *data, void *n) +{ + struct cache_object *obj = n; + + if (ct_is_related(obj->ptr)) + cache_ct_commit_step(data, obj); + + /* keep iterating even if we have found errors */ + return 0; +} + +static int cache_ct_commit_master(void *data, void *n) +{ + struct cache_object *obj = n; + + if (ct_is_related(obj->ptr)) + return 0; + + cache_ct_commit_step(data, obj); + return 0; +} + +static int cache_ct_commit(struct cache *c, struct nfct_handle *h, int clientfd) +{ + unsigned int commit_ok, commit_fail; + struct __commit_container tmp = { + .h = h, + .c = c, + }; + struct timeval commit_stop, res; + + /* we already have one commit in progress, skip this. The clientfd + * descriptor has to be closed by the caller. */ + if (clientfd && STATE_SYNC(commit).clientfd != -1) + return 0; + + switch(STATE_SYNC(commit).state) { + case COMMIT_STATE_INACTIVE: + gettimeofday(&STATE_SYNC(commit).stats.start, NULL); + STATE_SYNC(commit).stats.ok = c->stats.commit_ok; + STATE_SYNC(commit).stats.fail = c->stats.commit_fail; + STATE_SYNC(commit).clientfd = clientfd; + case COMMIT_STATE_MASTER: + STATE_SYNC(commit).current = + hashtable_iterate_limit(c->h, &tmp, + STATE_SYNC(commit).current, + CONFIG(general).commit_steps, + cache_ct_commit_master); + if (STATE_SYNC(commit).current < CONFIG(hashsize)) { + STATE_SYNC(commit).state = COMMIT_STATE_MASTER; + /* give it another step as soon as possible */ + write_evfd(STATE_SYNC(commit).evfd); + return 1; + } + STATE_SYNC(commit).current = 0; + STATE_SYNC(commit).state = COMMIT_STATE_RELATED; + case COMMIT_STATE_RELATED: + STATE_SYNC(commit).current = + hashtable_iterate_limit(c->h, &tmp, + STATE_SYNC(commit).current, + CONFIG(general).commit_steps, + cache_ct_commit_related); + if (STATE_SYNC(commit).current < CONFIG(hashsize)) { + STATE_SYNC(commit).state = COMMIT_STATE_RELATED; + /* give it another step as soon as possible */ + write_evfd(STATE_SYNC(commit).evfd); + return 1; + } + /* calculate the time that commit has taken */ + gettimeofday(&commit_stop, NULL); + timersub(&commit_stop, &STATE_SYNC(commit).stats.start, &res); + + /* calculate new entries committed */ + commit_ok = c->stats.commit_ok - STATE_SYNC(commit).stats.ok; + commit_fail = + c->stats.commit_fail - STATE_SYNC(commit).stats.fail; + + /* log results */ + dlog(LOG_NOTICE, "Committed %u new entries", commit_ok); + + if (commit_fail) + dlog(LOG_NOTICE, "%u entries can't be " + "committed", commit_fail); + + dlog(LOG_NOTICE, "commit has taken %lu.%06lu seconds", + res.tv_sec, res.tv_usec); + + /* prepare the state machine for new commits */ + STATE_SYNC(commit).current = 0; + STATE_SYNC(commit).state = COMMIT_STATE_INACTIVE; + + /* Close the client socket now that we're done. */ + close(STATE_SYNC(commit).clientfd); + STATE_SYNC(commit).clientfd = -1; + } + return 1; +} + +static struct nethdr * +cache_ct_build_msg(const struct cache_object *obj, int type) +{ + return BUILD_NETMSG_FROM_CT(obj->ptr, type); +} + +/* template to cache conntracks coming from the kernel. */ +struct cache_ops cache_sync_internal_ct_ops = { + .hash = cache_ct_hash, + .cmp = cache_ct_cmp, + .alloc = cache_ct_alloc, + .free = cache_ct_free, + .copy = cache_ct_copy, + .dump_step = cache_ct_dump_step, + .commit = NULL, + .build_msg = cache_ct_build_msg, +}; + +/* template to cache conntracks coming from the network. */ +struct cache_ops cache_sync_external_ct_ops = { + .hash = cache_ct_hash, + .cmp = cache_ct_cmp, + .alloc = cache_ct_alloc, + .free = cache_ct_free, + .copy = cache_ct_copy, + .dump_step = cache_ct_dump_step, + .commit = cache_ct_commit, + .build_msg = NULL, +}; + +/* template to cache conntracks for the statistics mode. */ +struct cache_ops cache_stats_ct_ops = { + .hash = cache_ct_hash, + .cmp = cache_ct_cmp, + .alloc = cache_ct_alloc, + .free = cache_ct_free, + .copy = cache_ct_copy, + .dump_step = cache_ct_dump_step, + .commit = NULL, + .build_msg = NULL, +}; diff --git a/src/cache.c b/src/cache.c index f411121..efdab0e 100644 --- a/src/cache.c +++ b/src/cache.c @@ -1,5 +1,6 @@ /* - * (C) 2006-2009 by Pablo Neira Ayuso + * (C) 2006-2011 by Pablo Neira Ayuso + * (C) 2011 by Vyatta Inc. * * 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 @@ -28,80 +29,14 @@ #include #include -static uint32_t -__hash4(const struct nf_conntrack *ct, const struct hashtable *table) -{ - uint32_t a[4] = { - [0] = nfct_get_attr_u32(ct, ATTR_IPV4_SRC), - [1] = nfct_get_attr_u32(ct, ATTR_IPV4_DST), - [2] = nfct_get_attr_u8(ct, ATTR_L3PROTO) << 16 | - nfct_get_attr_u8(ct, ATTR_L4PROTO), - [3] = nfct_get_attr_u16(ct, ATTR_PORT_SRC) << 16 | - nfct_get_attr_u16(ct, ATTR_PORT_DST), - }; - - /* - * Instead of returning hash % table->hashsize (implying a divide) - * we return the high 32 bits of the (hash * table->hashsize) that will - * give results between [0 and hashsize-1] and same hash distribution, - * but using a multiply, less expensive than a divide. See: - * http://www.mail-archive.com/netdev@vger.kernel.org/msg56623.html - */ - return ((uint64_t)jhash2(a, 4, 0) * table->hashsize) >> 32; -} - -static uint32_t -__hash6(const struct nf_conntrack *ct, const struct hashtable *table) -{ - uint32_t a[10]; - - memcpy(&a[0], nfct_get_attr(ct, ATTR_IPV6_SRC), sizeof(uint32_t)*4); - memcpy(&a[4], nfct_get_attr(ct, ATTR_IPV6_SRC), sizeof(uint32_t)*4); - a[8] = nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO) << 16 | - nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO); - a[9] = nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC) << 16 | - nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST); - - return ((uint64_t)jhash2(a, 10, 0) * table->hashsize) >> 32; -} - -static uint32_t hash(const void *data, const struct hashtable *table) -{ - int ret = 0; - const struct nf_conntrack *ct = data; - - switch(nfct_get_attr_u8(ct, ATTR_L3PROTO)) { - case AF_INET: - ret = __hash4(ct, table); - break; - case AF_INET6: - ret = __hash6(ct, table); - break; - default: - dlog(LOG_ERR, "unknown layer 3 proto in hash"); - break; - } - - return ret; -} - -static int compare(const void *data1, const void *data2) -{ - const struct cache_object *obj = data1; - const struct nf_conntrack *ct = data2; - - return nfct_cmp(obj->ct, ct, NFCT_CMP_ORIG) && - nfct_get_attr_u32(obj->ct, ATTR_ID) == - nfct_get_attr_u32(ct, ATTR_ID); -} - struct cache_feature *cache_feature[CACHE_MAX_FEATURE] = { [TIMER_FEATURE] = &timer_feature, }; -struct cache *cache_create(const char *name, +struct cache *cache_create(const char *name, enum cache_type type, unsigned int features, - struct cache_extra *extra) + struct cache_extra *extra, + struct cache_ops *ops) { size_t size = sizeof(struct cache_object); int i, j = 0; @@ -110,12 +45,16 @@ struct cache *cache_create(const char *name, unsigned int feature_offset[CACHE_MAX_FEATURE] = {}; unsigned int feature_type[CACHE_MAX_FEATURE] = {}; + if (type == CACHE_T_NONE || type >= CACHE_T_MAX) + return NULL; + c = malloc(sizeof(struct cache)); if (!c) return NULL; memset(c, 0, sizeof(struct cache)); strcpy(c->name, name); + c->type = type; for (i = 0; i < CACHE_MAX_FEATURE; i++) { if ((1 << i) & features) { @@ -150,11 +89,19 @@ struct cache *cache_create(const char *name, } memcpy(c->feature_offset, feature_offset, sizeof(unsigned int) * j); + if (!ops || !ops->hash || !ops->cmp || + !ops->alloc || !ops->copy || !ops->free) { + free(c->feature_offset); + free(c->features); + free(c); + return NULL; + } + c->ops = ops; + c->h = hashtable_create(CONFIG(hashsize), CONFIG(limit), - hash, - compare); - + c->ops->hash, + c->ops->cmp); if (!c->h) { free(c->features); free(c->feature_offset); @@ -175,7 +122,7 @@ void cache_destroy(struct cache *c) free(c); } -struct cache_object *cache_object_new(struct cache *c, struct nf_conntrack *ct) +struct cache_object *cache_object_new(struct cache *c, void *ptr) { struct cache_object *obj; @@ -187,13 +134,14 @@ struct cache_object *cache_object_new(struct cache *c, struct nf_conntrack *ct) } obj->cache = c; - if ((obj->ct = nfct_new()) == NULL) { + obj->ptr = c->ops->alloc(); + if (obj->ptr == NULL) { free(obj); errno = ENOMEM; c->stats.add_fail_enomem++; return NULL; } - nfct_copy(obj->ct, ct, NFCT_CP_OVERRIDE); + c->ops->copy(obj->ptr, ptr, NFCT_CP_OVERRIDE); obj->status = C_OBJ_NONE; c->stats.objects++; @@ -203,7 +151,8 @@ struct cache_object *cache_object_new(struct cache *c, struct nf_conntrack *ct) void cache_object_free(struct cache_object *obj) { obj->cache->stats.objects--; - nfct_destroy(obj->ct); + obj->cache->ops->free(obj->ptr); + free(obj); } @@ -271,13 +220,12 @@ int cache_add(struct cache *c, struct cache_object *obj, int id) return 0; } -void cache_update(struct cache *c, struct cache_object *obj, int id, - struct nf_conntrack *ct) +void cache_update(struct cache *c, struct cache_object *obj, int id, void *ptr) { char *data = obj->data; unsigned int i; - nfct_copy(obj->ct, ct, NFCT_CP_META); + c->ops->copy(obj->ptr, ptr, NFCT_CP_META); for (i = 0; i < c->num_features; i++) { c->features[i]->update(obj, data); @@ -322,23 +270,22 @@ void cache_del(struct cache *c, struct cache_object *obj) __del(c, obj); } -struct cache_object * -cache_update_force(struct cache *c, struct nf_conntrack *ct) +struct cache_object *cache_update_force(struct cache *c, void *ptr) { struct cache_object *obj; int id; - obj = cache_find(c, ct, &id); + obj = cache_find(c, ptr, &id); if (obj) { if (obj->status != C_OBJ_DEAD) { - cache_update(c, obj, id, ct); + cache_update(c, obj, id, ptr); return obj; } else { cache_del(c, obj); cache_object_free(obj); } } - obj = cache_object_new(c, ct); + obj = cache_object_new(c, ptr); if (obj == NULL) return NULL; @@ -350,11 +297,10 @@ cache_update_force(struct cache *c, struct nf_conntrack *ct) return obj; } -struct cache_object * -cache_find(struct cache *c, struct nf_conntrack *ct, int *id) +struct cache_object *cache_find(struct cache *c, void *ptr, int *id) { - *id = hashtable_hash(c->h, ct); - return ((struct cache_object *) hashtable_find(c->h, ct, *id)); + *id = hashtable_hash(c->h, ptr); + return ((struct cache_object *) hashtable_find(c->h, ptr, *id)); } struct cache_object *cache_data_get_object(struct cache *c, void *data) @@ -432,3 +378,33 @@ void cache_iterate_limit(struct cache *c, void *data, { hashtable_iterate_limit(c->h, data, from, steps, iterate); } + +void cache_dump(struct cache *c, int fd, int type) +{ + struct __dump_container tmp = { + .fd = fd, + .type = type + }; + hashtable_iterate(c->h, (void *) &tmp, c->ops->dump_step); +} + +int cache_commit(struct cache *c, struct nfct_handle *h, int clientfd) +{ + return c->ops->commit(c, h, clientfd); +} + +static int do_flush(void *data, void *n) +{ + struct cache *c = data; + struct cache_object *obj = n; + + cache_del(c, obj); + cache_object_free(obj); + return 0; +} + +void cache_flush(struct cache *c) +{ + hashtable_iterate(c->h, c, do_flush); + c->stats.flush++; +} diff --git a/src/cache_iterators.c b/src/cache_iterators.c deleted file mode 100644 index 3248c70..0000000 --- a/src/cache_iterators.c +++ /dev/null @@ -1,268 +0,0 @@ -/* - * (C) 2006-2007 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "cache.h" -#include "hash.h" -#include "log.h" -#include "conntrackd.h" -#include "netlink.h" -#include "event.h" - -#include -#include -#include -#include -#include - -struct __dump_container { - int fd; - int type; -}; - -static int do_dump(void *data1, void *n) -{ - char buf[1024]; - int size; - struct __dump_container *container = data1; - struct cache_object *obj = n; - char *data = obj->data; - unsigned i; - - /* - * XXX: Do not dump the entries that are scheduled to expire. - * These entries talk about already destroyed connections - * that we keep for some time just in case that we have to - * resent some lost messages. We do not show them to the - * user as he may think that the firewall replicas are not - * in sync. The branch below is a hack as it is quite - * specific and it breaks conntrackd modularity. Probably - * there's a nicer way to do this but until I come up with it... - */ - if (CONFIG(flags) & CTD_SYNC_FTFW && obj->status == C_OBJ_DEAD) - return 0; - - /* do not show cached timeout, this may confuse users */ - if (nfct_attr_is_set(obj->ct, ATTR_TIMEOUT)) - nfct_attr_unset(obj->ct, ATTR_TIMEOUT); - - memset(buf, 0, sizeof(buf)); - size = nfct_snprintf(buf, - sizeof(buf), - obj->ct, - NFCT_T_UNKNOWN, - container->type, - 0); - - for (i = 0; i < obj->cache->num_features; i++) { - if (obj->cache->features[i]->dump) { - size += obj->cache->features[i]->dump(obj, - data, - buf+size, - container->type); - data += obj->cache->features[i]->size; - } - } - if (container->type != NFCT_O_XML) { - long tm = time(NULL); - size += sprintf(buf+size, " [active since %lds]", - tm - obj->lifetime); - } - size += sprintf(buf+size, "\n"); - if (send(container->fd, buf, size, 0) == -1) { - if (errno != EPIPE) - return -1; - } - - return 0; -} - -void cache_dump(struct cache *c, int fd, int type) -{ - struct __dump_container tmp = { - .fd = fd, - .type = type - }; - - hashtable_iterate(c->h, (void *) &tmp, do_dump); -} - -struct __commit_container { - struct nfct_handle *h; - struct cache *c; -}; - -static void -__do_commit_step(struct __commit_container *tmp, struct cache_object *obj) -{ - int ret, retry = 1, timeout; - struct nf_conntrack *ct = obj->ct; - - if (CONFIG(commit_timeout)) { - timeout = CONFIG(commit_timeout); - } else { - timeout = time(NULL) - obj->lastupdate; - if (timeout < 0) { - /* XXX: Arbitrarily set the timer to one minute, how - * can this happen? For example, an adjustment due to - * daylight-saving. Probably other situations can - * trigger this. */ - timeout = 60; - } - /* calculate an estimation of the current timeout */ - timeout = nfct_get_attr_u32(ct, ATTR_TIMEOUT) - timeout; - if (timeout < 0) { - timeout = 60; - } - } - -retry: - if (nl_create_conntrack(tmp->h, ct, timeout) == -1) { - if (errno == EEXIST && retry == 1) { - ret = nl_destroy_conntrack(tmp->h, ct); - if (ret == 0 || (ret == -1 && errno == ENOENT)) { - if (retry) { - retry = 0; - goto retry; - } - } - dlog(LOG_ERR, "commit-destroy: %s", strerror(errno)); - dlog_ct(STATE(log), ct, NFCT_O_PLAIN); - tmp->c->stats.commit_fail++; - } else { - dlog(LOG_ERR, "commit-create: %s", strerror(errno)); - dlog_ct(STATE(log), ct, NFCT_O_PLAIN); - tmp->c->stats.commit_fail++; - } - } else { - tmp->c->stats.commit_ok++; - } -} - -static int do_commit_related(void *data, void *n) -{ - struct cache_object *obj = n; - - if (ct_is_related(obj->ct)) - __do_commit_step(data, obj); - - /* keep iterating even if we have found errors */ - return 0; -} - -static int do_commit_master(void *data, void *n) -{ - struct cache_object *obj = n; - - if (ct_is_related(obj->ct)) - return 0; - - __do_commit_step(data, obj); - return 0; -} - -int cache_commit(struct cache *c, struct nfct_handle *h, int clientfd) -{ - unsigned int commit_ok, commit_fail; - struct __commit_container tmp = { - .h = h, - .c = c, - }; - struct timeval commit_stop, res; - - /* we already have one commit in progress, skip this. The clientfd - * descriptor has to be closed by the caller. */ - if (clientfd && STATE_SYNC(commit).clientfd != -1) - return 0; - - switch(STATE_SYNC(commit).state) { - case COMMIT_STATE_INACTIVE: - gettimeofday(&STATE_SYNC(commit).stats.start, NULL); - STATE_SYNC(commit).stats.ok = c->stats.commit_ok; - STATE_SYNC(commit).stats.fail = c->stats.commit_fail; - STATE_SYNC(commit).clientfd = clientfd; - case COMMIT_STATE_MASTER: - STATE_SYNC(commit).current = - hashtable_iterate_limit(c->h, &tmp, - STATE_SYNC(commit).current, - CONFIG(general).commit_steps, - do_commit_master); - if (STATE_SYNC(commit).current < CONFIG(hashsize)) { - STATE_SYNC(commit).state = COMMIT_STATE_MASTER; - /* give it another step as soon as possible */ - write_evfd(STATE_SYNC(commit).evfd); - return 1; - } - STATE_SYNC(commit).current = 0; - STATE_SYNC(commit).state = COMMIT_STATE_RELATED; - case COMMIT_STATE_RELATED: - STATE_SYNC(commit).current = - hashtable_iterate_limit(c->h, &tmp, - STATE_SYNC(commit).current, - CONFIG(general).commit_steps, - do_commit_related); - if (STATE_SYNC(commit).current < CONFIG(hashsize)) { - STATE_SYNC(commit).state = COMMIT_STATE_RELATED; - /* give it another step as soon as possible */ - write_evfd(STATE_SYNC(commit).evfd); - return 1; - } - /* calculate the time that commit has taken */ - gettimeofday(&commit_stop, NULL); - timersub(&commit_stop, &STATE_SYNC(commit).stats.start, &res); - - /* calculate new entries committed */ - commit_ok = c->stats.commit_ok - STATE_SYNC(commit).stats.ok; - commit_fail = - c->stats.commit_fail - STATE_SYNC(commit).stats.fail; - - /* log results */ - dlog(LOG_NOTICE, "Committed %u new entries", commit_ok); - - if (commit_fail) - dlog(LOG_NOTICE, "%u entries can't be " - "committed", commit_fail); - - dlog(LOG_NOTICE, "commit has taken %lu.%06lu seconds", - res.tv_sec, res.tv_usec); - - /* prepare the state machine for new commits */ - STATE_SYNC(commit).current = 0; - STATE_SYNC(commit).state = COMMIT_STATE_INACTIVE; - - /* Close the client socket now that we're done. */ - close(STATE_SYNC(commit).clientfd); - STATE_SYNC(commit).clientfd = -1; - } - return 1; -} - -static int do_flush(void *data, void *n) -{ - struct cache *c = data; - struct cache_object *obj = n; - - cache_del(c, obj); - cache_object_free(obj); - return 0; -} - -void cache_flush(struct cache *c) -{ - hashtable_iterate(c->h, c, do_flush); - c->stats.flush++; -} diff --git a/src/external_cache.c b/src/external_cache.c index 59c706a..073f309 100644 --- a/src/external_cache.c +++ b/src/external_cache.c @@ -28,9 +28,9 @@ static struct cache *external; static int external_cache_init(void) { - external = cache_create("external", + external = cache_create("external", CACHE_T_CT, STATE_SYNC(sync)->external_cache_flags, - NULL); + NULL, &cache_sync_external_ct_ops); if (external == NULL) { dlog(LOG_ERR, "can't allocate memory for the external cache"); return -1; diff --git a/src/internal_bypass.c b/src/internal_bypass.c index 1e1478f..8ecec34 100644 --- a/src/internal_bypass.c +++ b/src/internal_bypass.c @@ -1,6 +1,7 @@ /* - * (C) 2009 by Pablo Neira Ayuso - * + * (C) 2006-2011 by Pablo Neira Ayuso + * (C) 2011 by Vyatta Inc. + * * 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 @@ -16,17 +17,18 @@ #include "network.h" #include "origin.h" -static int _init(void) +static int internal_bypass_init(void) { return 0; } -static void _close(void) +static void internal_bypass_close(void) { } -static int dump_cb(enum nf_conntrack_msg_type type, - struct nf_conntrack *ct, void *data) +static int +internal_bypass_ct_dump_cb(enum nf_conntrack_msg_type type, + struct nf_conntrack *ct, void *data) { char buf[1024]; int size, *fd = data; @@ -44,7 +46,7 @@ static int dump_cb(enum nf_conntrack_msg_type type, return NFCT_CB_CONTINUE; } -static void dump(int fd, int type) +static void internal_bypass_ct_dump(int fd, int type) { struct nfct_handle *h; u_int32_t family = AF_UNSPEC; @@ -55,7 +57,7 @@ static void dump(int fd, int type) dlog(LOG_ERR, "can't allocate memory for the internal cache"); return; } - nfct_callback_register(h, NFCT_T_ALL, dump_cb, &fd); + nfct_callback_register(h, NFCT_T_ALL, internal_bypass_ct_dump_cb, &fd); ret = nfct_query(h, NFCT_Q_DUMP, &family); if (ret == -1) { dlog(LOG_ERR, "can't dump kernel table"); @@ -63,7 +65,7 @@ static void dump(int fd, int type) nfct_close(h); } -static void flush(void) +static void internal_bypass_ct_flush(void) { nl_flush_conntrack_table(STATE(flush)); } @@ -74,7 +76,7 @@ struct { uint32_t del; } internal_bypass_stats; -static void stats(int fd) +static void internal_bypass_ct_stats(int fd) { char buf[512]; int size; @@ -91,25 +93,24 @@ static void stats(int fd) } /* unused, INTERNAL_F_POPULATE is unset. No cache, nothing to populate. */ -static void populate(struct nf_conntrack *ct) +static void internal_bypass_ct_populate(struct nf_conntrack *ct) { } /* unused, INTERNAL_F_RESYNC is unset. */ -static void purge(void) +static void internal_bypass_ct_purge(void) { } /* unused, INTERNAL_F_RESYNC is unset. Nothing to resync, we have no cache. */ -static int resync(enum nf_conntrack_msg_type type, - struct nf_conntrack *ct, - void *data) +static int +internal_bypass_ct_resync(enum nf_conntrack_msg_type type, + struct nf_conntrack *ct, void *data) { return NFCT_CB_CONTINUE; } -static void -event_new_sync(struct nf_conntrack *ct, int origin) +static void internal_bypass_ct_event_new(struct nf_conntrack *ct, int origin) { struct nethdr *net; @@ -122,8 +123,7 @@ event_new_sync(struct nf_conntrack *ct, int origin) internal_bypass_stats.new++; } -static void -event_update_sync(struct nf_conntrack *ct, int origin) +static void internal_bypass_ct_event_upd(struct nf_conntrack *ct, int origin) { struct nethdr *net; @@ -136,8 +136,7 @@ event_update_sync(struct nf_conntrack *ct, int origin) internal_bypass_stats.upd++; } -static int -event_destroy_sync(struct nf_conntrack *ct, int origin) +static int internal_bypass_ct_event_del(struct nf_conntrack *ct, int origin) { struct nethdr *net; @@ -153,16 +152,18 @@ event_destroy_sync(struct nf_conntrack *ct, int origin) } struct internal_handler internal_bypass = { - .init = _init, - .close = _close, - .dump = dump, - .flush = flush, - .stats = stats, - .stats_ext = stats, - .populate = populate, - .purge = purge, - .resync = resync, - .new = event_new_sync, - .update = event_update_sync, - .destroy = event_destroy_sync, + .init = internal_bypass_init, + .close = internal_bypass_close, + .ct = { + .dump = internal_bypass_ct_dump, + .flush = internal_bypass_ct_flush, + .stats = internal_bypass_ct_stats, + .stats_ext = internal_bypass_ct_stats, + .populate = internal_bypass_ct_populate, + .purge = internal_bypass_ct_purge, + .resync = internal_bypass_ct_resync, + .new = internal_bypass_ct_event_new, + .upd = internal_bypass_ct_event_upd, + .del = internal_bypass_ct_event_del, + }, }; diff --git a/src/internal_cache.c b/src/internal_cache.c index e50e1db..7a698e6 100644 --- a/src/internal_cache.c +++ b/src/internal_cache.c @@ -1,6 +1,7 @@ /* - * (C) 2009 by Pablo Neira Ayuso - * + * (C) 2006-2011 by Pablo Neira Ayuso + * (C) 2011 by Vyatta Inc. + * * 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 @@ -19,46 +20,47 @@ static inline void sync_send(struct cache_object *obj, int query) STATE_SYNC(sync)->enqueue(obj, query); } -static int _init(void) +static int internal_cache_init(void) { - STATE(mode)->internal->data = - cache_create("internal", + STATE(mode)->internal->ct.data = + cache_create("internal", CACHE_T_CT, STATE_SYNC(sync)->internal_cache_flags, - STATE_SYNC(sync)->internal_cache_extra); + STATE_SYNC(sync)->internal_cache_extra, + &cache_sync_internal_ct_ops); - if (!STATE(mode)->internal->data) { + if (!STATE(mode)->internal->ct.data) { dlog(LOG_ERR, "can't allocate memory for the internal cache"); return -1; } return 0; } -static void _close(void) +static void internal_cache_close(void) { - cache_destroy(STATE(mode)->internal->data); + cache_destroy(STATE(mode)->internal->ct.data); } -static void dump(int fd, int type) +static void internal_cache_ct_dump(int fd, int type) { - cache_dump(STATE(mode)->internal->data, fd, type); + cache_dump(STATE(mode)->internal->ct.data, fd, type); } -static void flush(void) +static void internal_cache_ct_flush(void) { - cache_flush(STATE(mode)->internal->data); + cache_flush(STATE(mode)->internal->ct.data); } -static void stats(int fd) +static void internal_cache_ct_stats(int fd) { - cache_stats(STATE(mode)->internal->data, fd); + cache_stats(STATE(mode)->internal->ct.data, fd); } -static void stats_ext(int fd) +static void internal_cache_ct_stats_ext(int fd) { - cache_stats_extended(STATE(mode)->internal->data, fd); + cache_stats_extended(STATE(mode)->internal->ct.data, fd); } -static void populate(struct nf_conntrack *ct) +static void internal_cache_ct_populate(struct nf_conntrack *ct) { /* This is required by kernels < 2.6.20 */ nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES); @@ -67,15 +69,15 @@ static void populate(struct nf_conntrack *ct) nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); nfct_attr_unset(ct, ATTR_USE); - cache_update_force(STATE(mode)->internal->data, ct); + cache_update_force(STATE(mode)->internal->ct.data, ct); } -static int purge_step(void *data1, void *data2) +static int internal_cache_ct_purge_step(void *data1, void *data2) { struct cache_object *obj = data2; STATE(get_retval) = 0; - nl_get_conntrack(STATE(get), obj->ct); /* modifies STATE(get_reval) */ + nl_get_conntrack(STATE(get), obj->ptr); /* modifies STATE(get_reval) */ if (!STATE(get_retval)) { if (obj->status != C_OBJ_DEAD) { cache_object_set_status(obj, C_OBJ_DEAD); @@ -87,14 +89,15 @@ static int purge_step(void *data1, void *data2) return 0; } -static void purge(void) +static void internal_cache_ct_purge(void) { - cache_iterate(STATE(mode)->internal->data, NULL, purge_step); + cache_iterate(STATE(mode)->internal->ct.data, NULL, + internal_cache_ct_purge_step); } -static int resync(enum nf_conntrack_msg_type type, - struct nf_conntrack *ct, - void *data) +static int +internal_cache_ct_resync(enum nf_conntrack_msg_type type, + struct nf_conntrack *ct, void *data) { struct cache_object *obj; @@ -108,7 +111,7 @@ static int resync(enum nf_conntrack_msg_type type, nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); nfct_attr_unset(ct, ATTR_USE); - obj = cache_update_force(STATE(mode)->internal->data, ct); + obj = cache_update_force(STATE(mode)->internal->ct.data, ct); if (obj == NULL) return NFCT_CB_CONTINUE; @@ -123,8 +126,7 @@ static int resync(enum nf_conntrack_msg_type type, return NFCT_CB_CONTINUE; } -static void -event_new_sync(struct nf_conntrack *ct, int origin) +static void internal_cache_ct_event_new(struct nf_conntrack *ct, int origin) { struct cache_object *obj; int id; @@ -139,13 +141,13 @@ event_new_sync(struct nf_conntrack *ct, int origin) nfct_attr_unset(ct, ATTR_REPL_COUNTER_BYTES); nfct_attr_unset(ct, ATTR_REPL_COUNTER_PACKETS); - obj = cache_find(STATE(mode)->internal->data, ct, &id); + obj = cache_find(STATE(mode)->internal->ct.data, ct, &id); if (obj == NULL) { retry: - obj = cache_object_new(STATE(mode)->internal->data, ct); + obj = cache_object_new(STATE(mode)->internal->ct.data, ct); if (obj == NULL) return; - if (cache_add(STATE(mode)->internal->data, obj, id) == -1) { + if (cache_add(STATE(mode)->internal->ct.data, obj, id) == -1) { cache_object_free(obj); return; } @@ -155,14 +157,13 @@ retry: if (origin == CTD_ORIGIN_NOT_ME) sync_send(obj, NET_T_STATE_NEW); } else { - cache_del(STATE(mode)->internal->data, obj); + cache_del(STATE(mode)->internal->ct.data, obj); cache_object_free(obj); goto retry; } } -static void -event_update_sync(struct nf_conntrack *ct, int origin) +static void internal_cache_ct_event_upd(struct nf_conntrack *ct, int origin) { struct cache_object *obj; @@ -170,7 +171,7 @@ event_update_sync(struct nf_conntrack *ct, int origin) if (origin == CTD_ORIGIN_INJECT) return; - obj = cache_update_force(STATE(mode)->internal->data, ct); + obj = cache_update_force(STATE(mode)->internal->ct.data, ct); if (obj == NULL) return; @@ -178,8 +179,7 @@ event_update_sync(struct nf_conntrack *ct, int origin) sync_send(obj, NET_T_STATE_UPD); } -static int -event_destroy_sync(struct nf_conntrack *ct, int origin) +static int internal_cache_ct_event_del(struct nf_conntrack *ct, int origin) { struct cache_object *obj; int id; @@ -189,7 +189,7 @@ event_destroy_sync(struct nf_conntrack *ct, int origin) return 0; /* we don't synchronize events for objects that are not in the cache */ - obj = cache_find(STATE(mode)->internal->data, ct, &id); + obj = cache_find(STATE(mode)->internal->ct.data, ct, &id); if (obj == NULL) return 0; @@ -205,16 +205,18 @@ event_destroy_sync(struct nf_conntrack *ct, int origin) struct internal_handler internal_cache = { .flags = INTERNAL_F_POPULATE | INTERNAL_F_RESYNC, - .init = _init, - .close = _close, - .dump = dump, - .flush = flush, - .stats = stats, - .stats_ext = stats_ext, - .populate = populate, - .purge = purge, - .resync = resync, - .new = event_new_sync, - .update = event_update_sync, - .destroy = event_destroy_sync, + .init = internal_cache_init, + .close = internal_cache_close, + .ct = { + .dump = internal_cache_ct_dump, + .flush = internal_cache_ct_flush, + .stats = internal_cache_ct_stats, + .stats_ext = internal_cache_ct_stats_ext, + .populate = internal_cache_ct_populate, + .purge = internal_cache_ct_purge, + .resync = internal_cache_ct_resync, + .new = internal_cache_ct_event_new, + .upd = internal_cache_ct_event_upd, + .del = internal_cache_ct_event_del, + }, }; diff --git a/src/run.c b/src/run.c index 265a949..f8d3fad 100644 --- a/src/run.c +++ b/src/run.c @@ -1,6 +1,7 @@ /* - * (C) 2006-2009 by Pablo Neira Ayuso - * + * (C) 2006-2011 by Pablo Neira Ayuso + * (C) 2011 by Vyatta Inc. + * * 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 @@ -241,8 +242,8 @@ static void do_overrun_resync_alarm(struct alarm_block *a, void *data) static void do_polling_alarm(struct alarm_block *a, void *data) { - if (STATE(mode)->internal->purge) - STATE(mode)->internal->purge(); + if (STATE(mode)->internal->ct.purge) + STATE(mode)->internal->ct.purge(); nl_send_resync(STATE(resync)); add_alarm(&STATE(polling_alarm), CONFIG(poll_kernel_secs), 0); @@ -267,13 +268,13 @@ static int event_handler(const struct nlmsghdr *nlh, switch(type) { case NFCT_T_NEW: - STATE(mode)->internal->new(ct, origin_type); + STATE(mode)->internal->ct.new(ct, origin_type); break; case NFCT_T_UPDATE: - STATE(mode)->internal->update(ct, origin_type); + STATE(mode)->internal->ct.upd(ct, origin_type); break; case NFCT_T_DESTROY: - if (STATE(mode)->internal->destroy(ct, origin_type)) + if (STATE(mode)->internal->ct.del(ct, origin_type)) update_traffic_stats(ct); break; default: @@ -298,7 +299,7 @@ static int dump_handler(enum nf_conntrack_msg_type type, switch(type) { case NFCT_T_UPDATE: - STATE(mode)->internal->populate(ct); + STATE(mode)->internal->ct.populate(ct); break; default: STATE(stats).nl_dump_unknown_type++; @@ -363,7 +364,7 @@ init(void) } nfct_callback_register(STATE(resync), NFCT_T_ALL, - STATE(mode)->internal->resync, + STATE(mode)->internal->ct.resync, NULL); register_fd(nfct_fd(STATE(resync)), STATE(fds)); fcntl(nfct_fd(STATE(resync)), F_SETFL, O_NONBLOCK); @@ -537,8 +538,8 @@ static void run_events(struct timeval *next_alarm) /* we previously requested a resync due to buffer overrun. */ if (FD_ISSET(nfct_fd(STATE(resync)), &readfds)) { nfct_catch(STATE(resync)); - if (STATE(mode)->internal->purge) - STATE(mode)->internal->purge(); + if (STATE(mode)->internal->ct.purge) + STATE(mode)->internal->ct.purge(); } if (STATE(mode)->run) diff --git a/src/stats-mode.c b/src/stats-mode.c index 0403ce2..c7a81e3 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -1,6 +1,7 @@ /* - * (C) 2006-2007 by Pablo Neira Ayuso - * + * (C) 2006-2011 by Pablo Neira Ayuso + * (C) 2011 by Vyatta Inc. + * * 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 @@ -37,7 +38,9 @@ static int init_stats(void) } memset(state.stats, 0, sizeof(struct ct_stats_state)); - STATE_STATS(cache) = cache_create("stats", NO_FEATURES, NULL); + STATE_STATS(cache) = cache_create("stats", CACHE_T_CT, + NO_FEATURES, NULL, + &cache_stats_ct_ops); if (!STATE_STATS(cache)) { dlog(LOG_ERR, "can't allocate memory for the " "external cache"); @@ -88,7 +91,7 @@ static int local_handler_stats(int fd, int type, void *data) return ret; } -static void populate_stats(struct nf_conntrack *ct) +static void stats_populate(struct nf_conntrack *ct) { nfct_attr_unset(ct, ATTR_ORIG_COUNTER_BYTES); nfct_attr_unset(ct, ATTR_ORIG_COUNTER_PACKETS); @@ -100,7 +103,7 @@ static void populate_stats(struct nf_conntrack *ct) cache_update_force(STATE_STATS(cache), ct); } -static int resync_stats(enum nf_conntrack_msg_type type, +static int stats_resync(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data) { @@ -125,23 +128,22 @@ static int purge_step(void *data1, void *data2) struct cache_object *obj = data2; STATE(get_retval) = 0; - nl_get_conntrack(STATE(get), obj->ct); /* modifies STATE(get_retval) */ + nl_get_conntrack(STATE(get), obj->ptr); /* modifies STATE(get_retval) */ if (!STATE(get_retval)) { cache_del(STATE_STATS(cache), obj); - dlog_ct(STATE(stats_log), obj->ct, NFCT_O_PLAIN); + dlog_ct(STATE(stats_log), obj->ptr, NFCT_O_PLAIN); cache_object_free(obj); } return 0; } -static void purge_stats(void) +static void stats_purge(void) { cache_iterate(STATE_STATS(cache), NULL, purge_step); } -static void -event_new_stats(struct nf_conntrack *ct, int origin) +static void stats_event_new(struct nf_conntrack *ct, int origin) { int id; struct cache_object *obj; @@ -162,15 +164,13 @@ event_new_stats(struct nf_conntrack *ct, int origin) return; } -static void -event_update_stats(struct nf_conntrack *ct, int origin) +static void stats_event_upd(struct nf_conntrack *ct, int origin) { nfct_attr_unset(ct, ATTR_TIMEOUT); cache_update_force(STATE_STATS(cache), ct); } -static int -event_destroy_stats(struct nf_conntrack *ct, int origin) +static int stats_event_del(struct nf_conntrack *ct, int origin) { int id; struct cache_object *obj; @@ -189,12 +189,14 @@ event_destroy_stats(struct nf_conntrack *ct, int origin) static struct internal_handler internal_cache_stats = { .flags = INTERNAL_F_POPULATE | INTERNAL_F_RESYNC, - .populate = populate_stats, - .resync = resync_stats, - .purge = purge_stats, - .new = event_new_stats, - .update = event_update_stats, - .destroy = event_destroy_stats + .ct = { + .populate = stats_populate, + .resync = stats_resync, + .purge = stats_purge, + .new = stats_event_new, + .upd = stats_event_upd, + .del = stats_event_del, + }, }; struct ct_mode stats_mode = { diff --git a/src/sync-alarm.c b/src/sync-alarm.c index b555dd5..8d6b34d 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -1,6 +1,7 @@ /* - * (C) 2006-2007 by Pablo Neira Ayuso - * + * (C) 2006-2011 by Pablo Neira Ayuso + * (C) 2011 by Vyatta Inc. + * * 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 @@ -110,7 +111,7 @@ static int alarm_recv(const struct nethdr *net) static void alarm_enqueue(struct cache_object *obj, int query) { struct cache_alarm *ca = - cache_get_extra(STATE(mode)->internal->data, obj); + cache_get_extra(STATE(mode)->internal->ct.data, obj); if (queue_add(STATE_SYNC(tx_queue), &ca->qnode) > 0) cache_object_get(obj); } @@ -135,9 +136,9 @@ static int tx_queue_xmit(struct queue_node *n, const void *data) int type; ca = (struct cache_alarm *)n; - obj = cache_data_get_object(STATE(mode)->internal->data, ca); + obj = cache_data_get_object(STATE(mode)->internal->ct.data, ca); type = object_status_to_network_type(obj->status); - net = BUILD_NETMSG(obj->ct, type); + net = obj->cache->ops->build_msg(obj, type); multichannel_send(STATE_SYNC(channel), net); cache_object_put(obj); break; diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 581b5ca..55eda0b 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -1,6 +1,7 @@ /* - * (C) 2006-2008 by Pablo Neira Ayuso - * + * (C) 2006-2011 by Pablo Neira Ayuso + * (C) 2011 by Vyatta Inc. + * * 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 @@ -169,7 +170,7 @@ static int do_cache_to_tx(void *data1, void *data2) { struct cache_object *obj = data2; struct cache_ftfw *cn = - cache_get_extra(STATE(mode)->internal->data, obj); + cache_get_extra(STATE(mode)->internal->ct.data, obj); if (queue_in(rs_queue, &cn->qnode)) { queue_del(&cn->qnode); @@ -227,7 +228,7 @@ static int ftfw_local(int fd, int type, void *data) break; case SEND_BULK: dlog(LOG_NOTICE, "sending bulk update"); - cache_iterate(STATE(mode)->internal->data, + cache_iterate(STATE(mode)->internal->ct.data, NULL, do_cache_to_tx); break; case STATS_RSQUEUE: @@ -307,7 +308,7 @@ static int rs_queue_empty(struct queue_node *n, const void *data) cn = (struct cache_ftfw *) n; if (h == NULL) { queue_del(n); - obj = cache_data_get_object(STATE(mode)->internal->data, cn); + obj = cache_data_get_object(STATE(mode)->internal->ct.data, cn); cache_object_put(obj); return 0; } @@ -318,7 +319,7 @@ static int rs_queue_empty(struct queue_node *n, const void *data) dp("queue: deleting from queue (seq=%u)\n", cn->seq); queue_del(n); - obj = cache_data_get_object(STATE(mode)->internal->data, cn); + obj = cache_data_get_object(STATE(mode)->internal->ct.data, cn); cache_object_put(obj); break; } @@ -351,7 +352,7 @@ static int digest_msg(const struct nethdr *net) } else if (IS_RESYNC(net)) { dp("RESYNC ALL\n"); - cache_iterate(STATE(mode)->internal->data, NULL, do_cache_to_tx); + cache_iterate(STATE(mode)->internal->ct.data, NULL, do_cache_to_tx); return MSG_CTL; } else if (IS_ALIVE(net)) @@ -468,7 +469,7 @@ static void rs_queue_purge_full(void) struct cache_object *obj; cn = (struct cache_ftfw *)n; - obj = cache_data_get_object(STATE(mode)->internal->data, cn); + obj = cache_data_get_object(STATE(mode)->internal->ct.data, cn); cache_object_put(obj); break; } @@ -516,9 +517,9 @@ static int tx_queue_xmit(struct queue_node *n, const void *data) struct nethdr *net; cn = (struct cache_ftfw *)n; - obj = cache_data_get_object(STATE(mode)->internal->data, cn); + obj = cache_data_get_object(STATE(mode)->internal->ct.data, cn); type = object_status_to_network_type(obj->status); - net = BUILD_NETMSG(obj->ct, type); + net = obj->cache->ops->build_msg(obj, type); nethdr_set_hello(net); dp("tx_list sq: %u fl:%u len:%u\n", @@ -551,7 +552,7 @@ static void ftfw_xmit(void) static void ftfw_enqueue(struct cache_object *obj, int type) { struct cache_ftfw *cn = - cache_get_extra(STATE(mode)->internal->data, obj); + cache_get_extra(STATE(mode)->internal->ct.data, obj); if (queue_in(rs_queue, &cn->qnode)) { queue_del(&cn->qnode); queue_add(STATE_SYNC(tx_queue), &cn->qnode); diff --git a/src/sync-mode.c b/src/sync-mode.c index 5351110..34d9706 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -1,6 +1,7 @@ /* - * (C) 2006-2007 by Pablo Neira Ayuso - * + * (C) 2006-2011 by Pablo Neira Ayuso + * (C) 2011 by Vyatta Inc. + * * 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 @@ -251,7 +252,7 @@ static void do_reset_cache_alarm(struct alarm_block *a, void *data) exit(EXIT_SUCCESS); } /* this is not required if events don't get lost */ - STATE(mode)->internal->flush(); + STATE(mode)->internal->ct.flush(); } static int init_sync(void) @@ -471,7 +472,7 @@ static int local_handler_sync(int fd, int type, void *data) switch(type) { case DUMP_INTERNAL: if (fork_process_new(CTD_PROC_ANY, 0, NULL, NULL) == 0) { - STATE(mode)->internal->dump(fd, NFCT_O_PLAIN); + STATE(mode)->internal->ct.dump(fd, NFCT_O_PLAIN); exit(EXIT_SUCCESS); } break; @@ -483,7 +484,7 @@ static int local_handler_sync(int fd, int type, void *data) break; case DUMP_INT_XML: if (fork_process_new(CTD_PROC_ANY, 0, NULL, NULL) == 0) { - STATE(mode)->internal->dump(fd, NFCT_O_XML); + STATE(mode)->internal->ct.dump(fd, NFCT_O_XML); exit(EXIT_SUCCESS); } break; @@ -512,14 +513,14 @@ static int local_handler_sync(int fd, int type, void *data) /* inmediate flush, remove pending flush scheduled if any */ del_alarm(&STATE_SYNC(reset_cache_alarm)); dlog(LOG_NOTICE, "flushing caches"); - STATE(mode)->internal->flush(); + STATE(mode)->internal->ct.flush(); STATE_SYNC(external)->flush(); break; case FLUSH_INT_CACHE: /* inmediate flush, remove pending flush scheduled if any */ del_alarm(&STATE_SYNC(reset_cache_alarm)); dlog(LOG_NOTICE, "flushing internal cache"); - STATE(mode)->internal->flush(); + STATE(mode)->internal->ct.flush(); break; case FLUSH_EXT_CACHE: dlog(LOG_NOTICE, "flushing external cache"); @@ -529,7 +530,7 @@ static int local_handler_sync(int fd, int type, void *data) killer(0); break; case STATS: - STATE(mode)->internal->stats(fd); + STATE(mode)->internal->ct.stats(fd); STATE_SYNC(external)->stats(fd); dump_traffic_stats(fd); multichannel_stats(STATE_SYNC(channel), fd); @@ -540,7 +541,7 @@ static int local_handler_sync(int fd, int type, void *data) multichannel_stats(STATE_SYNC(channel), fd); break; case STATS_CACHE: - STATE(mode)->internal->stats_ext(fd); + STATE(mode)->internal->ct.stats_ext(fd); STATE_SYNC(external)->stats_ext(fd); break; case STATS_LINK: diff --git a/src/sync-notrack.c b/src/sync-notrack.c index 06af58b..e25cfd8 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -76,7 +76,7 @@ static int do_cache_to_tx(void *data1, void *data2) { struct cache_object *obj = data2; struct cache_notrack *cn = - cache_get_extra(STATE(mode)->internal->data, obj); + cache_get_extra(STATE(mode)->internal->ct.data, obj); if (queue_add(STATE_SYNC(tx_queue), &cn->qnode) > 0) cache_object_get(obj); return 0; @@ -127,7 +127,7 @@ static int notrack_local(int fd, int type, void *data) if (CONFIG(sync).internal_cache_disable) { kernel_resync(); } else { - cache_iterate(STATE(mode)->internal->data, + cache_iterate(STATE(mode)->internal->ct.data, NULL, do_cache_to_tx); } break; @@ -148,7 +148,7 @@ static int digest_msg(const struct nethdr *net) if (CONFIG(sync).internal_cache_disable) { kernel_resync(); } else { - cache_iterate(STATE(mode)->internal->data, + cache_iterate(STATE(mode)->internal->ct.data, NULL, do_cache_to_tx); } return MSG_CTL; @@ -197,9 +197,9 @@ static int tx_queue_xmit(struct queue_node *n, const void *data2) struct nethdr *net; cn = (struct cache_ftfw *)n; - obj = cache_data_get_object(STATE(mode)->internal->data, cn); + obj = cache_data_get_object(STATE(mode)->internal->ct.data, cn); type = object_status_to_network_type(obj->status);; - net = BUILD_NETMSG(obj->ct, type); + net = obj->cache->ops->build_msg(obj, type); multichannel_send(STATE_SYNC(channel), net); queue_del(n); @@ -219,7 +219,7 @@ static void notrack_xmit(void) static void notrack_enqueue(struct cache_object *obj, int query) { struct cache_notrack *cn = - cache_get_extra(STATE(mode)->internal->data, obj); + cache_get_extra(STATE(mode)->internal->ct.data, obj); if (queue_add(STATE_SYNC(tx_queue), &cn->qnode) > 0) cache_object_get(obj); } -- cgit v1.2.3 From 395ac42f5f1844834698f29032b101c2890b6772 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 27 Oct 2011 12:04:50 +0200 Subject: conntrackd: generalize external handlers to prepare expectation support This patch contains cleanups to prepare the expectation support for external handlers. Mostly renamings. I have also updated the file headers to include Vyatta in the copyright statement. Signed-off-by: Pablo Neira Ayuso --- include/external.h | 18 ++++++++++-------- src/external_cache.c | 39 +++++++++++++++++++++------------------ src/external_inject.c | 37 ++++++++++++++++++++----------------- src/sync-mode.c | 22 +++++++++++----------- 4 files changed, 62 insertions(+), 54 deletions(-) (limited to 'src') diff --git a/include/external.h b/include/external.h index 6619967..eef0e42 100644 --- a/include/external.h +++ b/include/external.h @@ -7,15 +7,17 @@ struct external_handler { int (*init)(void); void (*close)(void); - void (*new)(struct nf_conntrack *ct); - void (*update)(struct nf_conntrack *ct); - void (*destroy)(struct nf_conntrack *ct); + struct { + void (*new)(struct nf_conntrack *ct); + void (*upd)(struct nf_conntrack *ct); + void (*del)(struct nf_conntrack *ct); - void (*dump)(int fd, int type); - void (*flush)(void); - int (*commit)(struct nfct_handle *h, int fd); - void (*stats)(int fd); - void (*stats_ext)(int fd); + void (*dump)(int fd, int type); + void (*flush)(void); + int (*commit)(struct nfct_handle *h, int fd); + void (*stats)(int fd); + void (*stats_ext)(int fd); + } ct; }; extern struct external_handler external_cache; diff --git a/src/external_cache.c b/src/external_cache.c index 073f309..4b6fa6f 100644 --- a/src/external_cache.c +++ b/src/external_cache.c @@ -1,6 +1,7 @@ /* - * (C) 2006-2009 by Pablo Neira Ayuso - * + * (C) 2006-2011 by Pablo Neira Ayuso + * (C) 2011 by Vyatta Inc. + * * 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 @@ -43,7 +44,7 @@ static void external_cache_close(void) cache_destroy(external); } -static void external_cache_new(struct nf_conntrack *ct) +static void external_cache_ct_new(struct nf_conntrack *ct) { struct cache_object *obj; int id; @@ -66,12 +67,12 @@ retry: } } -static void external_cache_upd(struct nf_conntrack *ct) +static void external_cache_ct_upd(struct nf_conntrack *ct) { cache_update_force(external, ct); } -static void external_cache_del(struct nf_conntrack *ct) +static void external_cache_ct_del(struct nf_conntrack *ct) { struct cache_object *obj; int id; @@ -83,12 +84,12 @@ static void external_cache_del(struct nf_conntrack *ct) } } -static void external_cache_dump(int fd, int type) +static void external_cache_ct_dump(int fd, int type) { cache_dump(external, fd, type); } -static int external_cache_commit(struct nfct_handle *h, int fd) +static int external_cache_ct_commit(struct nfct_handle *h, int fd) { if (!cache_commit(external, h, fd)) { dlog(LOG_NOTICE, "commit already in progress, skipping"); @@ -98,17 +99,17 @@ static int external_cache_commit(struct nfct_handle *h, int fd) return LOCAL_RET_STOLEN; } -static void external_cache_flush(void) +static void external_cache_ct_flush(void) { cache_flush(external); } -static void external_cache_stats(int fd) +static void external_cache_ct_stats(int fd) { cache_stats(external, fd); } -static void external_cache_stats_ext(int fd) +static void external_cache_ct_stats_ext(int fd) { cache_stats_extended(external, fd); } @@ -116,12 +117,14 @@ static void external_cache_stats_ext(int fd) struct external_handler external_cache = { .init = external_cache_init, .close = external_cache_close, - .new = external_cache_new, - .update = external_cache_upd, - .destroy = external_cache_del, - .dump = external_cache_dump, - .commit = external_cache_commit, - .flush = external_cache_flush, - .stats = external_cache_stats, - .stats_ext = external_cache_stats_ext, + .ct = { + .new = external_cache_ct_new, + .upd = external_cache_ct_upd, + .del = external_cache_ct_del, + .dump = external_cache_ct_dump, + .commit = external_cache_ct_commit, + .flush = external_cache_ct_flush, + .stats = external_cache_ct_stats, + .stats_ext = external_cache_ct_stats_ext, + }, }; diff --git a/src/external_inject.c b/src/external_inject.c index 56e24a3..ba5f3d1 100644 --- a/src/external_inject.c +++ b/src/external_inject.c @@ -1,6 +1,7 @@ /* - * (C) 2009 by Pablo Neira Ayuso - * + * (C) 2006-2011 by Pablo Neira Ayuso + * (C) 2011 by Vyatta Inc. + * * 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 @@ -59,7 +60,7 @@ static void external_inject_close(void) nfct_close(inject); } -static void external_inject_new(struct nf_conntrack *ct) +static void external_inject_ct_new(struct nf_conntrack *ct) { int ret, retry = 1; @@ -87,7 +88,7 @@ retry: } } -static void external_inject_upd(struct nf_conntrack *ct) +static void external_inject_ct_upd(struct nf_conntrack *ct) { int ret; @@ -128,7 +129,7 @@ static void external_inject_upd(struct nf_conntrack *ct) dlog_ct(STATE(log), ct, NFCT_O_PLAIN); } -static void external_inject_del(struct nf_conntrack *ct) +static void external_inject_ct_del(struct nf_conntrack *ct) { if (nl_destroy_conntrack(inject, ct) == -1) { if (errno != ENOENT) { @@ -141,21 +142,21 @@ static void external_inject_del(struct nf_conntrack *ct) } } -static void external_inject_dump(int fd, int type) +static void external_inject_ct_dump(int fd, int type) { } -static int external_inject_commit(struct nfct_handle *h, int fd) +static int external_inject_ct_commit(struct nfct_handle *h, int fd) { /* close the commit socket. */ return LOCAL_RET_OK; } -static void external_inject_flush(void) +static void external_inject_ct_flush(void) { } -static void external_inject_stats(int fd) +static void external_inject_ct_stats(int fd) { char buf[512]; int size; @@ -177,12 +178,14 @@ static void external_inject_stats(int fd) struct external_handler external_inject = { .init = external_inject_init, .close = external_inject_close, - .new = external_inject_new, - .update = external_inject_upd, - .destroy = external_inject_del, - .dump = external_inject_dump, - .commit = external_inject_commit, - .flush = external_inject_flush, - .stats = external_inject_stats, - .stats_ext = external_inject_stats, + .ct = { + .new = external_inject_ct_new, + .upd = external_inject_ct_upd, + .del = external_inject_ct_del, + .dump = external_inject_ct_dump, + .commit = external_inject_ct_commit, + .flush = external_inject_ct_flush, + .stats = external_inject_ct_stats, + .stats_ext = external_inject_ct_stats, + }, }; diff --git a/src/sync-mode.c b/src/sync-mode.c index 34d9706..7f019f7 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -88,13 +88,13 @@ do_channel_handler_step(int i, struct nethdr *net, size_t remain) switch(net->type) { case NET_T_STATE_NEW: - STATE_SYNC(external)->new(ct); + STATE_SYNC(external)->ct.new(ct); break; case NET_T_STATE_UPD: - STATE_SYNC(external)->update(ct); + STATE_SYNC(external)->ct.upd(ct); break; case NET_T_STATE_DEL: - STATE_SYNC(external)->destroy(ct); + STATE_SYNC(external)->ct.del(ct); break; default: STATE_SYNC(error).msg_rcv_malformed++; @@ -387,7 +387,7 @@ static void run_sync(fd_set *readfds) if (FD_ISSET(get_read_evfd(STATE_SYNC(commit).evfd), readfds)) { read_evfd(STATE_SYNC(commit).evfd); - STATE_SYNC(external)->commit(STATE_SYNC(commit).h, 0); + STATE_SYNC(external)->ct.commit(STATE_SYNC(commit).h, 0); } /* flush pending messages */ @@ -478,7 +478,7 @@ static int local_handler_sync(int fd, int type, void *data) break; case DUMP_EXTERNAL: if (fork_process_new(CTD_PROC_ANY, 0, NULL, NULL) == 0) { - STATE_SYNC(external)->dump(fd, NFCT_O_PLAIN); + STATE_SYNC(external)->ct.dump(fd, NFCT_O_PLAIN); exit(EXIT_SUCCESS); } break; @@ -490,7 +490,7 @@ static int local_handler_sync(int fd, int type, void *data) break; case DUMP_EXT_XML: if (fork_process_new(CTD_PROC_ANY, 0, NULL, NULL) == 0) { - STATE_SYNC(external)->dump(fd, NFCT_O_XML); + STATE_SYNC(external)->ct.dump(fd, NFCT_O_XML); exit(EXIT_SUCCESS); } break; @@ -499,7 +499,7 @@ static int local_handler_sync(int fd, int type, void *data) del_alarm(&STATE_SYNC(reset_cache_alarm)); dlog(LOG_NOTICE, "committing external cache"); - ret = STATE_SYNC(external)->commit(STATE_SYNC(commit).h, fd); + ret = STATE_SYNC(external)->ct.commit(STATE_SYNC(commit).h, fd); break; case RESET_TIMERS: if (!alarm_pending(&STATE_SYNC(reset_cache_alarm))) { @@ -514,7 +514,7 @@ static int local_handler_sync(int fd, int type, void *data) del_alarm(&STATE_SYNC(reset_cache_alarm)); dlog(LOG_NOTICE, "flushing caches"); STATE(mode)->internal->ct.flush(); - STATE_SYNC(external)->flush(); + STATE_SYNC(external)->ct.flush(); break; case FLUSH_INT_CACHE: /* inmediate flush, remove pending flush scheduled if any */ @@ -524,14 +524,14 @@ static int local_handler_sync(int fd, int type, void *data) break; case FLUSH_EXT_CACHE: dlog(LOG_NOTICE, "flushing external cache"); - STATE_SYNC(external)->flush(); + STATE_SYNC(external)->ct.flush(); break; case KILL: killer(0); break; case STATS: STATE(mode)->internal->ct.stats(fd); - STATE_SYNC(external)->stats(fd); + STATE_SYNC(external)->ct.stats(fd); dump_traffic_stats(fd); multichannel_stats(STATE_SYNC(channel), fd); dump_stats_sync(fd); @@ -542,7 +542,7 @@ static int local_handler_sync(int fd, int type, void *data) break; case STATS_CACHE: STATE(mode)->internal->ct.stats_ext(fd); - STATE_SYNC(external)->stats_ext(fd); + STATE_SYNC(external)->ct.stats_ext(fd); break; case STATS_LINK: multichannel_stats_extended(STATE_SYNC(channel), -- cgit v1.2.3 From 931c0eff309d8c7277ebe6d670fd72d8fbe3c674 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 4 Jan 2012 14:30:02 +0100 Subject: conntrackd: generalize/cleanup network message building/parsing This patch generalizes the network message building and parsing to prepare the upcoming expectation support. Basically, it renames: - NET_T_STATE_* by NET_T_STATE_CT_*, as I plan to add NET_T_STATE_EXP_* - BUILD_NETMSG by BUILD_NETMSG_FROM_CT, and build_payload by ct2msg. I plan to add exp2msg. - parse_payload by msg2ct, since I plan to add msg2exp. - modify object_status_to_network_type to prepare the support of expectations. - add prefix ct_ to all parsing functions in parse.c, as we will have similar functions to convert messages to expectation objects. Signed-off-by: Pablo Neira Ayuso --- include/cache.h | 3 +- include/network.h | 21 +++++++------ src/build.c | 81 ++++++++++++++++++++++++------------------------ src/internal_bypass.c | 6 ++-- src/internal_cache.c | 12 ++++---- src/network.c | 19 +++++++----- src/parse.c | 85 ++++++++++++++++++++++++++------------------------- src/sync-alarm.c | 4 +-- src/sync-ftfw.c | 2 +- src/sync-mode.c | 44 +++++++++++++++++--------- src/sync-notrack.c | 9 +++--- 11 files changed, 155 insertions(+), 131 deletions(-) (limited to 'src') diff --git a/include/cache.h b/include/cache.h index a42e395..02bb386 100644 --- a/include/cache.h +++ b/include/cache.h @@ -21,7 +21,8 @@ enum { C_OBJ_NONE = 0, /* not in the cache */ C_OBJ_NEW, /* just added to the cache */ C_OBJ_ALIVE, /* in the cache, alive */ - C_OBJ_DEAD /* still in the cache, but dead */ + C_OBJ_DEAD, /* still in the cache, but dead */ + C_OBJ_MAX }; struct cache; diff --git a/include/network.h b/include/network.h index 567317b..d0531b9 100644 --- a/include/network.h +++ b/include/network.h @@ -25,10 +25,10 @@ struct nethdr { #define NETHDR_SIZ nethdr_align(sizeof(struct nethdr)) enum nethdr_type { - NET_T_STATE_NEW = 0, - NET_T_STATE_UPD, - NET_T_STATE_DEL, - NET_T_STATE_MAX = NET_T_STATE_DEL, + NET_T_STATE_CT_NEW = 0, + NET_T_STATE_CT_UPD, + NET_T_STATE_CT_DEL, + NET_T_STATE_MAX = NET_T_STATE_CT_DEL, NET_T_CTL = 10, }; @@ -37,7 +37,9 @@ int nethdr_size(int len); void nethdr_set(struct nethdr *net, int type); void nethdr_set_ack(struct nethdr *net); void nethdr_set_ctl(struct nethdr *net); -int object_status_to_network_type(int status); + +struct cache_object; +int object_status_to_network_type(struct cache_object *obj); #define NETHDR_DATA(x) \ (struct netattr *)(((char *)x) + NETHDR_SIZ) @@ -79,13 +81,13 @@ enum { MSG_BAD, }; -#define BUILD_NETMSG(ct, query) \ +#define BUILD_NETMSG_FROM_CT(ct, query) \ ({ \ static char __net[4096]; \ struct nethdr *__hdr = (struct nethdr *) __net; \ memset(__hdr, 0, NETHDR_SIZ); \ nethdr_set(__hdr, query); \ - build_payload(ct, __hdr); \ + ct2msg(ct, __hdr); \ HDR_HOST2NETWORK(__hdr); \ __hdr; \ }) @@ -234,8 +236,7 @@ struct nta_attr_natseqadj { uint32_t repl_seq_offset_after; }; -void build_payload(const struct nf_conntrack *ct, struct nethdr *n); - -int parse_payload(struct nf_conntrack *ct, struct nethdr *n, size_t remain); +void ct2msg(const struct nf_conntrack *ct, struct nethdr *n); +int msg2ct(struct nf_conntrack *ct, struct nethdr *n, size_t remain); #endif diff --git a/src/build.c b/src/build.c index a495872..9c3687c 100644 --- a/src/build.c +++ b/src/build.c @@ -1,6 +1,7 @@ /* - * (C) 2006-2008 by Pablo Neira Ayuso - * + * (C) 2006-2011 by Pablo Neira Ayuso + * (C) 2011 by Vyatta Inc. + * * 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 @@ -42,14 +43,14 @@ addattr(struct nethdr *n, int attr, const void *data, size_t len) } static inline void -__build_u8(const struct nf_conntrack *ct, int a, struct nethdr *n, int b) +ct_build_u8(const struct nf_conntrack *ct, int a, struct nethdr *n, int b) { void *ptr = put_header(n, b, sizeof(uint8_t)); memcpy(ptr, nfct_get_attr(ct, a), sizeof(uint8_t)); } static inline void -__build_u16(const struct nf_conntrack *ct, int a, struct nethdr *n, int b) +ct_build_u16(const struct nf_conntrack *ct, int a, struct nethdr *n, int b) { uint16_t data = nfct_get_attr_u16(ct, a); data = htons(data); @@ -57,7 +58,7 @@ __build_u16(const struct nf_conntrack *ct, int a, struct nethdr *n, int b) } static inline void -__build_u32(const struct nf_conntrack *ct, int a, struct nethdr *n, int b) +ct_build_u32(const struct nf_conntrack *ct, int a, struct nethdr *n, int b) { uint32_t data = nfct_get_attr_u32(ct, a); data = htonl(data); @@ -65,7 +66,7 @@ __build_u32(const struct nf_conntrack *ct, int a, struct nethdr *n, int b) } static inline void -__build_group(const struct nf_conntrack *ct, int a, struct nethdr *n, +ct_build_group(const struct nf_conntrack *ct, int a, struct nethdr *n, int b, int size) { void *ptr = put_header(n, b, size); @@ -73,7 +74,7 @@ __build_group(const struct nf_conntrack *ct, int a, struct nethdr *n, } static inline void -__build_natseqadj(const struct nf_conntrack *ct, struct nethdr *n) +ct_build_natseqadj(const struct nf_conntrack *ct, struct nethdr *n) { struct nta_attr_natseqadj data = { .orig_seq_correction_pos = @@ -99,54 +100,54 @@ static enum nf_conntrack_attr nat_type[] = static void build_l4proto_tcp(const struct nf_conntrack *ct, struct nethdr *n) { - __build_group(ct, ATTR_GRP_ORIG_PORT, n, NTA_PORT, + ct_build_group(ct, ATTR_GRP_ORIG_PORT, n, NTA_PORT, sizeof(struct nfct_attr_grp_port)); if (!nfct_attr_is_set(ct, ATTR_TCP_STATE)) return; - __build_u8(ct, ATTR_TCP_STATE, n, NTA_TCP_STATE); + ct_build_u8(ct, ATTR_TCP_STATE, n, NTA_TCP_STATE); if (CONFIG(sync).tcp_window_tracking) { - __build_u8(ct, ATTR_TCP_WSCALE_ORIG, n, NTA_TCP_WSCALE_ORIG); - __build_u8(ct, ATTR_TCP_WSCALE_REPL, n, NTA_TCP_WSCALE_REPL); + ct_build_u8(ct, ATTR_TCP_WSCALE_ORIG, n, NTA_TCP_WSCALE_ORIG); + ct_build_u8(ct, ATTR_TCP_WSCALE_REPL, n, NTA_TCP_WSCALE_REPL); } } static void build_l4proto_sctp(const struct nf_conntrack *ct, struct nethdr *n) { - __build_group(ct, ATTR_GRP_ORIG_PORT, n, NTA_PORT, + ct_build_group(ct, ATTR_GRP_ORIG_PORT, n, NTA_PORT, sizeof(struct nfct_attr_grp_port)); if (!nfct_attr_is_set(ct, ATTR_SCTP_STATE)) return; - __build_u8(ct, ATTR_SCTP_STATE, n, NTA_SCTP_STATE); - __build_u32(ct, ATTR_SCTP_VTAG_ORIG, n, NTA_SCTP_VTAG_ORIG); - __build_u32(ct, ATTR_SCTP_VTAG_REPL, n, NTA_SCTP_VTAG_REPL); + ct_build_u8(ct, ATTR_SCTP_STATE, n, NTA_SCTP_STATE); + ct_build_u32(ct, ATTR_SCTP_VTAG_ORIG, n, NTA_SCTP_VTAG_ORIG); + ct_build_u32(ct, ATTR_SCTP_VTAG_REPL, n, NTA_SCTP_VTAG_REPL); } static void build_l4proto_dccp(const struct nf_conntrack *ct, struct nethdr *n) { - __build_group(ct, ATTR_GRP_ORIG_PORT, n, NTA_PORT, + ct_build_group(ct, ATTR_GRP_ORIG_PORT, n, NTA_PORT, sizeof(struct nfct_attr_grp_port)); if (!nfct_attr_is_set(ct, ATTR_DCCP_STATE)) return; - __build_u8(ct, ATTR_DCCP_STATE, n, NTA_DCCP_STATE); - __build_u8(ct, ATTR_DCCP_ROLE, n, NTA_DCCP_ROLE); + ct_build_u8(ct, ATTR_DCCP_STATE, n, NTA_DCCP_STATE); + ct_build_u8(ct, ATTR_DCCP_ROLE, n, NTA_DCCP_ROLE); } static void build_l4proto_icmp(const struct nf_conntrack *ct, struct nethdr *n) { - __build_u8(ct, ATTR_ICMP_TYPE, n, NTA_ICMP_TYPE); - __build_u8(ct, ATTR_ICMP_CODE, n, NTA_ICMP_CODE); - __build_u16(ct, ATTR_ICMP_ID, n, NTA_ICMP_ID); + ct_build_u8(ct, ATTR_ICMP_TYPE, n, NTA_ICMP_TYPE); + ct_build_u8(ct, ATTR_ICMP_CODE, n, NTA_ICMP_CODE); + ct_build_u16(ct, ATTR_ICMP_ID, n, NTA_ICMP_ID); } static void build_l4proto_udp(const struct nf_conntrack *ct, struct nethdr *n) { - __build_group(ct, ATTR_GRP_ORIG_PORT, n, NTA_PORT, + ct_build_group(ct, ATTR_GRP_ORIG_PORT, n, NTA_PORT, sizeof(struct nfct_attr_grp_port)); } @@ -165,45 +166,45 @@ static struct build_l4proto { [IPPROTO_UDP] = { .build = build_l4proto_udp }, }; -void build_payload(const struct nf_conntrack *ct, struct nethdr *n) +void ct2msg(const struct nf_conntrack *ct, struct nethdr *n) { uint8_t l4proto = nfct_get_attr_u8(ct, ATTR_L4PROTO); if (nfct_attr_grp_is_set(ct, ATTR_GRP_ORIG_IPV4)) { - __build_group(ct, ATTR_GRP_ORIG_IPV4, n, NTA_IPV4, + ct_build_group(ct, ATTR_GRP_ORIG_IPV4, n, NTA_IPV4, sizeof(struct nfct_attr_grp_ipv4)); } else if (nfct_attr_grp_is_set(ct, ATTR_GRP_ORIG_IPV6)) { - __build_group(ct, ATTR_GRP_ORIG_IPV6, n, NTA_IPV6, + ct_build_group(ct, ATTR_GRP_ORIG_IPV6, n, NTA_IPV6, sizeof(struct nfct_attr_grp_ipv6)); } - __build_u32(ct, ATTR_STATUS, n, NTA_STATUS); - __build_u8(ct, ATTR_L4PROTO, n, NTA_L4PROTO); + ct_build_u32(ct, ATTR_STATUS, n, NTA_STATUS); + ct_build_u8(ct, ATTR_L4PROTO, n, NTA_L4PROTO); if (l4proto_fcn[l4proto].build) l4proto_fcn[l4proto].build(ct, n); if (!CONFIG(commit_timeout) && nfct_attr_is_set(ct, ATTR_TIMEOUT)) - __build_u32(ct, ATTR_TIMEOUT, n, NTA_TIMEOUT); + ct_build_u32(ct, ATTR_TIMEOUT, n, NTA_TIMEOUT); if (nfct_attr_is_set(ct, ATTR_MARK)) - __build_u32(ct, ATTR_MARK, n, NTA_MARK); + ct_build_u32(ct, ATTR_MARK, n, NTA_MARK); /* setup the master conntrack */ if (nfct_attr_grp_is_set(ct, ATTR_GRP_MASTER_IPV4)) { - __build_group(ct, ATTR_GRP_MASTER_IPV4, n, NTA_MASTER_IPV4, + ct_build_group(ct, ATTR_GRP_MASTER_IPV4, n, NTA_MASTER_IPV4, sizeof(struct nfct_attr_grp_ipv4)); - __build_u8(ct, ATTR_MASTER_L4PROTO, n, NTA_MASTER_L4PROTO); + ct_build_u8(ct, ATTR_MASTER_L4PROTO, n, NTA_MASTER_L4PROTO); if (nfct_attr_grp_is_set(ct, ATTR_GRP_MASTER_PORT)) { - __build_group(ct, ATTR_GRP_MASTER_PORT, + ct_build_group(ct, ATTR_GRP_MASTER_PORT, n, NTA_MASTER_PORT, sizeof(struct nfct_attr_grp_port)); } } else if (nfct_attr_grp_is_set(ct, ATTR_GRP_MASTER_IPV6)) { - __build_group(ct, ATTR_GRP_MASTER_IPV6, n, NTA_MASTER_IPV6, + ct_build_group(ct, ATTR_GRP_MASTER_IPV6, n, NTA_MASTER_IPV6, sizeof(struct nfct_attr_grp_ipv6)); - __build_u8(ct, ATTR_MASTER_L4PROTO, n, NTA_MASTER_L4PROTO); + ct_build_u8(ct, ATTR_MASTER_L4PROTO, n, NTA_MASTER_L4PROTO); if (nfct_attr_grp_is_set(ct, ATTR_GRP_MASTER_PORT)) { - __build_group(ct, ATTR_GRP_MASTER_PORT, + ct_build_group(ct, ATTR_GRP_MASTER_PORT, n, NTA_MASTER_PORT, sizeof(struct nfct_attr_grp_port)); } @@ -211,15 +212,15 @@ void build_payload(const struct nf_conntrack *ct, struct nethdr *n) /* NAT */ if (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) - __build_u32(ct, ATTR_REPL_IPV4_DST, n, NTA_SNAT_IPV4); + ct_build_u32(ct, ATTR_REPL_IPV4_DST, n, NTA_SNAT_IPV4); if (nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) - __build_u32(ct, ATTR_REPL_IPV4_SRC, n, NTA_DNAT_IPV4); + ct_build_u32(ct, ATTR_REPL_IPV4_SRC, n, NTA_DNAT_IPV4); if (nfct_getobjopt(ct, NFCT_GOPT_IS_SPAT)) - __build_u16(ct, ATTR_REPL_PORT_DST, n, NTA_SPAT_PORT); + ct_build_u16(ct, ATTR_REPL_PORT_DST, n, NTA_SPAT_PORT); if (nfct_getobjopt(ct, NFCT_GOPT_IS_DPAT)) - __build_u16(ct, ATTR_REPL_PORT_SRC, n, NTA_DPAT_PORT); + ct_build_u16(ct, ATTR_REPL_PORT_SRC, n, NTA_DPAT_PORT); /* NAT sequence adjustment */ if (nfct_attr_is_set_array(ct, nat_type, 6)) - __build_natseqadj(ct, n); + ct_build_natseqadj(ct, n); } diff --git a/src/internal_bypass.c b/src/internal_bypass.c index 8ecec34..98717f3 100644 --- a/src/internal_bypass.c +++ b/src/internal_bypass.c @@ -118,7 +118,7 @@ static void internal_bypass_ct_event_new(struct nf_conntrack *ct, int origin) if (origin != CTD_ORIGIN_NOT_ME) return; - net = BUILD_NETMSG(ct, NET_T_STATE_NEW); + net = BUILD_NETMSG_FROM_CT(ct, NET_T_STATE_CT_NEW); multichannel_send(STATE_SYNC(channel), net); internal_bypass_stats.new++; } @@ -131,7 +131,7 @@ static void internal_bypass_ct_event_upd(struct nf_conntrack *ct, int origin) if (origin != CTD_ORIGIN_NOT_ME) return; - net = BUILD_NETMSG(ct, NET_T_STATE_UPD); + net = BUILD_NETMSG_FROM_CT(ct, NET_T_STATE_CT_UPD); multichannel_send(STATE_SYNC(channel), net); internal_bypass_stats.upd++; } @@ -144,7 +144,7 @@ static int internal_bypass_ct_event_del(struct nf_conntrack *ct, int origin) if (origin != CTD_ORIGIN_NOT_ME) return 1; - net = BUILD_NETMSG(ct, NET_T_STATE_DEL); + net = BUILD_NETMSG_FROM_CT(ct, NET_T_STATE_CT_DEL); multichannel_send(STATE_SYNC(channel), net); internal_bypass_stats.del++; diff --git a/src/internal_cache.c b/src/internal_cache.c index 7a698e6..952327d 100644 --- a/src/internal_cache.c +++ b/src/internal_cache.c @@ -81,7 +81,7 @@ static int internal_cache_ct_purge_step(void *data1, void *data2) if (!STATE(get_retval)) { if (obj->status != C_OBJ_DEAD) { cache_object_set_status(obj, C_OBJ_DEAD); - sync_send(obj, NET_T_STATE_DEL); + sync_send(obj, NET_T_STATE_CT_DEL); cache_object_put(obj); } } @@ -117,10 +117,10 @@ internal_cache_ct_resync(enum nf_conntrack_msg_type type, switch (obj->status) { case C_OBJ_NEW: - sync_send(obj, NET_T_STATE_NEW); + sync_send(obj, NET_T_STATE_CT_NEW); break; case C_OBJ_ALIVE: - sync_send(obj, NET_T_STATE_UPD); + sync_send(obj, NET_T_STATE_CT_UPD); break; } return NFCT_CB_CONTINUE; @@ -155,7 +155,7 @@ retry: * processes or the kernel, but don't propagate events that * have been triggered by conntrackd itself, eg. commits. */ if (origin == CTD_ORIGIN_NOT_ME) - sync_send(obj, NET_T_STATE_NEW); + sync_send(obj, NET_T_STATE_CT_NEW); } else { cache_del(STATE(mode)->internal->ct.data, obj); cache_object_free(obj); @@ -176,7 +176,7 @@ static void internal_cache_ct_event_upd(struct nf_conntrack *ct, int origin) return; if (origin == CTD_ORIGIN_NOT_ME) - sync_send(obj, NET_T_STATE_UPD); + sync_send(obj, NET_T_STATE_CT_UPD); } static int internal_cache_ct_event_del(struct nf_conntrack *ct, int origin) @@ -196,7 +196,7 @@ static int internal_cache_ct_event_del(struct nf_conntrack *ct, int origin) if (obj->status != C_OBJ_DEAD) { cache_object_set_status(obj, C_OBJ_DEAD); if (origin == CTD_ORIGIN_NOT_ME) { - sync_send(obj, NET_T_STATE_DEL); + sync_send(obj, NET_T_STATE_CT_DEL); } cache_object_put(obj); } diff --git a/src/network.c b/src/network.c index 6a66a2b..cadc466 100644 --- a/src/network.c +++ b/src/network.c @@ -1,6 +1,7 @@ /* - * (C) 2006-2007 by Pablo Neira Ayuso - * + * (C) 2006-2011 by Pablo Neira Ayuso + * (C) 2011 by Vyatta Inc. + * * 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 @@ -119,13 +120,15 @@ int nethdr_track_is_seq_set() #include "cache.h" -static int status2type[] = { - [C_OBJ_NEW] = NET_T_STATE_NEW, - [C_OBJ_ALIVE] = NET_T_STATE_UPD, - [C_OBJ_DEAD] = NET_T_STATE_DEL, +static int status2type[CACHE_T_MAX][C_OBJ_MAX] = { + [CACHE_T_CT] = { + [C_OBJ_NEW] = NET_T_STATE_CT_NEW, + [C_OBJ_ALIVE] = NET_T_STATE_CT_UPD, + [C_OBJ_DEAD] = NET_T_STATE_CT_DEL, + }, }; -int object_status_to_network_type(int status) +int object_status_to_network_type(struct cache_object *obj) { - return status2type[status]; + return status2type[obj->cache->type][obj->status]; } diff --git a/src/parse.c b/src/parse.c index 7e60597..0718128 100644 --- a/src/parse.c +++ b/src/parse.c @@ -1,6 +1,7 @@ /* - * (C) 2006-2007 by Pablo Neira Ayuso - * + * (C) 2006-2011 by Pablo Neira Ayuso + * (C) 2011 by Vyatta Inc. + * * 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 @@ -24,184 +25,184 @@ #define ssizeof(x) (int)sizeof(x) #endif -static void parse_u8(struct nf_conntrack *ct, int attr, void *data); -static void parse_u16(struct nf_conntrack *ct, int attr, void *data); -static void parse_u32(struct nf_conntrack *ct, int attr, void *data); -static void parse_group(struct nf_conntrack *ct, int attr, void *data); -static void parse_nat_seq_adj(struct nf_conntrack *ct, int attr, void *data); +static void ct_parse_u8(struct nf_conntrack *ct, int attr, void *data); +static void ct_parse_u16(struct nf_conntrack *ct, int attr, void *data); +static void ct_parse_u32(struct nf_conntrack *ct, int attr, void *data); +static void ct_parse_group(struct nf_conntrack *ct, int attr, void *data); +static void ct_parse_nat_seq_adj(struct nf_conntrack *ct, int attr, void *data); -struct parser { +struct ct_parser { void (*parse)(struct nf_conntrack *ct, int attr, void *data); int attr; int size; }; -static struct parser h[NTA_MAX] = { +static struct ct_parser h[NTA_MAX] = { [NTA_IPV4] = { - .parse = parse_group, + .parse = ct_parse_group, .attr = ATTR_GRP_ORIG_IPV4, .size = NTA_SIZE(sizeof(struct nfct_attr_grp_ipv4)), }, [NTA_IPV6] = { - .parse = parse_group, + .parse = ct_parse_group, .attr = ATTR_GRP_ORIG_IPV6, .size = NTA_SIZE(sizeof(struct nfct_attr_grp_ipv6)), }, [NTA_PORT] = { - .parse = parse_group, + .parse = ct_parse_group, .attr = ATTR_GRP_ORIG_PORT, .size = NTA_SIZE(sizeof(struct nfct_attr_grp_port)), }, [NTA_L4PROTO] = { - .parse = parse_u8, + .parse = ct_parse_u8, .attr = ATTR_L4PROTO, .size = NTA_SIZE(sizeof(uint8_t)), }, [NTA_TCP_STATE] = { - .parse = parse_u8, + .parse = ct_parse_u8, .attr = ATTR_TCP_STATE, .size = NTA_SIZE(sizeof(uint8_t)), }, [NTA_STATUS] = { - .parse = parse_u32, + .parse = ct_parse_u32, .attr = ATTR_STATUS, .size = NTA_SIZE(sizeof(uint32_t)), }, [NTA_MARK] = { - .parse = parse_u32, + .parse = ct_parse_u32, .attr = ATTR_MARK, .size = NTA_SIZE(sizeof(uint32_t)), }, [NTA_TIMEOUT] = { - .parse = parse_u32, + .parse = ct_parse_u32, .attr = ATTR_TIMEOUT, .size = NTA_SIZE(sizeof(uint32_t)), }, [NTA_MASTER_IPV4] = { - .parse = parse_group, + .parse = ct_parse_group, .attr = ATTR_GRP_MASTER_IPV4, .size = NTA_SIZE(sizeof(struct nfct_attr_grp_ipv4)), }, [NTA_MASTER_IPV6] = { - .parse = parse_group, + .parse = ct_parse_group, .attr = ATTR_GRP_MASTER_IPV6, .size = NTA_SIZE(sizeof(struct nfct_attr_grp_ipv6)), }, [NTA_MASTER_L4PROTO] = { - .parse = parse_u8, + .parse = ct_parse_u8, .attr = ATTR_MASTER_L4PROTO, .size = NTA_SIZE(sizeof(uint8_t)), }, [NTA_MASTER_PORT] = { - .parse = parse_group, + .parse = ct_parse_group, .attr = ATTR_GRP_MASTER_PORT, .size = NTA_SIZE(sizeof(struct nfct_attr_grp_port)), }, [NTA_SNAT_IPV4] = { - .parse = parse_u32, + .parse = ct_parse_u32, .attr = ATTR_SNAT_IPV4, .size = NTA_SIZE(sizeof(uint32_t)), }, [NTA_DNAT_IPV4] = { - .parse = parse_u32, + .parse = ct_parse_u32, .attr = ATTR_DNAT_IPV4, .size = NTA_SIZE(sizeof(uint32_t)), }, [NTA_SPAT_PORT] = { - .parse = parse_u16, + .parse = ct_parse_u16, .attr = ATTR_SNAT_PORT, .size = NTA_SIZE(sizeof(uint16_t)), }, [NTA_DPAT_PORT] = { - .parse = parse_u16, + .parse = ct_parse_u16, .attr = ATTR_DNAT_PORT, .size = NTA_SIZE(sizeof(uint16_t)), }, [NTA_NAT_SEQ_ADJ] = { - .parse = parse_nat_seq_adj, + .parse = ct_parse_nat_seq_adj, .size = NTA_SIZE(sizeof(struct nta_attr_natseqadj)), }, [NTA_SCTP_STATE] = { - .parse = parse_u8, + .parse = ct_parse_u8, .attr = ATTR_SCTP_STATE, .size = NTA_SIZE(sizeof(uint8_t)), }, [NTA_SCTP_VTAG_ORIG] = { - .parse = parse_u32, + .parse = ct_parse_u32, .attr = ATTR_SCTP_VTAG_ORIG, .size = NTA_SIZE(sizeof(uint32_t)), }, [NTA_SCTP_VTAG_REPL] = { - .parse = parse_u32, + .parse = ct_parse_u32, .attr = ATTR_SCTP_VTAG_REPL, .size = NTA_SIZE(sizeof(uint32_t)), }, [NTA_DCCP_STATE] = { - .parse = parse_u8, + .parse = ct_parse_u8, .attr = ATTR_DCCP_STATE, .size = NTA_SIZE(sizeof(uint8_t)), }, [NTA_DCCP_ROLE] = { - .parse = parse_u8, + .parse = ct_parse_u8, .attr = ATTR_DCCP_ROLE, .size = NTA_SIZE(sizeof(uint8_t)), }, [NTA_ICMP_TYPE] = { - .parse = parse_u8, + .parse = ct_parse_u8, .attr = ATTR_ICMP_TYPE, .size = NTA_SIZE(sizeof(uint8_t)), }, [NTA_ICMP_CODE] = { - .parse = parse_u8, + .parse = ct_parse_u8, .attr = ATTR_ICMP_CODE, .size = NTA_SIZE(sizeof(uint8_t)), }, [NTA_ICMP_ID] = { - .parse = parse_u16, + .parse = ct_parse_u16, .attr = ATTR_ICMP_ID, .size = NTA_SIZE(sizeof(uint16_t)), }, [NTA_TCP_WSCALE_ORIG] = { - .parse = parse_u8, + .parse = ct_parse_u8, .attr = ATTR_TCP_WSCALE_ORIG, .size = NTA_SIZE(sizeof(uint8_t)), }, [NTA_TCP_WSCALE_REPL] = { - .parse = parse_u8, + .parse = ct_parse_u8, .attr = ATTR_TCP_WSCALE_REPL, .size = NTA_SIZE(sizeof(uint8_t)), }, }; static void -parse_u8(struct nf_conntrack *ct, int attr, void *data) +ct_parse_u8(struct nf_conntrack *ct, int attr, void *data) { uint8_t *value = (uint8_t *) data; nfct_set_attr_u8(ct, h[attr].attr, *value); } static void -parse_u16(struct nf_conntrack *ct, int attr, void *data) +ct_parse_u16(struct nf_conntrack *ct, int attr, void *data) { uint16_t *value = (uint16_t *) data; nfct_set_attr_u16(ct, h[attr].attr, ntohs(*value)); } static void -parse_u32(struct nf_conntrack *ct, int attr, void *data) +ct_parse_u32(struct nf_conntrack *ct, int attr, void *data) { uint32_t *value = (uint32_t *) data; nfct_set_attr_u32(ct, h[attr].attr, ntohl(*value)); } static void -parse_group(struct nf_conntrack *ct, int attr, void *data) +ct_parse_group(struct nf_conntrack *ct, int attr, void *data) { nfct_set_attr_grp(ct, h[attr].attr, data); } static void -parse_nat_seq_adj(struct nf_conntrack *ct, int attr, void *data) +ct_parse_nat_seq_adj(struct nf_conntrack *ct, int attr, void *data) { struct nta_attr_natseqadj *this = data; nfct_set_attr_u32(ct, ATTR_ORIG_NAT_SEQ_CORRECTION_POS, @@ -218,7 +219,7 @@ parse_nat_seq_adj(struct nf_conntrack *ct, int attr, void *data) ntohl(this->repl_seq_offset_after)); } -int parse_payload(struct nf_conntrack *ct, struct nethdr *net, size_t remain) +int msg2ct(struct nf_conntrack *ct, struct nethdr *net, size_t remain) { int len; struct netattr *attr; diff --git a/src/sync-alarm.c b/src/sync-alarm.c index 8d6b34d..65154a1 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -42,7 +42,7 @@ static void refresher(struct alarm_block *a, void *data) random() % CONFIG(refresh) + 1, ((random() % 5 + 1) * 200000) - 1); - alarm_enqueue(obj, NET_T_STATE_UPD); + alarm_enqueue(obj, NET_T_STATE_CT_UPD); } static void cache_alarm_add(struct cache_object *obj, void *data) @@ -137,7 +137,7 @@ static int tx_queue_xmit(struct queue_node *n, const void *data) ca = (struct cache_alarm *)n; obj = cache_data_get_object(STATE(mode)->internal->ct.data, ca); - type = object_status_to_network_type(obj->status); + type = object_status_to_network_type(obj); net = obj->cache->ops->build_msg(obj, type); multichannel_send(STATE_SYNC(channel), net); cache_object_put(obj); diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index 55eda0b..cff4d25 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -518,7 +518,7 @@ static int tx_queue_xmit(struct queue_node *n, const void *data) cn = (struct cache_ftfw *)n; obj = cache_data_get_object(STATE(mode)->internal->ct.data, cn); - type = object_status_to_network_type(obj->status); + type = object_status_to_network_type(obj); net = obj->cache->ops->build_msg(obj, type); nethdr_set_hello(net); diff --git a/src/sync-mode.c b/src/sync-mode.c index 7f019f7..17533f8 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -41,6 +41,24 @@ #include #include +static struct nf_conntrack *msg2ct_alloc(struct nethdr *net, size_t remain) +{ + struct nf_conntrack *ct; + + /* TODO: add stats on ENOMEM errors in the future. */ + ct = nfct_new(); + if (ct == NULL) + return NULL; + + if (msg2ct(ct, net, remain) == -1) { + STATE_SYNC(error).msg_rcv_malformed++; + STATE_SYNC(error).msg_rcv_bad_payload++; + nfct_destroy(ct); + return NULL; + } + return ct; +} + static void do_channel_handler_step(int i, struct nethdr *net, size_t remain) { @@ -74,26 +92,24 @@ do_channel_handler_step(int i, struct nethdr *net, size_t remain) STATE_SYNC(error).msg_rcv_bad_type++; return; } - /* TODO: add stats on ENOMEM errors in the future. */ - ct = nfct_new(); - if (ct == NULL) - return; - - if (parse_payload(ct, net, remain) == -1) { - STATE_SYNC(error).msg_rcv_malformed++; - STATE_SYNC(error).msg_rcv_bad_payload++; - nfct_destroy(ct); - return; - } switch(net->type) { - case NET_T_STATE_NEW: + case NET_T_STATE_CT_NEW: + ct = msg2ct_alloc(net, remain); + if (ct == NULL) + return; STATE_SYNC(external)->ct.new(ct); break; - case NET_T_STATE_UPD: + case NET_T_STATE_CT_UPD: + ct = msg2ct_alloc(net, remain); + if (ct == NULL) + return; STATE_SYNC(external)->ct.upd(ct); break; - case NET_T_STATE_DEL: + case NET_T_STATE_CT_DEL: + ct = msg2ct_alloc(net, remain); + if (ct == NULL) + return; STATE_SYNC(external)->ct.del(ct); break; default: diff --git a/src/sync-notrack.c b/src/sync-notrack.c index e25cfd8..6c798ac 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -1,6 +1,7 @@ /* - * (C) 2008 by Pablo Neira Ayuso - * + * (C) 2006-2011 by Pablo Neira Ayuso + * (C) 2011 by Vyatta Inc. + * * 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 @@ -87,7 +88,7 @@ static int kernel_resync_cb(enum nf_conntrack_msg_type type, { struct nethdr *net; - net = BUILD_NETMSG(ct, NET_T_STATE_NEW); + net = BUILD_NETMSG_FROM_CT(ct, NET_T_STATE_CT_NEW); multichannel_send(STATE_SYNC(channel), net); return NFCT_CB_CONTINUE; @@ -198,7 +199,7 @@ static int tx_queue_xmit(struct queue_node *n, const void *data2) cn = (struct cache_ftfw *)n; obj = cache_data_get_object(STATE(mode)->internal->ct.data, cn); - type = object_status_to_network_type(obj->status);; + type = object_status_to_network_type(obj);; net = obj->cache->ops->build_msg(obj, type); multichannel_send(STATE_SYNC(channel), net); -- cgit v1.2.3 From 598e465087365db1fa36b67aa53d291e400ec5b1 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 27 Oct 2011 12:18:34 +0200 Subject: conntrackd: generalize local handler actions This patch prepares the introduction of actions with the expectation table. Mostly renamings. Signed-off-by: Pablo Neira Ayuso --- include/conntrackd.h | 46 +++++++++++++++++++++++----------------------- src/main.c | 24 ++++++++++++------------ src/run.c | 4 ++-- src/stats-mode.c | 8 ++++---- src/sync-mode.c | 16 ++++++++-------- 5 files changed, 49 insertions(+), 49 deletions(-) (limited to 'src') diff --git a/include/conntrackd.h b/include/conntrackd.h index b35c95d..697d3d7 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -14,29 +14,29 @@ #include /* UNIX facilities */ -#define FLUSH_MASTER 0 /* flush kernel conntrack table */ -#define RESYNC_MASTER 1 /* resync with kernel conntrack table */ -#define DUMP_INTERNAL 16 /* dump internal cache */ -#define DUMP_EXTERNAL 17 /* dump external cache */ -#define COMMIT 18 /* commit external cache */ -#define FLUSH_CACHE 19 /* flush cache */ -#define KILL 20 /* kill conntrackd */ -#define STATS 21 /* dump statistics */ -#define SEND_BULK 22 /* send a bulk */ -#define REQUEST_DUMP 23 /* request dump */ -#define DUMP_INT_XML 24 /* dump internal cache in XML */ -#define DUMP_EXT_XML 25 /* dump external cache in XML */ -#define RESET_TIMERS 26 /* reset kernel timers */ -#define DEBUG_INFO 27 /* unused */ -#define STATS_NETWORK 28 /* extended network stats */ -#define STATS_CACHE 29 /* extended cache stats */ -#define STATS_RUNTIME 30 /* extended runtime stats */ -#define STATS_LINK 31 /* dedicated link stats */ -#define STATS_RSQUEUE 32 /* resend queue stats */ -#define FLUSH_INT_CACHE 33 /* flush internal cache */ -#define FLUSH_EXT_CACHE 34 /* flush external cache */ -#define STATS_PROCESS 35 /* child process stats */ -#define STATS_QUEUE 36 /* queue stats */ +#define CT_FLUSH_MASTER 0 /* flush kernel conntrack table */ +#define CT_RESYNC_MASTER 1 /* resync with kernel ct table */ +#define CT_DUMP_INTERNAL 16 /* dump internal cache */ +#define CT_DUMP_EXTERNAL 17 /* dump external cache */ +#define CT_COMMIT 18 /* commit external cache */ +#define CT_FLUSH_CACHE 19 /* flush cache */ +#define KILL 20 /* kill conntrackd */ +#define STATS 21 /* dump statistics */ +#define SEND_BULK 22 /* send a bulk */ +#define REQUEST_DUMP 23 /* request dump */ +#define CT_DUMP_INT_XML 24 /* dump internal cache in XML */ +#define CT_DUMP_EXT_XML 25 /* dump external cache in XML */ +#define RESET_TIMERS 26 /* reset kernel timers */ +#define DEBUG_INFO 27 /* unused */ +#define STATS_NETWORK 28 /* extended network stats */ +#define STATS_CACHE 29 /* extended cache stats */ +#define STATS_RUNTIME 30 /* extended runtime stats */ +#define STATS_LINK 31 /* dedicated link stats */ +#define STATS_RSQUEUE 32 /* resend queue stats */ +#define CT_FLUSH_INT_CACHE 33 /* flush internal cache */ +#define CT_FLUSH_EXT_CACHE 34 /* flush external cache */ +#define STATS_PROCESS 35 /* child process stats */ +#define STATS_QUEUE 36 /* queue stats */ #define DEFAULT_CONFIGFILE "/etc/conntrackd/conntrackd.conf" #define DEFAULT_LOCKFILE "/var/lock/conntrackd.lock" diff --git a/src/main.c b/src/main.c index 4ead2ea..ebfc8b9 100644 --- a/src/main.c +++ b/src/main.c @@ -115,15 +115,15 @@ int main(int argc, char *argv[]) break; case 'c': set_operation_mode(&type, REQUEST, argv); - action = COMMIT; + action = CT_COMMIT; break; case 'i': set_operation_mode(&type, REQUEST, argv); - action = DUMP_INTERNAL; + action = CT_DUMP_INTERNAL; break; case 'e': set_operation_mode(&type, REQUEST, argv); - action = DUMP_EXTERNAL; + action = CT_DUMP_EXTERNAL; break; case 'C': if (++i < argc) { @@ -142,18 +142,18 @@ int main(int argc, char *argv[]) break; case 'F': set_operation_mode(&type, REQUEST, argv); - action = FLUSH_MASTER; + action = CT_FLUSH_MASTER; break; case 'f': set_operation_mode(&type, REQUEST, argv); if (i+1 < argc && argv[i+1][0] != '-') { if (strncmp(argv[i+1], "internal", strlen(argv[i+1])) == 0) { - action = FLUSH_INT_CACHE; + action = CT_FLUSH_INT_CACHE; i++; } else if (strncmp(argv[i+1], "external", strlen(argv[i+1])) == 0) { - action = FLUSH_EXT_CACHE; + action = CT_FLUSH_EXT_CACHE; i++; } else { fprintf(stderr, "ERROR: unknown " @@ -164,12 +164,12 @@ int main(int argc, char *argv[]) } } else { /* default to general flushing */ - action = FLUSH_CACHE; + action = CT_FLUSH_CACHE; } break; case 'R': set_operation_mode(&type, REQUEST, argv); - action = RESYNC_MASTER; + action = CT_RESYNC_MASTER; break; case 'B': set_operation_mode(&type, REQUEST, argv); @@ -243,10 +243,10 @@ int main(int argc, char *argv[]) action = REQUEST_DUMP; break; case 'x': - if (action == DUMP_INTERNAL) - action = DUMP_INT_XML; - else if (action == DUMP_EXTERNAL) - action = DUMP_EXT_XML; + if (action == CT_DUMP_INTERNAL) + action = CT_DUMP_INT_XML; + else if (action == CT_DUMP_EXTERNAL) + action = CT_DUMP_EXT_XML; else { show_usage(argv[0]); fprintf(stderr, "Error: Invalid parameters\n"); diff --git a/src/run.c b/src/run.c index f8d3fad..c21db2e 100644 --- a/src/run.c +++ b/src/run.c @@ -197,7 +197,7 @@ static int local_handler(int fd, void *data) return LOCAL_RET_OK; } switch(type) { - case FLUSH_MASTER: + case CT_FLUSH_MASTER: STATE(stats).nl_kernel_table_flush++; dlog(LOG_NOTICE, "flushing kernel conntrack table"); @@ -209,7 +209,7 @@ static int local_handler(int fd, void *data) exit(EXIT_SUCCESS); } break; - case RESYNC_MASTER: + case CT_RESYNC_MASTER: if (STATE(mode)->internal->flags & INTERNAL_F_POPULATE) { STATE(stats).nl_kernel_table_resync++; dlog(LOG_NOTICE, "resync with master table"); diff --git a/src/stats-mode.c b/src/stats-mode.c index c7a81e3..b768033 100644 --- a/src/stats-mode.c +++ b/src/stats-mode.c @@ -62,14 +62,14 @@ static int local_handler_stats(int fd, int type, void *data) int ret = LOCAL_RET_OK; switch(type) { - case DUMP_INTERNAL: + case CT_DUMP_INTERNAL: cache_dump(STATE_STATS(cache), fd, NFCT_O_PLAIN); break; - case DUMP_INT_XML: + case CT_DUMP_INT_XML: cache_dump(STATE_STATS(cache), fd, NFCT_O_XML); break; - case FLUSH_CACHE: - case FLUSH_INT_CACHE: + case CT_FLUSH_CACHE: + case CT_FLUSH_INT_CACHE: dlog(LOG_NOTICE, "flushing caches"); cache_flush(STATE_STATS(cache)); break; diff --git a/src/sync-mode.c b/src/sync-mode.c index 17533f8..7e6fa31 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -486,31 +486,31 @@ static int local_handler_sync(int fd, int type, void *data) int ret = LOCAL_RET_OK; switch(type) { - case DUMP_INTERNAL: + case CT_DUMP_INTERNAL: if (fork_process_new(CTD_PROC_ANY, 0, NULL, NULL) == 0) { STATE(mode)->internal->ct.dump(fd, NFCT_O_PLAIN); exit(EXIT_SUCCESS); } break; - case DUMP_EXTERNAL: + case CT_DUMP_EXTERNAL: if (fork_process_new(CTD_PROC_ANY, 0, NULL, NULL) == 0) { STATE_SYNC(external)->ct.dump(fd, NFCT_O_PLAIN); exit(EXIT_SUCCESS); } break; - case DUMP_INT_XML: + case CT_DUMP_INT_XML: if (fork_process_new(CTD_PROC_ANY, 0, NULL, NULL) == 0) { STATE(mode)->internal->ct.dump(fd, NFCT_O_XML); exit(EXIT_SUCCESS); } break; - case DUMP_EXT_XML: + case CT_DUMP_EXT_XML: if (fork_process_new(CTD_PROC_ANY, 0, NULL, NULL) == 0) { STATE_SYNC(external)->ct.dump(fd, NFCT_O_XML); exit(EXIT_SUCCESS); } break; - case COMMIT: + case CT_COMMIT: /* delete the reset alarm if any before committing */ del_alarm(&STATE_SYNC(reset_cache_alarm)); @@ -525,20 +525,20 @@ static int local_handler_sync(int fd, int type, void *data) CONFIG(purge_timeout), 0); } break; - case FLUSH_CACHE: + case CT_FLUSH_CACHE: /* inmediate flush, remove pending flush scheduled if any */ del_alarm(&STATE_SYNC(reset_cache_alarm)); dlog(LOG_NOTICE, "flushing caches"); STATE(mode)->internal->ct.flush(); STATE_SYNC(external)->ct.flush(); break; - case FLUSH_INT_CACHE: + case CT_FLUSH_INT_CACHE: /* inmediate flush, remove pending flush scheduled if any */ del_alarm(&STATE_SYNC(reset_cache_alarm)); dlog(LOG_NOTICE, "flushing internal cache"); STATE(mode)->internal->ct.flush(); break; - case FLUSH_EXT_CACHE: + case CT_FLUSH_EXT_CACHE: dlog(LOG_NOTICE, "flushing external cache"); STATE_SYNC(external)->ct.flush(); break; -- cgit v1.2.3 From 79ab299bfb20b7fc1982ca90d77d8b908b824fea Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 4 Jan 2012 14:31:41 +0100 Subject: conntrackd: simplify cache_get_extra function This patch simplifies cache_get_extra which now takes only one parameter that is the cache_object. With it, the extra area can be calculated. Signed-off-by: Pablo Neira Ayuso --- include/cache.h | 2 +- src/cache.c | 4 ++-- src/sync-alarm.c | 3 +-- src/sync-ftfw.c | 6 ++---- src/sync-notrack.c | 6 ++---- 5 files changed, 8 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/include/cache.h b/include/cache.h index 02bb386..65f7e3a 100644 --- a/include/cache.h +++ b/include/cache.h @@ -148,7 +148,7 @@ struct cache_object *cache_find(struct cache *c, void *ptr, int *pos); void cache_stats(const struct cache *c, int fd); void cache_stats_extended(const struct cache *c, int fd); struct cache_object *cache_data_get_object(struct cache *c, void *data); -void *cache_get_extra(struct cache *, void *); +void *cache_get_extra(struct cache_object *); void cache_iterate(struct cache *c, void *data, int (*iterate)(void *data1, void *data2)); void cache_iterate_limit(struct cache *c, void *data, uint32_t from, uint32_t steps, int (*iterate)(void *data1, void *data2)); diff --git a/src/cache.c b/src/cache.c index efdab0e..f515ba0 100644 --- a/src/cache.c +++ b/src/cache.c @@ -308,9 +308,9 @@ struct cache_object *cache_data_get_object(struct cache *c, void *data) return (struct cache_object *)((char*)data - c->extra_offset); } -void *cache_get_extra(struct cache *c, void *data) +void *cache_get_extra(struct cache_object *obj) { - return (char*)data + c->extra_offset; + return (char*)obj + obj->cache->extra_offset; } void cache_stats(const struct cache *c, int fd) diff --git a/src/sync-alarm.c b/src/sync-alarm.c index 65154a1..03481fd 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -110,8 +110,7 @@ static int alarm_recv(const struct nethdr *net) static void alarm_enqueue(struct cache_object *obj, int query) { - struct cache_alarm *ca = - cache_get_extra(STATE(mode)->internal->ct.data, obj); + struct cache_alarm *ca = cache_get_extra(obj); if (queue_add(STATE_SYNC(tx_queue), &ca->qnode) > 0) cache_object_get(obj); } diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index cff4d25..c7cc4aa 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -169,8 +169,7 @@ static void ftfw_kill(void) static int do_cache_to_tx(void *data1, void *data2) { struct cache_object *obj = data2; - struct cache_ftfw *cn = - cache_get_extra(STATE(mode)->internal->ct.data, obj); + struct cache_ftfw *cn = cache_get_extra(obj); if (queue_in(rs_queue, &cn->qnode)) { queue_del(&cn->qnode); @@ -551,8 +550,7 @@ static void ftfw_xmit(void) static void ftfw_enqueue(struct cache_object *obj, int type) { - struct cache_ftfw *cn = - cache_get_extra(STATE(mode)->internal->ct.data, obj); + struct cache_ftfw *cn = cache_get_extra(obj); if (queue_in(rs_queue, &cn->qnode)) { queue_del(&cn->qnode); queue_add(STATE_SYNC(tx_queue), &cn->qnode); diff --git a/src/sync-notrack.c b/src/sync-notrack.c index 6c798ac..a8cc6bf 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -76,8 +76,7 @@ static void tx_queue_add_ctlmsg(uint32_t flags, uint32_t from, uint32_t to) static int do_cache_to_tx(void *data1, void *data2) { struct cache_object *obj = data2; - struct cache_notrack *cn = - cache_get_extra(STATE(mode)->internal->ct.data, obj); + struct cache_notrack *cn = cache_get_extra(obj); if (queue_add(STATE_SYNC(tx_queue), &cn->qnode) > 0) cache_object_get(obj); return 0; @@ -219,8 +218,7 @@ static void notrack_xmit(void) static void notrack_enqueue(struct cache_object *obj, int query) { - struct cache_notrack *cn = - cache_get_extra(STATE(mode)->internal->ct.data, obj); + struct cache_notrack *cn = cache_get_extra(obj); if (queue_add(STATE_SYNC(tx_queue), &cn->qnode) > 0) cache_object_get(obj); } -- cgit v1.2.3 From 75a7cd3c722e1abca14fc375bec8ab30c34ab284 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 16 Nov 2011 02:10:31 +0100 Subject: conntrackd: remove cache_data_get_object and replace by direct pointer We now include one pointer to the object in the extra section. This is required to generalize this code for the expectation support. We consume 4-8 bytes extra, but we will not need more changes to support expectations which is a good idea. --- include/cache.h | 1 - src/cache.c | 5 ----- src/sync-alarm.c | 10 +++++----- src/sync-ftfw.c | 19 +++++++------------ src/sync-notrack.c | 14 +++++++------- 5 files changed, 19 insertions(+), 30 deletions(-) (limited to 'src') diff --git a/include/cache.h b/include/cache.h index 65f7e3a..abebb97 100644 --- a/include/cache.h +++ b/include/cache.h @@ -147,7 +147,6 @@ void cache_del(struct cache *c, struct cache_object *obj); struct cache_object *cache_find(struct cache *c, void *ptr, int *pos); void cache_stats(const struct cache *c, int fd); void cache_stats_extended(const struct cache *c, int fd); -struct cache_object *cache_data_get_object(struct cache *c, void *data); void *cache_get_extra(struct cache_object *); void cache_iterate(struct cache *c, void *data, int (*iterate)(void *data1, void *data2)); void cache_iterate_limit(struct cache *c, void *data, uint32_t from, uint32_t steps, int (*iterate)(void *data1, void *data2)); diff --git a/src/cache.c b/src/cache.c index f515ba0..7c41e54 100644 --- a/src/cache.c +++ b/src/cache.c @@ -303,11 +303,6 @@ struct cache_object *cache_find(struct cache *c, void *ptr, int *id) return ((struct cache_object *) hashtable_find(c->h, ptr, *id)); } -struct cache_object *cache_data_get_object(struct cache *c, void *data) -{ - return (struct cache_object *)((char*)data - c->extra_offset); -} - void *cache_get_extra(struct cache_object *obj) { return (char*)obj + obj->cache->extra_offset; diff --git a/src/sync-alarm.c b/src/sync-alarm.c index 03481fd..acaf5e6 100644 --- a/src/sync-alarm.c +++ b/src/sync-alarm.c @@ -29,6 +29,7 @@ struct cache_alarm { struct queue_node qnode; + struct cache_object *obj; struct alarm_block alarm; }; @@ -50,6 +51,7 @@ static void cache_alarm_add(struct cache_object *obj, void *data) struct cache_alarm *ca = data; queue_node_init(&ca->qnode, Q_ELEM_OBJ); + ca->obj = obj; init_alarm(&ca->alarm, obj, refresher); add_alarm(&ca->alarm, random() % CONFIG(refresh) + 1, @@ -131,15 +133,13 @@ static int tx_queue_xmit(struct queue_node *n, const void *data) break; case Q_ELEM_OBJ: { struct cache_alarm *ca; - struct cache_object *obj; int type; ca = (struct cache_alarm *)n; - obj = cache_data_get_object(STATE(mode)->internal->ct.data, ca); - type = object_status_to_network_type(obj); - net = obj->cache->ops->build_msg(obj, type); + type = object_status_to_network_type(ca->obj); + net = ca->obj->cache->ops->build_msg(ca->obj, type); multichannel_send(STATE_SYNC(channel), net); - cache_object_put(obj); + cache_object_put(ca->obj); break; } } diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index c7cc4aa..fa76c0c 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -55,12 +55,14 @@ static int say_hello_back; struct cache_ftfw { struct queue_node qnode; + struct cache_object *obj; uint32_t seq; }; static void cache_ftfw_add(struct cache_object *obj, void *data) { struct cache_ftfw *cn = data; + cn->obj = obj; /* These nodes are not inserted in the list */ queue_node_init(&cn->qnode, Q_ELEM_OBJ); } @@ -302,13 +304,11 @@ static int rs_queue_empty(struct queue_node *n, const void *data) } case Q_ELEM_OBJ: { struct cache_ftfw *cn; - struct cache_object *obj; cn = (struct cache_ftfw *) n; if (h == NULL) { queue_del(n); - obj = cache_data_get_object(STATE(mode)->internal->ct.data, cn); - cache_object_put(obj); + cache_object_put(cn->obj); return 0; } if (before(cn->seq, h->from)) @@ -318,8 +318,7 @@ static int rs_queue_empty(struct queue_node *n, const void *data) dp("queue: deleting from queue (seq=%u)\n", cn->seq); queue_del(n); - obj = cache_data_get_object(STATE(mode)->internal->ct.data, cn); - cache_object_put(obj); + cache_object_put(cn->obj); break; } } @@ -465,11 +464,9 @@ static void rs_queue_purge_full(void) } case Q_ELEM_OBJ: { struct cache_ftfw *cn; - struct cache_object *obj; cn = (struct cache_ftfw *)n; - obj = cache_data_get_object(STATE(mode)->internal->ct.data, cn); - cache_object_put(obj); + cache_object_put(cn->obj); break; } } @@ -511,14 +508,12 @@ static int tx_queue_xmit(struct queue_node *n, const void *data) } case Q_ELEM_OBJ: { struct cache_ftfw *cn; - struct cache_object *obj; int type; struct nethdr *net; cn = (struct cache_ftfw *)n; - obj = cache_data_get_object(STATE(mode)->internal->ct.data, cn); - type = object_status_to_network_type(obj); - net = obj->cache->ops->build_msg(obj, type); + type = object_status_to_network_type(cn->obj); + net = cn->obj->cache->ops->build_msg(cn->obj, type); nethdr_set_hello(net); dp("tx_list sq: %u fl:%u len:%u\n", diff --git a/src/sync-notrack.c b/src/sync-notrack.c index a8cc6bf..06ad1f0 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -34,12 +34,14 @@ static struct alarm_block alive_alarm; struct cache_notrack { struct queue_node qnode; + struct cache_object *obj; }; static void cache_notrack_add(struct cache_object *obj, void *data) { struct cache_notrack *cn = data; queue_node_init(&cn->qnode, Q_ELEM_OBJ); + cn->obj = obj; } static void cache_notrack_del(struct cache_object *obj, void *data) @@ -191,19 +193,17 @@ static int tx_queue_xmit(struct queue_node *n, const void *data2) break; } case Q_ELEM_OBJ: { - struct cache_ftfw *cn; - struct cache_object *obj; + struct cache_notrack *cn; int type; struct nethdr *net; - cn = (struct cache_ftfw *)n; - obj = cache_data_get_object(STATE(mode)->internal->ct.data, cn); - type = object_status_to_network_type(obj);; - net = obj->cache->ops->build_msg(obj, type); + cn = (struct cache_notrack *)n; + type = object_status_to_network_type(cn->obj); + net = cn->obj->cache->ops->build_msg(cn->obj, type); multichannel_send(STATE_SYNC(channel), net); queue_del(n); - cache_object_put(obj); + cache_object_put(cn->obj); break; } } -- cgit v1.2.3 From f33b72ca969994384a5db6122f8c85e62cfc46ce Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 14 Dec 2011 19:51:38 +0100 Subject: conntrackd: constify ct parameter of ct_filter_* functions The ct object that is passed as parameter is not modified, make it constant. Signed-off-by: Pablo Neira Ayuso --- include/filter.h | 2 +- src/filter.c | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/include/filter.h b/include/filter.h index 72c2aa4..f19b18b 100644 --- a/include/filter.h +++ b/include/filter.h @@ -50,6 +50,6 @@ void ct_filter_add_state(struct ct_filter *f, int protonum, int state); void ct_filter_set_logic(struct ct_filter *f, enum ct_filter_type type, enum ct_filter_logic logic); -int ct_filter_conntrack(struct nf_conntrack *ct, int userspace); +int ct_filter_conntrack(const struct nf_conntrack *ct, int userspace); #endif diff --git a/src/filter.c b/src/filter.c index 6a09c77..7c4ddc1 100644 --- a/src/filter.c +++ b/src/filter.c @@ -235,7 +235,7 @@ void ct_filter_add_state(struct ct_filter *f, int protonum, int val) } static inline int -__ct_filter_test_ipv4(struct ct_filter *f, struct nf_conntrack *ct) +__ct_filter_test_ipv4(struct ct_filter *f, const struct nf_conntrack *ct) { int id_src, id_dst; uint32_t src, dst; @@ -252,7 +252,7 @@ __ct_filter_test_ipv4(struct ct_filter *f, struct nf_conntrack *ct) } static inline int -__ct_filter_test_ipv6(struct ct_filter *f, struct nf_conntrack *ct) +__ct_filter_test_ipv6(struct ct_filter *f, const struct nf_conntrack *ct) { int id_src, id_dst; const uint32_t *src, *dst; @@ -295,7 +295,8 @@ __ct_filter_test_mask6(const void *ptr, const void *ct) (elem->ip[3] & elem->mask[3]) == (dst[3] & elem->mask[3]))); } -static int __ct_filter_test_state(struct ct_filter *f, struct nf_conntrack *ct) +static int +__ct_filter_test_state(struct ct_filter *f, const struct nf_conntrack *ct) { uint16_t val = 0; uint8_t protonum = nfct_get_attr_u8(ct, ATTR_L4PROTO); @@ -314,7 +315,8 @@ static int __ct_filter_test_state(struct ct_filter *f, struct nf_conntrack *ct) return test_bit_u16(val, &f->statemap[protonum]); } -static int ct_filter_check(struct ct_filter *f, struct nf_conntrack *ct) +static int +ct_filter_check(struct ct_filter *f, const struct nf_conntrack *ct) { int ret, protonum = nfct_get_attr_u8(ct, ATTR_L4PROTO); @@ -361,7 +363,7 @@ static int ct_filter_check(struct ct_filter *f, struct nf_conntrack *ct) return 1; } -static inline int ct_filter_sanity_check(struct nf_conntrack *ct) +static inline int ct_filter_sanity_check(const struct nf_conntrack *ct) { if (!nfct_attr_is_set(ct, ATTR_L3PROTO)) { dlog(LOG_ERR, "missing layer 3 protocol"); @@ -396,7 +398,7 @@ static inline int ct_filter_sanity_check(struct nf_conntrack *ct) } /* we do user-space filtering for dump and resyncs */ -int ct_filter_conntrack(struct nf_conntrack *ct, int userspace) +int ct_filter_conntrack(const struct nf_conntrack *ct, int userspace) { /* missing mandatory attributes in object */ if (!ct_filter_sanity_check(ct)) -- cgit v1.2.3 From 2719bd93ad5f589139d8ede0726fa6a2ef2eb321 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 14 Dec 2011 23:55:47 +0100 Subject: conntrackd: relax checkings in ct_filter_sanity_check This is required to prepare the expectation support. The master, expect and mask objects that are part of the conntrack object do not have any reply information. This allows the expectation support to re-use the existing filtering infrastructure. Signed-off-by: Pablo Neira Ayuso --- src/filter.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/filter.c b/src/filter.c index 7c4ddc1..746a9bb 100644 --- a/src/filter.c +++ b/src/filter.c @@ -373,9 +373,7 @@ static inline int ct_filter_sanity_check(const struct nf_conntrack *ct) switch(nfct_get_attr_u8(ct, ATTR_L3PROTO)) { case AF_INET: if (!nfct_attr_is_set(ct, ATTR_IPV4_SRC) || - !nfct_attr_is_set(ct, ATTR_IPV4_DST) || - !nfct_attr_is_set(ct, ATTR_REPL_IPV4_SRC) || - !nfct_attr_is_set(ct, ATTR_REPL_IPV4_DST)) { + !nfct_attr_is_set(ct, ATTR_IPV4_DST)) { dlog(LOG_ERR, "missing IPv4 address. " "You forgot to load " "nf_conntrack_ipv4?"); @@ -384,9 +382,7 @@ static inline int ct_filter_sanity_check(const struct nf_conntrack *ct) break; case AF_INET6: if (!nfct_attr_is_set(ct, ATTR_IPV6_SRC) || - !nfct_attr_is_set(ct, ATTR_IPV6_DST) || - !nfct_attr_is_set(ct, ATTR_REPL_IPV6_SRC) || - !nfct_attr_is_set(ct, ATTR_REPL_IPV6_DST)) { + !nfct_attr_is_set(ct, ATTR_IPV6_DST)) { dlog(LOG_ERR, "missing IPv6 address. " "You forgot to load " "nf_conntrack_ipv6?"); -- cgit v1.2.3 From eb31a0c3eb9db28e673587d4614662645a10cffa Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 19 Dec 2011 17:12:41 +0100 Subject: conntrackd: minor cleanup for commit Comestical cleanup for better code readability. Signed-off-by: Pablo Neira Ayuso --- src/external_cache.c | 7 +------ src/sync-mode.c | 8 ++++++++ 2 files changed, 9 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/external_cache.c b/src/external_cache.c index 4b6fa6f..3f896a0 100644 --- a/src/external_cache.c +++ b/src/external_cache.c @@ -91,12 +91,7 @@ static void external_cache_ct_dump(int fd, int type) static int external_cache_ct_commit(struct nfct_handle *h, int fd) { - if (!cache_commit(external, h, fd)) { - dlog(LOG_NOTICE, "commit already in progress, skipping"); - return LOCAL_RET_OK; - } - /* Keep the client socket open, we want synchronous commits. */ - return LOCAL_RET_STOLEN; + return cache_commit(external, h, fd); } static void external_cache_ct_flush(void) diff --git a/src/sync-mode.c b/src/sync-mode.c index 7e6fa31..fa522c7 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -516,6 +516,14 @@ static int local_handler_sync(int fd, int type, void *data) dlog(LOG_NOTICE, "committing external cache"); ret = STATE_SYNC(external)->ct.commit(STATE_SYNC(commit).h, fd); + if (ret == 0) { + dlog(LOG_NOTICE, "commit already in progress, " + "skipping"); + ret = LOCAL_RET_OK; + } else { + /* Keep open the client, we want synchronous commit. */ + ret = LOCAL_RET_STOLEN; + } break; case RESET_TIMERS: if (!alarm_pending(&STATE_SYNC(reset_cache_alarm))) { -- cgit v1.2.3 From 79a777c60cfe02197c135adcc4edb2f63ae9a695 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 19 Dec 2011 17:13:25 +0100 Subject: conntrackd: support for expectation synchronization This patch adds support to synchronize expectations between firewalls. This addition aims to re-use as much as possible of the existing infrastructure for stability reasons. The expectation support has been tested with the FTP helper. This extension requires libnetfilter_conntrack 1.0.0. If this is the first time you're playing with conntrackd, I *strongly* recommend you to get working setup of conntrackd without expectation support before as described in the documentation. Then, enabling expectation support is rather easy. To know more about expectations, if you're not familiar with them, I suggest you to read: "Netfilter's Connection Tracking System" http://people.netfilter.org/pablo/docs/login.pdf Reprinted from ;login: The Magazine of USENIX, vol. 31, no. 3 (Berkeley, CA: USENIX Association, 2006, pp40-45.) In short, expectations allow one Linux firewall to filter multi-flow traffic like FTP, SIP and H.323. In my testbed, there are two firewalls in a primary-backup configuration running keepalived. The use a couple of floating cluster IP address (192.168.0.100 and 192.168.1.100) that are used by the client. These firewalls protect one FTP server (192.168.1.2) that will be accessed by one client. In ASCII art, it looks like this: 192.168.0.100 192.168.1.100 eth1 eth2 fw-1 / \ FTP -- client ------ ------ server -- 192.168.0.2 \ / 192.168.1.2 fw-2 This is the rule-set for the firewalls: -A POSTROUTING -t nat -s 192.168.0.2/32 -d 192.168.1.2/32 -j SNAT --to-source 192.168.1.100 -A INPUT -p tcp -m tcp --dport 22 -j ACCEPT -A INPUT -m state --state INVALID -j DROP -A FORWARD -m state --state RELATED -j ACCEPT -A FORWARD -i eth2 -m state --state ESTABLISHED -j ACCEPT -A FORWARD -i eth1 -p tcp -m tcp --dport 21 --tcp-flags FIN,SYN,RST,ACK SYN -m state --state NEW -j ACCEPT -A FORWARD -i eth1 -p tcp -m state --state ESTABLISHED -j ACCEPT -A FORWARD -m state --state INVALID -j LOG --log-prefix "invalid: " The following steps detail how to check that the expectation support works fine for conntrackd: 1) You have to enable the expectation support in the configuration file with the following option: Sync { ... Options { ExpectationSync { ftp sip h323 } } } This enables expectation synchronization for the FTP, SIP and H.323 helpers. You can alternatively use: Sync { ... Options { ExpectationSync On } } To enable expectation synchronization for all helpers. 2) Make sure you have loaded the FTP helper in both firewalls. root@fw1# modprobe nf_conntrack_ftp root@fw2# modprobe nf_conntrack_ftp 3) Switch to the client. Start one FTP control connection to one server that is protected by the firewalls, enter passive mode: (term-1) user@client$ nc 192.168.1.2 21 220 dummy FTP server USER anonymous 331 Please specify the password. PASS nothing 230 Login successful. PASV 227 Entering Passive Mode (192,168,1,2,163,11). This means that port 163*256+11=41739 will be used for the data traffic. Read this if you are not familiar with the FTP protocol: http://www.freefire.org/articles/ftpexample.php 3) Switch to fw-1 (primary) to check that the expectation is in the internal cache. root@fw1# conntrackd -i exp proto=6 src=192.168.0.2 dst=192.168.1.2 sport=0 dport=41739 mask-src=255.255.255.255 mask-dst=255.255.255.255 sport=0 dport=65535 master-src=192.168.0.2 master-dst=192.168.1.2 sport=36390 dport=21 [active since 5s] 4) Switch to fw-2 (backup) to check that the expectation has been successfully replicated. root@fw2# conntrackd -e exp proto=6 src=192.168.0.2 dst=192.168.1.2 sport=0 dport=41739 mask-src=255.255.255.255 mask-dst=255.255.255.255 sport=0 dport=65535 master-src=192.168.0.2 master-dst=192.168.1.2 sport=36390 dport=21 [active since 8s] 5) Make the primary firewall fw-1 fail. Now fw-2 becomes primary. 6) Switch to fw-2 (primary) to commit the external cache into the kernel. root@fw2# conntrackd -c exp The logs should display that the commit was successful: root@fw2# tail -100f /var/log/conntrackd.log [Wed Dec 7 22:16:31 2011] (pid=19195) [notice] committing external cache: expectations [Wed Dec 7 22:16:31 2011] (pid=19195) [notice] Committed 1 new entries [Wed Dec 7 22:16:31 2011] (pid=19195) [notice] commit has taken 0.000366 seconds 7) Switch to the client. Open a new terminal and connect to the port that has been announced by the server: (term-2) user@client$ nc -vvv 192.168.1.2 41739 (UNKNOWN) [192.168.1.2] 41739 (?) open 8) Switch to term-1 and ask for the file listing: [...] 227 Entering Passive Mode (192,168,1,2,163,11). LIST 9) Switch to term-2, it should display the listing. That means everything has worked fine. You may want to try disabling the expectation support and repeating the steps to check that *it does not work* without the state-synchronization. You can also display expectation statistics by means of: root@fwX# conntrackd -s exp This update requires no changes in the primary-backup.sh script that is used by the HA manager to interact with conntrackd. Thus, we provide a backward compatible command line interface. Regarding the Filter clause and expectations, we use the master conntrack to filter expectation events. The filtering is performed in user-space. No kernel-space filtering support for expectations yet (this support should go in libnetfilter_conntrack at some point). This patch also includes support to disable caching and to allow direct injection of expectations. Signed-off-by: Pablo Neira Ayuso --- configure.ac | 2 +- conntrackd.8 | 12 +- doc/sync/alarm/conntrackd.conf | 16 ++ doc/sync/ftfw/conntrackd.conf | 16 ++ doc/sync/notrack/conntrackd.conf | 16 ++ include/cache.h | 4 + include/conntrackd.h | 19 +++ include/external.h | 11 ++ include/filter.h | 7 + include/internal.h | 17 +++ include/log.h | 2 + include/netlink.h | 7 + include/network.h | 40 ++++- src/Makefile.am | 2 +- src/build.c | 99 +++++++++++++ src/cache-ct.c | 6 +- src/cache-exp.c | 308 +++++++++++++++++++++++++++++++++++++++ src/external_cache.c | 85 +++++++++++ src/external_inject.c | 95 +++++++++++- src/filter.c | 76 ++++++++++ src/internal_bypass.c | 146 ++++++++++++++++++- src/internal_cache.c | 173 ++++++++++++++++++++++ src/log.c | 37 +++++ src/main.c | 69 +++++++-- src/netlink.c | 63 +++++++- src/network.c | 5 + src/parse.c | 192 ++++++++++++++++++++++++ src/read_config_lex.l | 1 + src/read_config_yy.y | 50 ++++++- src/run.c | 206 +++++++++++++++++++++++--- src/sync-ftfw.c | 7 +- src/sync-mode.c | 165 ++++++++++++++++++--- src/sync-notrack.c | 6 +- 33 files changed, 1889 insertions(+), 71 deletions(-) create mode 100644 src/cache-exp.c (limited to 'src') diff --git a/configure.ac b/configure.ac index 0481e23..26a7e02 100644 --- a/configure.ac +++ b/configure.ac @@ -52,7 +52,7 @@ else fi PKG_CHECK_MODULES([LIBNFNETLINK], [libnfnetlink >= 1.0.0]) -PKG_CHECK_MODULES([LIBNETFILTER_CONNTRACK], [libnetfilter_conntrack >= 0.9.1]) +PKG_CHECK_MODULES([LIBNETFILTER_CONNTRACK], [libnetfilter_conntrack >= 1.0.0]) AC_CHECK_HEADERS([linux/capability.h],, [AC_MSG_ERROR([Cannot find linux/capabibility.h])]) diff --git a/conntrackd.8 b/conntrackd.8 index 0c9054e..f07ad7a 100644 --- a/conntrackd.8 +++ b/conntrackd.8 @@ -24,10 +24,10 @@ Run conntrackd in daemon mode. .B conntrackd can be used in client mode to request several information and operations to a running daemon .TP -.BI "-i " +.BI "-i "[ct|expect]" Dump the internal cache, i.e. show local states .TP -.BI "-e " +.BI "-e "[ct|expect]" Dump the external cache, i.e. show foreign states .TP .BI "-x " @@ -37,7 +37,7 @@ with "-i" and "-e" parameters. .BI "-f " "[|internal|external]" Flush the internal and/or external cache .TP -.BI "-F " +.BI "-F [ct|expect]" Flush the kernel conntrack table (if you use a Linux kernel >= 2.6.29, this option will not flush your internal and external cache). .TP @@ -48,15 +48,17 @@ ask conntrackd to send the state-entries that it owns to others. .BI "-k " Kill the daemon .TP -.BI "-s " "[|network|cache|runtime|link|rsqueue|process|queue]" +.BI "-s " "[|network|cache|runtime|link|rsqueue|process|queue|ct|expect]" Dump statistics. If no parameter is passed, it displays the general statistics. If "network" is passed as parameter it displays the networking statistics. If "cache" is passed as parameter, it shows the extended cache statistics. If "runtime" is passed as parameter, it shows the run-time statistics. If "process" is passed as parameter, it shows existing child processes (if any). If "queue" is passed as parameter, it shows queue statistics. +If "ct" is passed, it displays the general statistics. +If "expect" is passed as parameter, it shows expectation statistics. .TP -.BI "-R " +.BI "-R " "[ct|expect]" Force a resync against the kernel connection tracking table .TP .BI "-t " diff --git a/doc/sync/alarm/conntrackd.conf b/doc/sync/alarm/conntrackd.conf index d05b499..deed291 100644 --- a/doc/sync/alarm/conntrackd.conf +++ b/doc/sync/alarm/conntrackd.conf @@ -191,6 +191,22 @@ Sync { # This feature requires a Linux kernel >= 2.6.36. # # TCPWindowTracking Off + + # Set this option on if you want to enable the synchronization + # of expectations. You have to specify the list of helpers that + # you want to enable. Default is off. + # + # ExpectationSync { + # ftp + # h323 + # sip + # } + # + # You can use this alternatively: + # + # ExpectationSync On + # + # If you want to synchronize expectations of all helpers. # } } diff --git a/doc/sync/ftfw/conntrackd.conf b/doc/sync/ftfw/conntrackd.conf index c52f214..0304f0f 100644 --- a/doc/sync/ftfw/conntrackd.conf +++ b/doc/sync/ftfw/conntrackd.conf @@ -214,6 +214,22 @@ Sync { # This feature requires a Linux kernel >= 2.6.36. # # TCPWindowTracking Off + + # Set this option on if you want to enable the synchronization + # of expectations. You have to specify the list of helpers that + # you want to enable. Default is off. + # + # ExpectationSync { + # ftp + # h323 + # sip + # } + # + # You can use this alternatively: + # + # ExpectationSync On + # + # If you want to synchronize expectations of all helpers. # } } diff --git a/doc/sync/notrack/conntrackd.conf b/doc/sync/notrack/conntrackd.conf index 4d77266..34e7b32 100644 --- a/doc/sync/notrack/conntrackd.conf +++ b/doc/sync/notrack/conntrackd.conf @@ -253,6 +253,22 @@ Sync { # This feature requires a Linux kernel >= 2.6.36. # # TCPWindowTracking Off + + # Set this option on if you want to enable the synchronization + # of expectations. You have to specify the list of helpers that + # you want to enable. Default is off. + # + # ExpectationSync { + # ftp + # h323 + # sip + # } + # + # You can use this alternatively: + # + # ExpectationSync On + # + # If you want to synchronize expectations of all helpers. # } } diff --git a/include/cache.h b/include/cache.h index abebb97..3af2741 100644 --- a/include/cache.h +++ b/include/cache.h @@ -52,6 +52,7 @@ extern struct cache_feature timer_feature; enum cache_type { CACHE_T_NONE = 0, CACHE_T_CT, + CACHE_T_EXP, CACHE_T_MAX }; @@ -128,6 +129,9 @@ struct cache_ops { extern struct cache_ops cache_sync_internal_ct_ops; extern struct cache_ops cache_sync_external_ct_ops; extern struct cache_ops cache_stats_ct_ops; +/* templates to configure expectation caching. */ +extern struct cache_ops cache_sync_internal_exp_ops; +extern struct cache_ops cache_sync_external_exp_ops; struct nf_conntrack; diff --git a/include/conntrackd.h b/include/conntrackd.h index 697d3d7..8baa088 100644 --- a/include/conntrackd.h +++ b/include/conntrackd.h @@ -37,6 +37,16 @@ #define CT_FLUSH_EXT_CACHE 34 /* flush external cache */ #define STATS_PROCESS 35 /* child process stats */ #define STATS_QUEUE 36 /* queue stats */ +#define EXP_STATS 37 /* dump statistics */ +#define EXP_FLUSH_MASTER 38 /* flush kernel expect table */ +#define EXP_RESYNC_MASTER 39 /* resync with kernel exp table */ +#define EXP_DUMP_INTERNAL 40 /* dump internal expect cache */ +#define EXP_DUMP_EXTERNAL 41 /* dump external expect cache */ +#define EXP_COMMIT 42 /* commit expectations */ +#define ALL_FLUSH_MASTER 43 /* flush all kernel tables */ +#define ALL_RESYNC_MASTER 44 /* resync w/all kernel tables */ +#define ALL_FLUSH_CACHE 45 /* flush all caches */ +#define ALL_COMMIT 46 /* commit all tables */ #define DEFAULT_CONFIGFILE "/etc/conntrackd/conntrackd.conf" #define DEFAULT_LOCKFILE "/var/lock/conntrackd.lock" @@ -56,6 +66,7 @@ #define CTD_SYNC_ALARM (1UL << 3) #define CTD_SYNC_NOTRACK (1UL << 4) #define CTD_POLL (1UL << 5) +#define CTD_EXPECT (1UL << 6) /* FILENAME_MAX is 4096 on my system, perhaps too much? */ #ifndef FILENAME_MAXLEN @@ -105,6 +116,8 @@ struct ct_conf { int tcp_window_tracking; } sync; struct { + int subsys_id; + int groups; int events_reliable; } netlink; struct { @@ -130,6 +143,7 @@ struct ct_general_state { struct local_server local; struct ct_mode *mode; struct ct_filter *us_filter; + struct exp_filter *exp_filter; struct nfct_handle *event; /* event handler */ struct nfct_filter *filter; /* event filter */ @@ -177,6 +191,10 @@ struct ct_general_state { } stats; }; +struct commit_runqueue { + int (*cb)(struct nfct_handle *h, int step); +}; + #define STATE_SYNC(x) state.sync->x struct ct_sync_state { @@ -196,6 +214,7 @@ struct ct_sync_state { struct nfct_handle *h; struct evfd *evfd; int current; + struct commit_runqueue rq[2]; struct { int ok; int fail; diff --git a/include/external.h b/include/external.h index eef0e42..70f0c5c 100644 --- a/include/external.h +++ b/include/external.h @@ -18,6 +18,17 @@ struct external_handler { void (*stats)(int fd); void (*stats_ext)(int fd); } ct; + struct { + void (*new)(struct nf_expect *exp); + void (*upd)(struct nf_expect *exp); + void (*del)(struct nf_expect *exp); + + void (*dump)(int fd, int type); + void (*flush)(void); + int (*commit)(struct nfct_handle *h, int fd); + void (*stats)(int fd); + void (*stats_ext)(int fd); + } exp; }; extern struct external_handler external_cache; diff --git a/include/filter.h b/include/filter.h index f19b18b..3c7c8cc 100644 --- a/include/filter.h +++ b/include/filter.h @@ -52,4 +52,11 @@ void ct_filter_set_logic(struct ct_filter *f, enum ct_filter_logic logic); int ct_filter_conntrack(const struct nf_conntrack *ct, int userspace); +struct exp_filter; +struct nf_expect; + +struct exp_filter *exp_filter_create(void); +int exp_filter_add(struct exp_filter *f, const char *helper_name); +int exp_filter_find(struct exp_filter *f, const struct nf_expect *exp); + #endif diff --git a/include/internal.h b/include/internal.h index f50eb79..2ba9714 100644 --- a/include/internal.h +++ b/include/internal.h @@ -34,6 +34,23 @@ struct internal_handler { void (*stats)(int fd); void (*stats_ext)(int fd); } ct; + struct { + void *data; + + void (*new)(struct nf_expect *exp, int origin_type); + void (*upd)(struct nf_expect *exp, int origin_type); + int (*del)(struct nf_expect *exp, int origin_type); + + void (*dump)(int fd, int type); + void (*populate)(struct nf_expect *exp); + void (*purge)(void); + int (*resync)(enum nf_conntrack_msg_type type, + struct nf_expect *exp, void *data); + void (*flush)(void); + + void (*stats)(int fd); + void (*stats_ext)(int fd); + } exp; }; extern struct internal_handler internal_cache; diff --git a/include/log.h b/include/log.h index f5c5b4f..ae58e79 100644 --- a/include/log.h +++ b/include/log.h @@ -4,10 +4,12 @@ #include struct nf_conntrack; +struct nf_expect; int init_log(void); void dlog(int priority, const char *format, ...); void dlog_ct(FILE *fd, struct nf_conntrack *ct, unsigned int type); +void dlog_exp(FILE *fd, struct nf_expect *exp, unsigned int type); void close_log(void); #endif diff --git a/include/netlink.h b/include/netlink.h index 0df0cbb..3bde30c 100644 --- a/include/netlink.h +++ b/include/netlink.h @@ -30,4 +30,11 @@ static inline int ct_is_related(const struct nf_conntrack *ct) nfct_attr_is_set(ct, ATTR_MASTER_PORT_DST)); } +int nl_create_expect(struct nfct_handle *h, const struct nf_expect *orig, int timeout); +int nl_destroy_expect(struct nfct_handle *h, const struct nf_expect *exp); +int nl_get_expect(struct nfct_handle *h, const struct nf_expect *exp); +int nl_dump_expect_table(struct nfct_handle *h); +int nl_flush_expect_table(struct nfct_handle *h); +int nl_send_expect_resync(struct nfct_handle *h); + #endif diff --git a/include/network.h b/include/network.h index d0531b9..ab95499 100644 --- a/include/network.h +++ b/include/network.h @@ -4,9 +4,10 @@ #include #include -#define CONNTRACKD_PROTOCOL_VERSION 0 +#define CONNTRACKD_PROTOCOL_VERSION 1 struct nf_conntrack; +struct nf_expect; struct nethdr { #if __BYTE_ORDER == __LITTLE_ENDIAN @@ -28,7 +29,10 @@ enum nethdr_type { NET_T_STATE_CT_NEW = 0, NET_T_STATE_CT_UPD, NET_T_STATE_CT_DEL, - NET_T_STATE_MAX = NET_T_STATE_CT_DEL, + NET_T_STATE_EXP_NEW = 3, + NET_T_STATE_EXP_UPD, + NET_T_STATE_EXP_DEL, + NET_T_STATE_MAX = NET_T_STATE_EXP_DEL, NET_T_CTL = 10, }; @@ -92,6 +96,17 @@ enum { __hdr; \ }) +#define BUILD_NETMSG_FROM_EXP(exp, query) \ +({ \ + static char __net[4096]; \ + struct nethdr *__hdr = (struct nethdr *) __net; \ + memset(__hdr, 0, NETHDR_SIZ); \ + nethdr_set(__hdr, query); \ + exp2msg(exp, __hdr); \ + HDR_HOST2NETWORK(__hdr); \ + __hdr; \ +}) + struct mcast_sock_multi; enum { @@ -239,4 +254,25 @@ struct nta_attr_natseqadj { void ct2msg(const struct nf_conntrack *ct, struct nethdr *n); int msg2ct(struct nf_conntrack *ct, struct nethdr *n, size_t remain); +enum nta_exp_attr { + NTA_EXP_MASTER_IPV4 = 0, /* struct nfct_attr_grp_ipv4 */ + NTA_EXP_MASTER_IPV6, /* struct nfct_attr_grp_ipv6 */ + NTA_EXP_MASTER_L4PROTO, /* uint8_t */ + NTA_EXP_MASTER_PORT, /* struct nfct_attr_grp_port */ + NTA_EXP_EXPECT_IPV4 = 4, /* struct nfct_attr_grp_ipv4 */ + NTA_EXP_EXPECT_IPV6, /* struct nfct_attr_grp_ipv6 */ + NTA_EXP_EXPECT_L4PROTO, /* uint8_t */ + NTA_EXP_EXPECT_PORT, /* struct nfct_attr_grp_port */ + NTA_EXP_MASK_IPV4 = 8, /* struct nfct_attr_grp_ipv4 */ + NTA_EXP_MASK_IPV6, /* struct nfct_attr_grp_ipv6 */ + NTA_EXP_MASK_L4PROTO, /* uint8_t */ + NTA_EXP_MASK_PORT, /* struct nfct_attr_grp_port */ + NTA_EXP_TIMEOUT, /* uint32_t */ + NTA_EXP_FLAGS, /* uint32_t */ + NTA_EXP_MAX +}; + +void exp2msg(const struct nf_expect *exp, struct nethdr *n); +int msg2exp(struct nf_expect *exp, struct nethdr *n, size_t remain); + #endif diff --git a/src/Makefile.am b/src/Makefile.am index a0abeee..7d7b2ac 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -12,7 +12,7 @@ conntrack_LDADD = ../extensions/libct_proto_tcp.la ../extensions/libct_proto_udp conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c rbtree.c \ local.c log.c mcast.c udp.c netlink.c vector.c \ filter.c fds.c event.c process.c origin.c date.c \ - cache.c cache-ct.c \ + cache.c cache-ct.c cache-exp.c \ cache_timer.c \ sync-mode.c sync-alarm.c sync-ftfw.c sync-notrack.c \ traffic_stats.c stats-mode.c \ diff --git a/src/build.c b/src/build.c index 9c3687c..3193884 100644 --- a/src/build.c +++ b/src/build.c @@ -224,3 +224,102 @@ void ct2msg(const struct nf_conntrack *ct, struct nethdr *n) if (nfct_attr_is_set_array(ct, nat_type, 6)) ct_build_natseqadj(ct, n); } + +static void +exp_build_l4proto_tcp(const struct nf_conntrack *ct, struct nethdr *n, int a) +{ + ct_build_group(ct, ATTR_GRP_ORIG_PORT, n, a, + sizeof(struct nfct_attr_grp_port)); +} + +static void +exp_build_l4proto_sctp(const struct nf_conntrack *ct, struct nethdr *n, int a) +{ + ct_build_group(ct, ATTR_GRP_ORIG_PORT, n, a, + sizeof(struct nfct_attr_grp_port)); +} + +static void +exp_build_l4proto_dccp(const struct nf_conntrack *ct, struct nethdr *n, int a) +{ + ct_build_group(ct, ATTR_GRP_ORIG_PORT, n, a, + sizeof(struct nfct_attr_grp_port)); +} + +static void +exp_build_l4proto_udp(const struct nf_conntrack *ct, struct nethdr *n, int a) +{ + ct_build_group(ct, ATTR_GRP_ORIG_PORT, n, a, + sizeof(struct nfct_attr_grp_port)); +} + +static struct exp_build_l4proto { + void (*build)(const struct nf_conntrack *, struct nethdr *n, int a); +} exp_l4proto_fcn[IPPROTO_MAX] = { + [IPPROTO_TCP] = { .build = exp_build_l4proto_tcp }, + [IPPROTO_SCTP] = { .build = exp_build_l4proto_sctp }, + [IPPROTO_DCCP] = { .build = exp_build_l4proto_dccp }, + [IPPROTO_UDP] = { .build = exp_build_l4proto_udp }, +}; + +static inline void +exp_build_u32(const struct nf_expect *exp, int a, struct nethdr *n, int b) +{ + uint32_t data = nfexp_get_attr_u32(exp, a); + data = htonl(data); + addattr(n, b, &data, sizeof(uint32_t)); +} + +void exp2msg(const struct nf_expect *exp, struct nethdr *n) +{ + const struct nf_conntrack *ct = nfexp_get_attr(exp, ATTR_EXP_MASTER); + uint8_t l4proto = nfct_get_attr_u8(ct, ATTR_L4PROTO); + + /* master conntrack for this expectation. */ + if (nfct_attr_grp_is_set(ct, ATTR_GRP_ORIG_IPV4)) { + ct_build_group(ct, ATTR_GRP_ORIG_IPV4, n, NTA_EXP_MASTER_IPV4, + sizeof(struct nfct_attr_grp_ipv4)); + } else if (nfct_attr_grp_is_set(ct, ATTR_GRP_ORIG_IPV6)) { + ct_build_group(ct, ATTR_GRP_ORIG_IPV6, n, NTA_EXP_MASTER_IPV6, + sizeof(struct nfct_attr_grp_ipv6)); + } + ct_build_u8(ct, ATTR_L4PROTO, n, NTA_EXP_MASTER_L4PROTO); + + if (exp_l4proto_fcn[l4proto].build) + exp_l4proto_fcn[l4proto].build(ct, n, NTA_EXP_MASTER_PORT); + + /* the expectation itself. */ + ct = nfexp_get_attr(exp, ATTR_EXP_EXPECTED); + + if (nfct_attr_grp_is_set(ct, ATTR_GRP_ORIG_IPV4)) { + ct_build_group(ct, ATTR_GRP_ORIG_IPV4, n, NTA_EXP_EXPECT_IPV4, + sizeof(struct nfct_attr_grp_ipv4)); + } else if (nfct_attr_grp_is_set(ct, ATTR_GRP_ORIG_IPV6)) { + ct_build_group(ct, ATTR_GRP_ORIG_IPV6, n, NTA_EXP_EXPECT_IPV6, + sizeof(struct nfct_attr_grp_ipv6)); + } + ct_build_u8(ct, ATTR_L4PROTO, n, NTA_EXP_EXPECT_L4PROTO); + + if (exp_l4proto_fcn[l4proto].build) + exp_l4proto_fcn[l4proto].build(ct, n, NTA_EXP_EXPECT_PORT); + + /* mask for the expectation. */ + ct = nfexp_get_attr(exp, ATTR_EXP_MASK); + + if (nfct_attr_grp_is_set(ct, ATTR_GRP_ORIG_IPV4)) { + ct_build_group(ct, ATTR_GRP_ORIG_IPV4, n, NTA_EXP_MASK_IPV4, + sizeof(struct nfct_attr_grp_ipv4)); + } else if (nfct_attr_grp_is_set(ct, ATTR_GRP_ORIG_IPV6)) { + ct_build_group(ct, ATTR_GRP_ORIG_IPV6, n, NTA_EXP_MASK_IPV6, + sizeof(struct nfct_attr_grp_ipv6)); + } + ct_build_u8(ct, ATTR_L4PROTO, n, NTA_EXP_MASK_L4PROTO); + + if (exp_l4proto_fcn[l4proto].build) + exp_l4proto_fcn[l4proto].build(ct, n, NTA_EXP_MASK_PORT); + + if (!CONFIG(commit_timeout) && nfexp_attr_is_set(exp, ATTR_EXP_TIMEOUT)) + exp_build_u32(exp, ATTR_EXP_TIMEOUT, n, NTA_EXP_TIMEOUT); + + exp_build_u32(exp, ATTR_EXP_FLAGS, n, NTA_EXP_FLAGS); +} diff --git a/src/cache-ct.c b/src/cache-ct.c index 2c6fd4e..0ad8d2a 100644 --- a/src/cache-ct.c +++ b/src/cache-ct.c @@ -251,7 +251,7 @@ static int cache_ct_commit(struct cache *c, struct nfct_handle *h, int clientfd) /* we already have one commit in progress, skip this. The clientfd * descriptor has to be closed by the caller. */ if (clientfd && STATE_SYNC(commit).clientfd != -1) - return 0; + return -1; switch(STATE_SYNC(commit).state) { case COMMIT_STATE_INACTIVE: @@ -308,9 +308,7 @@ static int cache_ct_commit(struct cache *c, struct nfct_handle *h, int clientfd) STATE_SYNC(commit).current = 0; STATE_SYNC(commit).state = COMMIT_STATE_INACTIVE; - /* Close the client socket now that we're done. */ - close(STATE_SYNC(commit).clientfd); - STATE_SYNC(commit).clientfd = -1; + return 0; } return 1; } diff --git a/src/cache-exp.c b/src/cache-exp.c new file mode 100644 index 0000000..e88877a --- /dev/null +++ b/src/cache-exp.c @@ -0,0 +1,308 @@ +/* + * (C) 2006-2011 by Pablo Neira Ayuso + * (C) 2011 by Vyatta Inc. + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "cache.h" +#include "hash.h" +#include "log.h" +#include "conntrackd.h" +#include "netlink.h" +#include "event.h" +#include "jhash.h" +#include "network.h" + +#include +#include +#include +#include + +static uint32_t +cache_hash4_exp(const struct nf_conntrack *ct, const struct hashtable *table) +{ + uint32_t a[4] = { + [0] = nfct_get_attr_u32(ct, ATTR_IPV4_SRC), + [1] = nfct_get_attr_u32(ct, ATTR_IPV4_DST), + [2] = nfct_get_attr_u8(ct, ATTR_L3PROTO) << 16 | + nfct_get_attr_u8(ct, ATTR_L4PROTO), + [3] = nfct_get_attr_u16(ct, ATTR_PORT_SRC) << 16 | + nfct_get_attr_u16(ct, ATTR_PORT_DST), + }; + + /* + * Instead of returning hash % table->hashsize (implying a divide) + * we return the high 32 bits of the (hash * table->hashsize) that will + * give results between [0 and hashsize-1] and same hash distribution, + * but using a multiply, less expensive than a divide. See: + * http://www.mail-archive.com/netdev@vger.kernel.org/msg56623.html + */ + return ((uint64_t)jhash2(a, 4, 0) * table->hashsize) >> 32; +} + +static uint32_t +cache_hash6_exp(const struct nf_conntrack *ct, const struct hashtable *table) +{ + uint32_t a[10]; + + memcpy(&a[0], nfct_get_attr(ct, ATTR_IPV6_SRC), sizeof(uint32_t)*4); + memcpy(&a[4], nfct_get_attr(ct, ATTR_IPV6_SRC), sizeof(uint32_t)*4); + a[8] = nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO) << 16 | + nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO); + a[9] = nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC) << 16 | + nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST); + + return ((uint64_t)jhash2(a, 10, 0) * table->hashsize) >> 32; +} + +static uint32_t +cache_exp_hash(const void *data, const struct hashtable *table) +{ + int ret = 0; + const struct nf_expect *exp = data; + const struct nf_conntrack *ct = nfexp_get_attr(exp, ATTR_EXP_MASTER); + + switch(nfct_get_attr_u8(ct, ATTR_L3PROTO)) { + case AF_INET: + ret = cache_hash4_exp(ct, table); + break; + case AF_INET6: + ret = cache_hash6_exp(ct, table); + break; + default: + dlog(LOG_ERR, "unknown layer 3 proto in hash"); + break; + } + return ret; +} + +static int cache_exp_cmp(const void *data1, const void *data2) +{ + const struct cache_object *obj = data1; + const struct nf_expect *exp = data2; + + return nfexp_cmp(obj->ptr, exp, 0); +} + +static void *cache_exp_alloc(void) +{ + return nfexp_new(); +} + +static void cache_exp_free(void *ptr) +{ + nfexp_destroy(ptr); +} + +static void cache_exp_copy(void *dst, void *src, unsigned int flags) +{ + /* XXX: add nfexp_copy(...) to libnetfilter_conntrack. */ + memcpy(dst, src, nfexp_maxsize()); +} + +static int cache_exp_dump_step(void *data1, void *n) +{ + char buf[1024]; + int size; + struct __dump_container *container = data1; + struct cache_object *obj = n; + char *data = obj->data; + unsigned i; + + /* + * XXX: Do not dump the entries that are scheduled to expire. + * These entries talk about already destroyed connections + * that we keep for some time just in case that we have to + * resent some lost messages. We do not show them to the + * user as he may think that the firewall replicas are not + * in sync. The branch below is a hack as it is quite + * specific and it breaks conntrackd modularity. Probably + * there's a nicer way to do this but until I come up with it... + */ + if (CONFIG(flags) & CTD_SYNC_FTFW && obj->status == C_OBJ_DEAD) + return 0; + + /* do not show cached timeout, this may confuse users */ + if (nfexp_attr_is_set(obj->ptr, ATTR_EXP_TIMEOUT)) + nfexp_attr_unset(obj->ptr, ATTR_EXP_TIMEOUT); + + memset(buf, 0, sizeof(buf)); + size = nfexp_snprintf(buf, sizeof(buf),obj->ptr, + NFCT_T_UNKNOWN, container->type, 0); + + for (i = 0; i < obj->cache->num_features; i++) { + if (obj->cache->features[i]->dump) { + size += obj->cache->features[i]->dump(obj, data, + buf+size, + container->type); + data += obj->cache->features[i]->size; + } + } + if (container->type != NFCT_O_XML) { + long tm = time(NULL); + size += sprintf(buf+size, " [active since %lds]", + tm - obj->lifetime); + } + size += sprintf(buf+size, "\n"); + if (send(container->fd, buf, size, 0) == -1) { + if (errno != EPIPE) + return -1; + } + + return 0; +} + +static int cache_exp_commit_step(void *data, void *n) +{ + struct cache_object *obj = n; + struct __commit_container *tmp = data; + int ret, retry = 1, timeout; + struct nf_expect *exp = obj->ptr; + + if (CONFIG(commit_timeout)) { + timeout = CONFIG(commit_timeout); + } else { + timeout = time(NULL) - obj->lastupdate; + if (timeout < 0) { + /* XXX: Arbitrarily set the timer to one minute, how + * can this happen? For example, an adjustment due to + * daylight-saving. Probably other situations can + * trigger this. */ + timeout = 60; + } + /* calculate an estimation of the current timeout */ + timeout = nfexp_get_attr_u32(exp, ATTR_EXP_TIMEOUT) - timeout; + if (timeout < 0) { + timeout = 60; + } + } + +retry: + if (nl_create_expect(tmp->h, exp, timeout) == -1) { + if (errno == EEXIST && retry == 1) { + ret = nl_destroy_expect(tmp->h, exp); + if (ret == 0 || (ret == -1 && errno == ENOENT)) { + if (retry) { + retry = 0; + goto retry; + } + } + dlog(LOG_ERR, "commit-destroy: %s", strerror(errno)); + dlog_exp(STATE(log), exp, NFCT_O_PLAIN); + tmp->c->stats.commit_fail++; + } else { + dlog(LOG_ERR, "commit-create: %s", strerror(errno)); + dlog_exp(STATE(log), exp, NFCT_O_PLAIN); + tmp->c->stats.commit_fail++; + } + } else { + tmp->c->stats.commit_ok++; + } + /* keep iterating even if we have found errors */ + return 0; +} + +static int +cache_exp_commit(struct cache *c, struct nfct_handle *h, int clientfd) +{ + unsigned int commit_ok, commit_fail; + struct timeval commit_stop, res; + struct __commit_container tmp = { + .h = h, + .c = c, + }; + + /* we already have one commit in progress, skip this. The clientfd + * descriptor has to be closed by the caller. */ + if (clientfd && STATE_SYNC(commit).clientfd != -1) + return -1; + + switch(STATE_SYNC(commit).state) { + case COMMIT_STATE_INACTIVE: + gettimeofday(&STATE_SYNC(commit).stats.start, NULL); + STATE_SYNC(commit).stats.ok = c->stats.commit_ok; + STATE_SYNC(commit).stats.fail = c->stats.commit_fail; + STATE_SYNC(commit).clientfd = clientfd; + case COMMIT_STATE_MASTER: + STATE_SYNC(commit).current = + hashtable_iterate_limit(c->h, &tmp, + STATE_SYNC(commit).current, + CONFIG(general).commit_steps, + cache_exp_commit_step); + if (STATE_SYNC(commit).current < CONFIG(hashsize)) { + STATE_SYNC(commit).state = COMMIT_STATE_MASTER; + /* give it another step as soon as possible */ + write_evfd(STATE_SYNC(commit).evfd); + return 1; + } + + /* calculate the time that commit has taken */ + gettimeofday(&commit_stop, NULL); + timersub(&commit_stop, &STATE_SYNC(commit).stats.start, &res); + + /* calculate new entries committed */ + commit_ok = c->stats.commit_ok - STATE_SYNC(commit).stats.ok; + commit_fail = + c->stats.commit_fail - STATE_SYNC(commit).stats.fail; + + /* log results */ + dlog(LOG_NOTICE, "Committed %u new expectations", commit_ok); + + if (commit_fail) + dlog(LOG_NOTICE, "%u expectations can't be " + "committed", commit_fail); + + dlog(LOG_NOTICE, "commit has taken %lu.%06lu seconds", + res.tv_sec, res.tv_usec); + + /* prepare the state machine for new commits */ + STATE_SYNC(commit).current = 0; + STATE_SYNC(commit).state = COMMIT_STATE_INACTIVE; + + return 0; + } + return 1; +} + +static struct nethdr * +cache_exp_build_msg(const struct cache_object *obj, int type) +{ + return BUILD_NETMSG_FROM_EXP(obj->ptr, type); +} + +/* template to cache expectations coming from the kernel. */ +struct cache_ops cache_sync_internal_exp_ops = { + .hash = cache_exp_hash, + .cmp = cache_exp_cmp, + .alloc = cache_exp_alloc, + .free = cache_exp_free, + .copy = cache_exp_copy, + .dump_step = cache_exp_dump_step, + .commit = NULL, + .build_msg = cache_exp_build_msg, +}; + +/* template to cache expectations coming from the network. */ +struct cache_ops cache_sync_external_exp_ops = { + .hash = cache_exp_hash, + .cmp = cache_exp_cmp, + .alloc = cache_exp_alloc, + .free = cache_exp_free, + .copy = cache_exp_copy, + .dump_step = cache_exp_dump_step, + .commit = cache_exp_commit, + .build_msg = NULL, +}; diff --git a/src/external_cache.c b/src/external_cache.c index 3f896a0..e290249 100644 --- a/src/external_cache.c +++ b/src/external_cache.c @@ -26,6 +26,7 @@ #include static struct cache *external; +static struct cache *external_exp; static int external_cache_init(void) { @@ -36,12 +37,21 @@ static int external_cache_init(void) dlog(LOG_ERR, "can't allocate memory for the external cache"); return -1; } + external_exp = cache_create("external", CACHE_T_EXP, + STATE_SYNC(sync)->external_cache_flags, + NULL, &cache_sync_external_exp_ops); + if (external_exp == NULL) { + dlog(LOG_ERR, "can't allocate memory for the external cache"); + return -1; + } + return 0; } static void external_cache_close(void) { cache_destroy(external); + cache_destroy(external_exp); } static void external_cache_ct_new(struct nf_conntrack *ct) @@ -109,6 +119,71 @@ static void external_cache_ct_stats_ext(int fd) cache_stats_extended(external, fd); } +static void external_cache_exp_new(struct nf_expect *exp) +{ + struct cache_object *obj; + int id; + + obj = cache_find(external_exp, exp, &id); + if (obj == NULL) { +retry: + obj = cache_object_new(external_exp, exp); + if (obj == NULL) + return; + + if (cache_add(external_exp, obj, id) == -1) { + cache_object_free(obj); + return; + } + } else { + cache_del(external_exp, obj); + cache_object_free(obj); + goto retry; + } +} + +static void external_cache_exp_upd(struct nf_expect *exp) +{ + cache_update_force(external_exp, exp); +} + +static void external_cache_exp_del(struct nf_expect *exp) +{ + struct cache_object *obj; + int id; + + obj = cache_find(external_exp, exp, &id); + if (obj) { + cache_del(external_exp, obj); + cache_object_free(obj); + } +} + +static void external_cache_exp_dump(int fd, int type) +{ + cache_dump(external_exp, fd, type); +} + +static int external_cache_exp_commit(struct nfct_handle *h, int fd) +{ + return cache_commit(external_exp, h, fd); +} + +static void external_cache_exp_flush(void) +{ + cache_flush(external_exp); +} + +static void external_cache_exp_stats(int fd) +{ + cache_stats(external_exp, fd); +} + +static void external_cache_exp_stats_ext(int fd) +{ + cache_stats_extended(external_exp, fd); +} + struct external_handler external_cache = { .init = external_cache_init, .close = external_cache_close, @@ -122,4 +197,14 @@ struct external_handler external_cache = { .stats = external_cache_ct_stats, .stats_ext = external_cache_ct_stats_ext, }, + .exp = { + .new = external_cache_exp_new, + .upd = external_cache_exp_upd, + .del = external_cache_exp_del, + .dump = external_cache_exp_dump, + .commit = external_cache_exp_commit, + .flush = external_cache_exp_flush, + .stats = external_cache_exp_stats, + .stats_ext = external_cache_exp_stats_ext, + }, }; diff --git a/src/external_inject.c b/src/external_inject.c index ba5f3d1..0ad3478 100644 --- a/src/external_inject.c +++ b/src/external_inject.c @@ -42,7 +42,7 @@ struct { static int external_inject_init(void) { /* handler to directly inject conntracks into kernel-space */ - inject = nfct_open(CONNTRACK, 0); + inject = nfct_open(CONFIG(netlink).subsys_id, 0); if (inject == NULL) { dlog(LOG_ERR, "can't open netlink handler: %s", strerror(errno)); @@ -175,6 +175,89 @@ static void external_inject_ct_stats(int fd) send(fd, buf, size, 0); } +struct { + uint32_t add_ok; + uint32_t add_fail; + uint32_t upd_ok; + uint32_t upd_fail; + uint32_t del_ok; + uint32_t del_fail; +} exp_external_inject_stat; + +static void external_inject_exp_new(struct nf_expect *exp) +{ + int ret, retry = 1; + +retry: + if (nl_create_expect(inject, exp, 0) == -1) { + /* if the state entry exists, we delete and try again */ + if (errno == EEXIST && retry == 1) { + ret = nl_destroy_expect(inject, exp); + if (ret == 0 || (ret == -1 && errno == ENOENT)) { + if (retry) { + retry = 0; + goto retry; + } + } + exp_external_inject_stat.add_fail++; + dlog(LOG_ERR, "inject-add1: %s", strerror(errno)); + dlog_exp(STATE(log), exp, NFCT_O_PLAIN); + return; + } + exp_external_inject_stat.add_fail++; + dlog(LOG_ERR, "inject-add2: %s", strerror(errno)); + dlog_exp(STATE(log), exp, NFCT_O_PLAIN); + } else { + exp_external_inject_stat.add_ok++; + } +} + +static void external_inject_exp_del(struct nf_expect *exp) +{ + if (nl_destroy_expect(inject, exp) == -1) { + if (errno != ENOENT) { + exp_external_inject_stat.del_fail++; + dlog(LOG_ERR, "inject-del: %s", strerror(errno)); + dlog_exp(STATE(log), exp, NFCT_O_PLAIN); + } + } else { + exp_external_inject_stat.del_ok++; + } +} + +static void external_inject_exp_dump(int fd, int type) +{ +} + +static int external_inject_exp_commit(struct nfct_handle *h, int fd) +{ + /* close the commit socket. */ + return LOCAL_RET_OK; +} + +static void external_inject_exp_flush(void) +{ +} + +static void external_inject_exp_stats(int fd) +{ + char buf[512]; + int size; + + size = sprintf(buf, "external inject:\n" + "connections created:\t\t%12u\tfailed:\t%12u\n" + "connections updated:\t\t%12u\tfailed:\t%12u\n" + "connections destroyed:\t\t%12u\tfailed:\t%12u\n\n", + exp_external_inject_stat.add_ok, + exp_external_inject_stat.add_fail, + exp_external_inject_stat.upd_ok, + exp_external_inject_stat.upd_fail, + exp_external_inject_stat.del_ok, + exp_external_inject_stat.del_fail); + + send(fd, buf, size, 0); +} + struct external_handler external_inject = { .init = external_inject_init, .close = external_inject_close, @@ -188,4 +271,14 @@ struct external_handler external_inject = { .stats = external_inject_ct_stats, .stats_ext = external_inject_ct_stats, }, + .exp = { + .new = external_inject_exp_new, + .upd = external_inject_exp_new, + .del = external_inject_exp_del, + .dump = external_inject_exp_dump, + .commit = external_inject_exp_commit, + .flush = external_inject_exp_flush, + .stats = external_inject_exp_stats, + .stats_ext = external_inject_exp_stats, + }, }; diff --git a/src/filter.c b/src/filter.c index 746a9bb..e8515d6 100644 --- a/src/filter.c +++ b/src/filter.c @@ -405,3 +405,79 @@ int ct_filter_conntrack(const struct nf_conntrack *ct, int userspace) return 0; } + +struct exp_filter { + struct list_head list; +}; + +struct exp_filter *exp_filter_create(void) +{ + struct exp_filter *f; + + f = calloc(1, sizeof(struct exp_filter)); + if (f == NULL) + return NULL; + + INIT_LIST_HEAD(&f->list); + return f; +} + +struct exp_filter_item { + struct list_head head; + char helper_name[NFCT_HELPER_NAME_MAX]; +}; + +/* this is ugly, but it simplifies read_config_yy.y */ +static struct exp_filter *exp_filter_alloc(void) +{ + if (STATE(exp_filter) == NULL) { + STATE(exp_filter) = exp_filter_create(); + if (STATE(exp_filter) == NULL) { + fprintf(stderr, "Can't init expectation filtering!\n"); + return NULL; + } + } + return STATE(exp_filter);; +} + +int exp_filter_add(struct exp_filter *f, const char *helper_name) +{ + struct exp_filter_item *item; + + f = exp_filter_alloc(); + if (f == NULL) + return -1; + + list_for_each_entry(item, &f->list, head) { + if (strncmp(item->helper_name, helper_name, + NFCT_HELPER_NAME_MAX) == 0) { + return -1; + } + } + item = calloc(1, sizeof(struct exp_filter_item)); + if (item == NULL) + return -1; + + strncpy(item->helper_name, helper_name, NFCT_HELPER_NAME_MAX); + list_add(&item->head, &f->list); + return 0; +} + +int exp_filter_find(struct exp_filter *f, const struct nf_expect *exp) +{ + struct exp_filter_item *item; + + if (f == NULL) + return 0; + + list_for_each_entry(item, &f->list, head) { + const char *name = nfexp_get_attr(exp, ATTR_EXP_HELPER_NAME); + + /* we allow partial matching to support things like sip-PORT. */ + if (strncmp(item->helper_name, name, + strlen(item->helper_name)) == 0) { + return 1; + } + } + return 0; +} diff --git a/src/internal_bypass.c b/src/internal_bypass.c index 98717f3..5c83c21 100644 --- a/src/internal_bypass.c +++ b/src/internal_bypass.c @@ -52,7 +52,7 @@ static void internal_bypass_ct_dump(int fd, int type) u_int32_t family = AF_UNSPEC; int ret; - h = nfct_open(CONNTRACK, 0); + h = nfct_open(CONFIG(netlink).subsys_id, 0); if (h == NULL) { dlog(LOG_ERR, "can't allocate memory for the internal cache"); return; @@ -151,6 +151,138 @@ static int internal_bypass_ct_event_del(struct nf_conntrack *ct, int origin) return 1; } +static int +internal_bypass_exp_dump_cb(enum nf_conntrack_msg_type type, + struct nf_expect *exp, void *data) +{ + char buf[1024]; + int size, *fd = data; + const struct nf_conntrack *master = + nfexp_get_attr(exp, ATTR_EXP_MASTER); + + if (!exp_filter_find(STATE(exp_filter), exp)) + return NFCT_CB_CONTINUE; + + if (ct_filter_conntrack(master, 1)) + return NFCT_CB_CONTINUE; + + size = nfexp_snprintf(buf, 1024, exp, + NFCT_T_UNKNOWN, NFCT_O_DEFAULT, 0); + if (size < 1024) { + buf[size] = '\n'; + size++; + } + send(*fd, buf, size, 0); + + return NFCT_CB_CONTINUE; +} + +static void internal_bypass_exp_dump(int fd, int type) +{ + struct nfct_handle *h; + u_int32_t family = AF_UNSPEC; + int ret; + + h = nfct_open(CONFIG(netlink).subsys_id, 0); + if (h == NULL) { + dlog(LOG_ERR, "can't allocate memory for the internal cache"); + return; + } + nfexp_callback_register(h, NFCT_T_ALL, + internal_bypass_exp_dump_cb, &fd); + ret = nfexp_query(h, NFCT_Q_DUMP, &family); + if (ret == -1) { + dlog(LOG_ERR, "can't dump kernel table"); + } + nfct_close(h); +} + +static void internal_bypass_exp_flush(void) +{ + nl_flush_expect_table(STATE(flush)); +} + +struct { + uint32_t new; + uint32_t upd; + uint32_t del; +} exp_internal_bypass_stats; + +static void internal_bypass_exp_stats(int fd) +{ + char buf[512]; + int size; + + size = sprintf(buf, "internal bypass:\n" + "connections new:\t\t%12u\n" + "connections updated:\t\t%12u\n" + "connections destroyed:\t\t%12u\n\n", + exp_internal_bypass_stats.new, + exp_internal_bypass_stats.upd, + exp_internal_bypass_stats.del); + + send(fd, buf, size, 0); +} + +/* unused, INTERNAL_F_POPULATE is unset. No cache, nothing to populate. */ +static void internal_bypass_exp_populate(struct nf_expect *exp) +{ +} + +/* unused, INTERNAL_F_RESYNC is unset. */ +static void internal_bypass_exp_purge(void) +{ +} + +/* unused, INTERNAL_F_RESYNC is unset. Nothing to resync, we have no cache. */ +static int +internal_bypass_exp_resync(enum nf_conntrack_msg_type type, + struct nf_expect *exp, void *data) +{ + return NFCT_CB_CONTINUE; +} + +static void internal_bypass_exp_event_new(struct nf_expect *exp, int origin) +{ + struct nethdr *net; + + /* this event has been triggered by me, skip */ + if (origin != CTD_ORIGIN_NOT_ME) + return; + + net = BUILD_NETMSG_FROM_EXP(exp, NET_T_STATE_EXP_NEW); + multichannel_send(STATE_SYNC(channel), net); + exp_internal_bypass_stats.new++; +} + +static void internal_bypass_exp_event_upd(struct nf_expect *exp, int origin) +{ + struct nethdr *net; + + /* this event has been triggered by me, skip */ + if (origin != CTD_ORIGIN_NOT_ME) + return; + + net = BUILD_NETMSG_FROM_EXP(exp, NET_T_STATE_EXP_UPD); + multichannel_send(STATE_SYNC(channel), net); + exp_internal_bypass_stats.upd++; +} + +static int internal_bypass_exp_event_del(struct nf_expect *exp, int origin) +{ + struct nethdr *net; + + /* this event has been triggered by me, skip */ + if (origin != CTD_ORIGIN_NOT_ME) + return 1; + + net = BUILD_NETMSG_FROM_EXP(exp, NET_T_STATE_EXP_DEL); + multichannel_send(STATE_SYNC(channel), net); + exp_internal_bypass_stats.del++; + + return 1; +} + struct internal_handler internal_bypass = { .init = internal_bypass_init, .close = internal_bypass_close, @@ -166,4 +298,16 @@ struct internal_handler internal_bypass = { .upd = internal_bypass_ct_event_upd, .del = internal_bypass_ct_event_del, }, + .exp = { + .dump = internal_bypass_exp_dump, + .flush = internal_bypass_exp_flush, + .stats = internal_bypass_exp_stats, + .stats_ext = internal_bypass_exp_stats, + .populate = internal_bypass_exp_populate, + .purge = internal_bypass_exp_purge, + .resync = internal_bypass_exp_resync, + .new = internal_bypass_exp_event_new, + .upd = internal_bypass_exp_event_upd, + .del = internal_bypass_exp_event_del, + }, }; diff --git a/src/internal_cache.c b/src/internal_cache.c index 952327d..ba2d74b 100644 --- a/src/internal_cache.c +++ b/src/internal_cache.c @@ -32,12 +32,25 @@ static int internal_cache_init(void) dlog(LOG_ERR, "can't allocate memory for the internal cache"); return -1; } + + STATE(mode)->internal->exp.data = + cache_create("internal", CACHE_T_EXP, + STATE_SYNC(sync)->internal_cache_flags, + STATE_SYNC(sync)->internal_cache_extra, + &cache_sync_internal_exp_ops); + + if (!STATE(mode)->internal->exp.data) { + dlog(LOG_ERR, "can't allocate memory for the internal cache"); + return -1; + } + return 0; } static void internal_cache_close(void) { cache_destroy(STATE(mode)->internal->ct.data); + cache_destroy(STATE(mode)->internal->exp.data); } static void internal_cache_ct_dump(int fd, int type) @@ -203,6 +216,154 @@ static int internal_cache_ct_event_del(struct nf_conntrack *ct, int origin) return 1; } +static void internal_cache_exp_dump(int fd, int type) +{ + cache_dump(STATE(mode)->internal->exp.data, fd, type); +} + +static void internal_cache_exp_flush(void) +{ + cache_flush(STATE(mode)->internal->exp.data); +} + +static void internal_cache_exp_stats(int fd) +{ + cache_stats(STATE(mode)->internal->exp.data, fd); +} + +static void internal_cache_exp_stats_ext(int fd) +{ + cache_stats_extended(STATE(mode)->internal->exp.data, fd); +} + +static void internal_cache_exp_populate(struct nf_expect *exp) +{ + cache_update_force(STATE(mode)->internal->exp.data, exp); +} + +static int internal_cache_exp_purge_step(void *data1, void *data2) +{ + struct cache_object *obj = data2; + + STATE(get_retval) = 0; + nl_get_expect(STATE(get), obj->ptr); /* modifies STATE(get_reval) */ + if (!STATE(get_retval)) { + if (obj->status != C_OBJ_DEAD) { + cache_object_set_status(obj, C_OBJ_DEAD); + sync_send(obj, NET_T_STATE_EXP_DEL); + cache_object_put(obj); + } + } + + return 0; +} + +static void internal_cache_exp_purge(void) +{ + cache_iterate(STATE(mode)->internal->exp.data, NULL, + internal_cache_exp_purge_step); +} + +static int +internal_cache_exp_resync(enum nf_conntrack_msg_type type, + struct nf_expect *exp, void *data) +{ + struct cache_object *obj; + const struct nf_conntrack *master = + nfexp_get_attr(exp, ATTR_EXP_MASTER); + + if (!exp_filter_find(STATE(exp_filter), exp)) + return NFCT_CB_CONTINUE; + + if (ct_filter_conntrack(master, 1)) + return NFCT_CB_CONTINUE; + + obj = cache_update_force(STATE(mode)->internal->exp.data, exp); + if (obj == NULL) + return NFCT_CB_CONTINUE; + + switch (obj->status) { + case C_OBJ_NEW: + sync_send(obj, NET_T_STATE_EXP_NEW); + break; + case C_OBJ_ALIVE: + sync_send(obj, NET_T_STATE_EXP_UPD); + break; + } + return NFCT_CB_CONTINUE; +} + +static void internal_cache_exp_event_new(struct nf_expect *exp, int origin) +{ + struct cache_object *obj; + int id; + + /* this event has been triggered by a direct inject, skip */ + if (origin == CTD_ORIGIN_INJECT) + return; + + obj = cache_find(STATE(mode)->internal->exp.data, exp, &id); + if (obj == NULL) { +retry: + obj = cache_object_new(STATE(mode)->internal->exp.data, exp); + if (obj == NULL) + return; + if (cache_add(STATE(mode)->internal->exp.data, obj, id) == -1) { + cache_object_free(obj); + return; + } + /* only synchronize events that have been triggered by other + * processes or the kernel, but don't propagate events that + * have been triggered by conntrackd itself, eg. commits. */ + if (origin == CTD_ORIGIN_NOT_ME) + sync_send(obj, NET_T_STATE_EXP_NEW); + } else { + cache_del(STATE(mode)->internal->exp.data, obj); + cache_object_free(obj); + goto retry; + } +} + +static void internal_cache_exp_event_upd(struct nf_expect *exp, int origin) +{ + struct cache_object *obj; + + /* this event has been triggered by a direct inject, skip */ + if (origin == CTD_ORIGIN_INJECT) + return; + + obj = cache_update_force(STATE(mode)->internal->exp.data, exp); + if (obj == NULL) + return; + + if (origin == CTD_ORIGIN_NOT_ME) + sync_send(obj, NET_T_STATE_EXP_UPD); +} + +static int internal_cache_exp_event_del(struct nf_expect *exp, int origin) +{ + struct cache_object *obj; + int id; + + /* this event has been triggered by a direct inject, skip */ + if (origin == CTD_ORIGIN_INJECT) + return 0; + + /* we don't synchronize events for objects that are not in the cache */ + obj = cache_find(STATE(mode)->internal->exp.data, exp, &id); + if (obj == NULL) + return 0; + + if (obj->status != C_OBJ_DEAD) { + cache_object_set_status(obj, C_OBJ_DEAD); + if (origin == CTD_ORIGIN_NOT_ME) { + sync_send(obj, NET_T_STATE_EXP_DEL); + } + cache_object_put(obj); + } + return 1; +} + struct internal_handler internal_cache = { .flags = INTERNAL_F_POPULATE | INTERNAL_F_RESYNC, .init = internal_cache_init, @@ -219,4 +380,16 @@ struct internal_handler internal_cache = { .upd = internal_cache_ct_event_upd, .del = internal_cache_ct_event_del, }, + .exp = { + .dump = internal_cache_exp_dump, + .flush = internal_cache_exp_flush, + .stats = internal_cache_exp_stats, + .stats_ext = internal_cache_exp_stats_ext, + .populate = internal_cache_exp_populate, + .purge = internal_cache_exp_purge, + .resync = internal_cache_exp_resync, + .new = internal_cache_exp_event_new, + .upd = internal_cache_exp_event_upd, + .del = internal_cache_exp_event_del, + }, }; diff --git a/src/log.c b/src/log.c index 9fe5119..d4de111 100644 --- a/src/log.c +++ b/src/log.c @@ -145,6 +145,43 @@ void dlog_ct(FILE *fd, struct nf_conntrack *ct, unsigned int type) } } +void dlog_exp(FILE *fd, struct nf_expect *exp, unsigned int type) +{ + time_t t; + char buf[1024]; + char *tmp; + unsigned int flags = 0; + + buf[0]='\0'; + + switch(type) { + case NFCT_O_PLAIN: + t = time(NULL); + ctime_r(&t, buf); + tmp = buf + strlen(buf); + buf[strlen(buf)-1]='\t'; + break; + default: + return; + } + nfexp_snprintf(buf+strlen(buf), 1024-strlen(buf), exp, 0, type, flags); + + if (fd) { + snprintf(buf+strlen(buf), 1024-strlen(buf), "\n"); + fputs(buf, fd); + } + + if (fd == STATE(log)) { + /* error reporting */ + if (CONFIG(syslog_facility) != -1) + syslog(LOG_ERR, "%s", tmp); + } else if (fd == STATE(stats_log)) { + /* connection logging */ + if (CONFIG(stats).syslog_facility != -1) + syslog(LOG_INFO, "%s", tmp); + } +} + void close_log(void) { if (STATE(log) != NULL) diff --git a/src/main.c b/src/main.c index ebfc8b9..342ed45 100644 --- a/src/main.c +++ b/src/main.c @@ -1,5 +1,6 @@ /* - * (C) 2006-2007 by Pablo Neira Ayuso + * (C) 2006-2011 by Pablo Neira Ayuso + * (C) 2011 by Vyatta Inc. * * 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 @@ -38,14 +39,15 @@ static const char usage_daemon_commands[] = static const char usage_client_commands[] = "Client mode commands:\n" - " -c, commit external cache to conntrack table\n" + " -c [ct|expect], commit external cache to conntrack table\n" " -f [|internal|external], flush internal and external cache\n" - " -F, flush kernel conntrack table\n" - " -i, display content of the internal cache\n" - " -e, display the content of the external cache\n" + " -F [ct|expect], flush kernel conntrack table\n" + " -i [ct|expect], display content of the internal cache\n" + " -e [ct|expect], display the content of the external cache\n" " -k, kill conntrack daemon\n" - " -s [|network|cache|runtime|link|rsqueue|queue], dump statistics\n" - " -R, resync with kernel conntrack table\n" + " -s [|network|cache|runtime|link|rsqueue|queue|ct|expect], " + "dump statistics\n" + " -R [ct|expect], resync with kernel conntrack table\n" " -n, request resync with other node (only FT-FW and NOTRACK modes)\n" " -x, dump cache in XML format (requires -i or -e)\n" " -t, reset the kernel timeout (see PurgeTimeout clause)\n" @@ -89,6 +91,25 @@ set_operation_mode(int *current, int want, char *argv[]) } } +static int +set_action_by_table(int i, int argc, char *argv[], + int ct_action, int exp_action, int dfl_action, int *action) +{ + if (i+1 < argc && argv[i+1][0] != '-') { + if (strncmp(argv[i+1], "ct", strlen(argv[i+1])) == 0) { + *action = ct_action; + i++; + } else if (strncmp(argv[i+1], "expect", + strlen(argv[i+1])) == 0) { + *action = exp_action; + i++; + } + } else + *action = dfl_action; + + return i; +} + int main(int argc, char *argv[]) { int ret, i, action = -1; @@ -115,15 +136,23 @@ int main(int argc, char *argv[]) break; case 'c': set_operation_mode(&type, REQUEST, argv); - action = CT_COMMIT; + i = set_action_by_table(i, argc, argv, + CT_COMMIT, EXP_COMMIT, + ALL_COMMIT, &action); break; case 'i': set_operation_mode(&type, REQUEST, argv); - action = CT_DUMP_INTERNAL; + i = set_action_by_table(i, argc, argv, + CT_DUMP_INTERNAL, + EXP_DUMP_INTERNAL, + CT_DUMP_INTERNAL, &action); break; case 'e': set_operation_mode(&type, REQUEST, argv); - action = CT_DUMP_EXTERNAL; + i = set_action_by_table(i, argc, argv, + CT_DUMP_EXTERNAL, + EXP_DUMP_EXTERNAL, + CT_DUMP_EXTERNAL, &action); break; case 'C': if (++i < argc) { @@ -142,7 +171,10 @@ int main(int argc, char *argv[]) break; case 'F': set_operation_mode(&type, REQUEST, argv); - action = CT_FLUSH_MASTER; + i = set_action_by_table(i, argc, argv, + CT_FLUSH_MASTER, + EXP_FLUSH_MASTER, + ALL_FLUSH_MASTER, &action); break; case 'f': set_operation_mode(&type, REQUEST, argv); @@ -164,12 +196,15 @@ int main(int argc, char *argv[]) } } else { /* default to general flushing */ - action = CT_FLUSH_CACHE; + action = ALL_FLUSH_CACHE; } break; case 'R': set_operation_mode(&type, REQUEST, argv); - action = CT_RESYNC_MASTER; + i = set_action_by_table(i, argc, argv, + CT_RESYNC_MASTER, + EXP_RESYNC_MASTER, + ALL_RESYNC_MASTER, &action); break; case 'B': set_operation_mode(&type, REQUEST, argv); @@ -222,6 +257,14 @@ int main(int argc, char *argv[]) strlen(argv[i+1])) == 0) { action = STATS_QUEUE; i++; + } else if (strncmp(argv[i+1], "ct", + strlen(argv[i+1])) == 0) { + action = STATS; + i++; + } else if (strncmp(argv[i+1], "expect", + strlen(argv[i+1])) == 0) { + action = EXP_STATS; + i++; } else { fprintf(stderr, "ERROR: unknown " "parameter `%s' for " diff --git a/src/netlink.c b/src/netlink.c index 60274f3..fe979e3 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -1,5 +1,6 @@ /* - * (C) 2006 by Pablo Neira Ayuso + * (C) 2006-2011 by Pablo Neira Ayuso + * (C) 2011 by Vyatta Inc. * * 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 @@ -32,7 +33,7 @@ struct nfct_handle *nl_init_event_handler(void) { struct nfct_handle *h; - h = nfct_open(CONNTRACK, NFCT_ALL_CT_GROUPS); + h = nfct_open(CONFIG(netlink).subsys_id, CONFIG(netlink).groups); if (h == NULL) return NULL; @@ -301,3 +302,61 @@ int nl_destroy_conntrack(struct nfct_handle *h, const struct nf_conntrack *ct) { return nfct_query(h, NFCT_Q_DESTROY, ct); } + +int nl_create_expect(struct nfct_handle *h, const struct nf_expect *orig, + int timeout) +{ + int ret; + struct nf_expect *exp; + + exp = nfexp_clone(orig); + if (exp == NULL) + return -1; + + if (timeout > 0) + nfexp_set_attr_u32(exp, ATTR_EXP_TIMEOUT, timeout); + + ret = nfexp_query(h, NFCT_Q_CREATE, exp); + nfexp_destroy(exp); + + return ret; +} + +int nl_destroy_expect(struct nfct_handle *h, const struct nf_expect *exp) +{ + return nfexp_query(h, NFCT_Q_DESTROY, exp); +} + +/* if the handle has no callback, check for existence, otherwise, update */ +int nl_get_expect(struct nfct_handle *h, const struct nf_expect *exp) +{ + int ret = 1; + struct nf_expect *tmp; + + /* XXX: we only need the expectation, not the mask and the master. */ + tmp = nfexp_clone(exp); + if (tmp == NULL) + return -1; + + if (nfexp_query(h, NFCT_Q_GET, tmp) == -1) + ret = (errno == ENOENT) ? 0 : -1; + + nfexp_destroy(tmp); + return ret; +} + +int nl_dump_expect_table(struct nfct_handle *h) +{ + return nfexp_query(h, NFCT_Q_DUMP, &CONFIG(family)); +} + +int nl_flush_expect_table(struct nfct_handle *h) +{ + return nfexp_query(h, NFCT_Q_FLUSH, &CONFIG(family)); +} + +int nl_send_expect_resync(struct nfct_handle *h) +{ + int family = CONFIG(family); + return nfexp_send(h, NFCT_Q_DUMP, &family); +} diff --git a/src/network.c b/src/network.c index cadc466..13db37c 100644 --- a/src/network.c +++ b/src/network.c @@ -126,6 +126,11 @@ static int status2type[CACHE_T_MAX][C_OBJ_MAX] = { [C_OBJ_ALIVE] = NET_T_STATE_CT_UPD, [C_OBJ_DEAD] = NET_T_STATE_CT_DEL, }, + [CACHE_T_EXP] = { + [C_OBJ_NEW] = NET_T_STATE_EXP_NEW, + [C_OBJ_ALIVE] = NET_T_STATE_EXP_UPD, + [C_OBJ_DEAD] = NET_T_STATE_EXP_DEL, + }, }; int object_status_to_network_type(struct cache_object *obj) diff --git a/src/parse.c b/src/parse.c index 0718128..81e9c6b 100644 --- a/src/parse.c +++ b/src/parse.c @@ -248,3 +248,195 @@ int msg2ct(struct nf_conntrack *ct, struct nethdr *net, size_t remain) return 0; } + +static void exp_parse_ct_group(void *ct, int attr, void *data); +static void exp_parse_ct_u8(void *ct, int attr, void *data); +static void exp_parse_u32(void *exp, int attr, void *data); + +static struct exp_parser { + void (*parse)(void *obj, int attr, void *data); + int exp_attr; + int ct_attr; + int size; +} exp_h[NTA_EXP_MAX] = { + [NTA_EXP_MASTER_IPV4] = { + .parse = exp_parse_ct_group, + .exp_attr = ATTR_EXP_MASTER, + .ct_attr = ATTR_GRP_ORIG_IPV4, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_ipv4)), + }, + [NTA_EXP_MASTER_IPV6] = { + .parse = exp_parse_ct_group, + .exp_attr = ATTR_EXP_MASTER, + .ct_attr = ATTR_GRP_ORIG_IPV6, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_ipv6)), + }, + [NTA_EXP_MASTER_L4PROTO] = { + .parse = exp_parse_ct_u8, + .exp_attr = ATTR_EXP_MASTER, + .ct_attr = ATTR_L4PROTO, + .size = NTA_SIZE(sizeof(uint8_t)), + }, + [NTA_EXP_MASTER_PORT] = { + .parse = exp_parse_ct_group, + .exp_attr = ATTR_EXP_MASTER, + .ct_attr = ATTR_GRP_ORIG_PORT, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_port)), + }, + [NTA_EXP_EXPECT_IPV4] = { + .parse = exp_parse_ct_group, + .exp_attr = ATTR_EXP_EXPECTED, + .ct_attr = ATTR_GRP_ORIG_IPV4, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_ipv4)), + }, + [NTA_EXP_EXPECT_IPV6] = { + .parse = exp_parse_ct_group, + .exp_attr = ATTR_EXP_EXPECTED, + .ct_attr = ATTR_GRP_ORIG_IPV6, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_ipv6)), + }, + [NTA_EXP_EXPECT_L4PROTO] = { + .parse = exp_parse_ct_u8, + .exp_attr = ATTR_EXP_EXPECTED, + .ct_attr = ATTR_L4PROTO, + .size = NTA_SIZE(sizeof(uint8_t)), + }, + [NTA_EXP_EXPECT_PORT] = { + .parse = exp_parse_ct_group, + .exp_attr = ATTR_EXP_EXPECTED, + .ct_attr = ATTR_GRP_ORIG_PORT, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_port)), + }, + [NTA_EXP_MASK_IPV4] = { + .parse = exp_parse_ct_group, + .exp_attr = ATTR_EXP_MASK, + .ct_attr = ATTR_GRP_ORIG_IPV4, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_ipv4)), + }, + [NTA_EXP_MASK_IPV6] = { + .parse = exp_parse_ct_group, + .exp_attr = ATTR_EXP_MASK, + .ct_attr = ATTR_GRP_ORIG_IPV6, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_ipv6)), + }, + [NTA_EXP_MASK_L4PROTO] = { + .parse = exp_parse_ct_u8, + .exp_attr = ATTR_EXP_MASK, + .ct_attr = ATTR_L4PROTO, + .size = NTA_SIZE(sizeof(uint8_t)), + }, + [NTA_EXP_MASK_PORT] = { + .parse = exp_parse_ct_group, + .exp_attr = ATTR_EXP_MASK, + .ct_attr = ATTR_GRP_ORIG_PORT, + .size = NTA_SIZE(sizeof(struct nfct_attr_grp_port)), + }, + [NTA_EXP_TIMEOUT] = { + .parse = exp_parse_u32, + .exp_attr = ATTR_EXP_TIMEOUT, + .size = NTA_SIZE(sizeof(uint32_t)), + }, + [NTA_EXP_FLAGS] = { + .parse = exp_parse_u32, + .exp_attr = ATTR_EXP_FLAGS, + .size = NTA_SIZE(sizeof(uint32_t)), + }, +}; + +static void exp_parse_ct_group(void *ct, int attr, void *data) +{ + nfct_set_attr_grp(ct, exp_h[attr].ct_attr, data); +} + +static void exp_parse_ct_u8(void *ct, int attr, void *data) +{ + uint8_t *value = (uint8_t *) data; + nfct_set_attr_u8(ct, exp_h[attr].ct_attr, *value); +} + +static void exp_parse_u32(void *exp, int attr, void *data) +{ + uint32_t *value = (uint32_t *) data; + nfexp_set_attr_u32(exp, exp_h[attr].exp_attr, ntohl(*value)); +} + +int msg2exp(struct nf_expect *exp, struct nethdr *net, size_t remain) +{ + int len; + struct netattr *attr; + struct nf_conntrack *master, *expected, *mask; + + if (remain < net->len) + return -1; + + len = net->len - NETHDR_SIZ; + attr = NETHDR_DATA(net); + + master = nfct_new(); + if (master == NULL) + goto err_master; + + expected = nfct_new(); + if (expected == NULL) + goto err_expected; + + mask = nfct_new(); + if (mask == NULL) + goto err_mask; + + while (len > ssizeof(struct netattr)) { + ATTR_NETWORK2HOST(attr); + if (attr->nta_len > len) + goto err; + if (attr->nta_attr > NTA_MAX) + goto err; + if (attr->nta_len != exp_h[attr->nta_attr].size) + goto err; + if (exp_h[attr->nta_attr].parse == NULL) { + attr = NTA_NEXT(attr, len); + continue; + } + switch(exp_h[attr->nta_attr].exp_attr) { + case ATTR_EXP_MASTER: + exp_h[attr->nta_attr].parse(master, attr->nta_attr, + NTA_DATA(attr)); + case ATTR_EXP_EXPECTED: + exp_h[attr->nta_attr].parse(expected, attr->nta_attr, + NTA_DATA(attr)); + case ATTR_EXP_MASK: + exp_h[attr->nta_attr].parse(mask, attr->nta_attr, + NTA_DATA(attr)); + break; + case ATTR_EXP_TIMEOUT: + case ATTR_EXP_FLAGS: + exp_h[attr->nta_attr].parse(exp, attr->nta_attr, + NTA_DATA(attr)); + break; + } + attr = NTA_NEXT(attr, len); + } + + nfexp_set_attr(exp, ATTR_EXP_MASTER, master); + nfexp_set_attr(exp, ATTR_EXP_EXPECTED, expected); + nfexp_set_attr(exp, ATTR_EXP_MASK, mask); + + /* We can release the conntrack objects at this point because the + * setter makes a copy of them. This is not efficient, it would be + * better to save that extra copy but this is how the library works. + * I'm sorry, I cannot change it without breaking backward + * compatibility. Probably it is a good idea to think of adding new + * interfaces in the near future to get it better. */ + nfct_destroy(mask); + nfct_destroy(expected); + nfct_destroy(master); + + return 0; +err: + nfct_destroy(mask); +err_mask: + nfct_destroy(expected); +err_expected: + nfct_destroy(master); +err_master: + return -1; +} diff --git a/src/read_config_lex.l b/src/read_config_lex.l index be6bf8b..01fe4fc 100644 --- a/src/read_config_lex.l +++ b/src/read_config_lex.l @@ -140,6 +140,7 @@ notrack [N|n][O|o][T|t][R|r][A|a][C|c][K|k] "DisableExternalCache" { return T_DISABLE_EXTERNAL_CACHE; } "Options" { return T_OPTIONS; } "TCPWindowTracking" { return T_TCP_WINDOW_TRACKING; } +"ExpectationSync" { return T_EXPECT_SYNC; } "ErrorQueueLength" { return T_ERROR_QUEUE_LENGTH; } {is_on} { return T_ON; } diff --git a/src/read_config_yy.y b/src/read_config_yy.y index 68a83f7..b22784c 100644 --- a/src/read_config_yy.y +++ b/src/read_config_yy.y @@ -73,7 +73,7 @@ static void __max_dedicated_links_reached(void); %token T_NETLINK_OVERRUN_RESYNC T_NICE T_IPV4_DEST_ADDR T_IPV6_DEST_ADDR %token T_SCHEDULER T_TYPE T_PRIO T_NETLINK_EVENTS_RELIABLE %token T_DISABLE_INTERNAL_CACHE T_DISABLE_EXTERNAL_CACHE T_ERROR_QUEUE_LENGTH -%token T_OPTIONS T_TCP_WINDOW_TRACKING +%token T_OPTIONS T_TCP_WINDOW_TRACKING T_EXPECT_SYNC %token T_IP T_PATH_VAL %token T_NUMBER @@ -828,6 +828,46 @@ option: T_TCP_WINDOW_TRACKING T_OFF CONFIG(sync).tcp_window_tracking = 0; }; +option: T_EXPECT_SYNC T_ON +{ + CONFIG(flags) |= CTD_EXPECT; + CONFIG(netlink).subsys_id = NFNL_SUBSYS_NONE; + CONFIG(netlink).groups = NF_NETLINK_CONNTRACK_NEW | + NF_NETLINK_CONNTRACK_UPDATE | + NF_NETLINK_CONNTRACK_DESTROY | + NF_NETLINK_CONNTRACK_EXP_NEW | + NF_NETLINK_CONNTRACK_EXP_UPDATE | + NF_NETLINK_CONNTRACK_EXP_DESTROY; +}; + +option: T_EXPECT_SYNC T_OFF +{ + CONFIG(netlink).subsys_id = NFNL_SUBSYS_CTNETLINK; + CONFIG(netlink).groups = NF_NETLINK_CONNTRACK_NEW | + NF_NETLINK_CONNTRACK_UPDATE | + NF_NETLINK_CONNTRACK_DESTROY; +}; + +option: T_EXPECT_SYNC '{' expect_list '}' +{ + CONFIG(flags) |= CTD_EXPECT; + CONFIG(netlink).subsys_id = NFNL_SUBSYS_NONE; + CONFIG(netlink).groups = NF_NETLINK_CONNTRACK_NEW | + NF_NETLINK_CONNTRACK_UPDATE | + NF_NETLINK_CONNTRACK_DESTROY | + NF_NETLINK_CONNTRACK_EXP_NEW | + NF_NETLINK_CONNTRACK_EXP_UPDATE | + NF_NETLINK_CONNTRACK_EXP_DESTROY; +}; + +expect_list: + | expect_list expect_item ; + +expect_item: T_STRING +{ + exp_filter_add(STATE(exp_filter), $1); +} + sync_mode_alarm: T_SYNC_MODE T_ALARM '{' sync_mode_alarm_list '}' { conf.flags |= CTD_SYNC_ALARM; @@ -1598,6 +1638,7 @@ init_config(char *filename) /* Zero may be a valid facility */ CONFIG(syslog_facility) = -1; CONFIG(stats).syslog_facility = -1; + CONFIG(netlink).subsys_id = -1; yyrestart(fp); yyparse(); @@ -1646,5 +1687,12 @@ init_config(char *filename) if (CONFIG(channelc).error_queue_length == 0) CONFIG(channelc).error_queue_length = 128; + if (CONFIG(netlink).subsys_id == -1) { + CONFIG(netlink).subsys_id = NFNL_SUBSYS_CTNETLINK; + CONFIG(netlink).groups = NF_NETLINK_CONNTRACK_NEW | + NF_NETLINK_CONNTRACK_UPDATE | + NF_NETLINK_CONNTRACK_DESTROY; + } + return 0; } diff --git a/src/run.c b/src/run.c index c21db2e..26c1783 100644 --- a/src/run.c +++ b/src/run.c @@ -187,6 +187,62 @@ static void dump_stats_runtime(int fd) send(fd, buf, size, 0); } +static void local_flush_master(void) +{ + STATE(stats).nl_kernel_table_flush++; + dlog(LOG_NOTICE, "flushing kernel conntrack table"); + + /* fork a child process that performs the flush operation, + * meanwhile the parent process handles events. */ + if (fork_process_new(CTD_PROC_FLUSH, CTD_PROC_F_EXCL, + NULL, NULL) == 0) { + nl_flush_conntrack_table(STATE(flush)); + exit(EXIT_SUCCESS); + } +} + +static void local_resync_master(void) +{ + if (STATE(mode)->internal->flags & INTERNAL_F_POPULATE) { + STATE(stats).nl_kernel_table_resync++; + dlog(LOG_NOTICE, "resync with master conntrack table"); + nl_dump_conntrack_table(STATE(dump)); + } else { + dlog(LOG_NOTICE, "resync is unsupported in this mode"); + } +} + +static void local_exp_flush_master(void) +{ + if (!(CONFIG(flags) & CTD_EXPECT)) + return; + + STATE(stats).nl_kernel_table_flush++; + dlog(LOG_NOTICE, "flushing kernel expect table"); + + /* fork a child process that performs the flush operation, + * meanwhile the parent process handles events. */ + if (fork_process_new(CTD_PROC_FLUSH, CTD_PROC_F_EXCL, + NULL, NULL) == 0) { + nl_flush_expect_table(STATE(flush)); + exit(EXIT_SUCCESS); + } +} + +static void local_exp_resync_master(void) +{ + if (!(CONFIG(flags) & CTD_EXPECT)) + return; + + if (STATE(mode)->internal->flags & INTERNAL_F_POPULATE) { + STATE(stats).nl_kernel_table_resync++; + dlog(LOG_NOTICE, "resync with master expect table"); + nl_dump_expect_table(STATE(dump)); + } else { + dlog(LOG_NOTICE, "resync is unsupported in this mode"); + } +} + static int local_handler(int fd, void *data) { int ret = LOCAL_RET_OK; @@ -198,25 +254,24 @@ static int local_handler(int fd, void *data) } switch(type) { case CT_FLUSH_MASTER: - STATE(stats).nl_kernel_table_flush++; - dlog(LOG_NOTICE, "flushing kernel conntrack table"); - - /* fork a child process that performs the flush operation, - * meanwhile the parent process handles events. */ - if (fork_process_new(CTD_PROC_FLUSH, CTD_PROC_F_EXCL, - NULL, NULL) == 0) { - nl_flush_conntrack_table(STATE(flush)); - exit(EXIT_SUCCESS); - } + local_flush_master(); break; case CT_RESYNC_MASTER: - if (STATE(mode)->internal->flags & INTERNAL_F_POPULATE) { - STATE(stats).nl_kernel_table_resync++; - dlog(LOG_NOTICE, "resync with master table"); - nl_dump_conntrack_table(STATE(dump)); - } else { - dlog(LOG_NOTICE, "resync is unsupported in this mode"); - } + local_resync_master(); + break; + case EXP_FLUSH_MASTER: + local_exp_flush_master(); + break; + case EXP_RESYNC_MASTER: + local_exp_resync_master(); + break; + case ALL_FLUSH_MASTER: + local_flush_master(); + local_exp_flush_master(); + break; + case ALL_RESYNC_MASTER: + local_resync_master(); + local_exp_resync_master(); break; case STATS_RUNTIME: dump_stats_runtime(fd); @@ -245,7 +300,11 @@ static void do_polling_alarm(struct alarm_block *a, void *data) if (STATE(mode)->internal->ct.purge) STATE(mode)->internal->ct.purge(); + if (STATE(mode)->internal->exp.purge) + STATE(mode)->internal->exp.purge(); + nl_send_resync(STATE(resync)); + nl_send_expect_resync(STATE(resync)); add_alarm(&STATE(polling_alarm), CONFIG(poll_kernel_secs), 0); } @@ -290,6 +349,49 @@ out: return NFCT_CB_CONTINUE; } +static int exp_event_handler(const struct nlmsghdr *nlh, + enum nf_conntrack_msg_type type, + struct nf_expect *exp, + void *data) +{ + int origin_type; + const struct nf_conntrack *master = + nfexp_get_attr(exp, ATTR_EXP_MASTER); + + STATE(stats).nl_events_received++; + + if (!exp_filter_find(STATE(exp_filter), exp)) { + STATE(stats).nl_events_filtered++; + goto out; + } + if (ct_filter_conntrack(master, 1)) + return NFCT_CB_CONTINUE; + + origin_type = origin_find(nlh); + + switch(type) { + case NFCT_T_NEW: + STATE(mode)->internal->exp.new(exp, origin_type); + break; + case NFCT_T_UPDATE: + STATE(mode)->internal->exp.upd(exp, origin_type); + break; + case NFCT_T_DESTROY: + STATE(mode)->internal->exp.del(exp, origin_type); + break; + default: + STATE(stats).nl_events_unknown_type++; + break; + } + +out: + /* we reset the iteration limiter in the main select loop. */ + if (STATE(event_iterations_limit)-- <= 0) + return NFCT_CB_STOP; + else + return NFCT_CB_CONTINUE; +} + static int dump_handler(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data) @@ -308,6 +410,29 @@ static int dump_handler(enum nf_conntrack_msg_type type, return NFCT_CB_CONTINUE; } +static int exp_dump_handler(enum nf_conntrack_msg_type type, + struct nf_expect *exp, void *data) +{ + const struct nf_conntrack *master = + nfexp_get_attr(exp, ATTR_EXP_MASTER); + + if (!exp_filter_find(STATE(exp_filter), exp)) + return NFCT_CB_CONTINUE; + + if (ct_filter_conntrack(master, 1)) + return NFCT_CB_CONTINUE; + + switch(type) { + case NFCT_T_UPDATE: + STATE(mode)->internal->exp.populate(exp); + break; + default: + STATE(stats).nl_dump_unknown_type++; + break; + } + return NFCT_CB_CONTINUE; +} + static int get_handler(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data) @@ -319,6 +444,22 @@ static int get_handler(enum nf_conntrack_msg_type type, return NFCT_CB_CONTINUE; } +static int exp_get_handler(enum nf_conntrack_msg_type type, + struct nf_expect *exp, void *data) +{ + const struct nf_conntrack *master = + nfexp_get_attr(exp, ATTR_EXP_MASTER); + + if (!exp_filter_find(STATE(exp_filter), exp)) + return NFCT_CB_CONTINUE; + + if (ct_filter_conntrack(master, 1)) + return NFCT_CB_CONTINUE; + + STATE(get_retval) = 1; + return NFCT_CB_CONTINUE; +} + int init(void) { @@ -355,7 +496,7 @@ init(void) register_fd(STATE(local).fd, STATE(fds)); /* resynchronize (like 'dump' socket) but it also purges old entries */ - STATE(resync) = nfct_open(CONNTRACK, 0); + STATE(resync) = nfct_open(CONFIG(netlink).subsys_id, 0); if (STATE(resync)== NULL) { dlog(LOG_ERR, "can't open netlink handler: %s", strerror(errno)); @@ -370,7 +511,7 @@ init(void) fcntl(nfct_fd(STATE(resync)), F_SETFL, O_NONBLOCK); if (STATE(mode)->internal->flags & INTERNAL_F_POPULATE) { - STATE(dump) = nfct_open(CONNTRACK, 0); + STATE(dump) = nfct_open(CONFIG(netlink).subsys_id, 0); if (STATE(dump) == NULL) { dlog(LOG_ERR, "can't open netlink handler: %s", strerror(errno)); @@ -380,13 +521,26 @@ init(void) nfct_callback_register(STATE(dump), NFCT_T_ALL, dump_handler, NULL); + if (CONFIG(flags) & CTD_EXPECT) { + nfexp_callback_register(STATE(dump), NFCT_T_ALL, + exp_dump_handler, NULL); + } + if (nl_dump_conntrack_table(STATE(dump)) == -1) { dlog(LOG_ERR, "can't get kernel conntrack table"); return -1; } + + if (CONFIG(flags) & CTD_EXPECT) { + if (nl_dump_expect_table(STATE(dump)) == -1) { + dlog(LOG_ERR, "can't get kernel " + "expect table"); + return -1; + } + } } - STATE(get) = nfct_open(CONNTRACK, 0); + STATE(get) = nfct_open(CONFIG(netlink).subsys_id, 0); if (STATE(get) == NULL) { dlog(LOG_ERR, "can't open netlink handler: %s", strerror(errno)); @@ -395,7 +549,12 @@ init(void) } nfct_callback_register(STATE(get), NFCT_T_ALL, get_handler, NULL); - STATE(flush) = nfct_open(CONNTRACK, 0); + if (CONFIG(flags) & CTD_EXPECT) { + nfexp_callback_register(STATE(get), NFCT_T_ALL, + exp_get_handler, NULL); + } + + STATE(flush) = nfct_open(CONFIG(netlink).subsys_id, 0); if (STATE(flush) == NULL) { dlog(LOG_ERR, "cannot open flusher handler"); return -1; @@ -426,6 +585,11 @@ init(void) } nfct_callback_register2(STATE(event), NFCT_T_ALL, event_handler, NULL); + + if (CONFIG(flags) & CTD_EXPECT) { + nfexp_callback_register2(STATE(event), NFCT_T_ALL, + exp_event_handler, NULL); + } register_fd(nfct_fd(STATE(event)), STATE(fds)); } diff --git a/src/sync-ftfw.c b/src/sync-ftfw.c index fa76c0c..1bc2d9f 100644 --- a/src/sync-ftfw.c +++ b/src/sync-ftfw.c @@ -231,6 +231,8 @@ static int ftfw_local(int fd, int type, void *data) dlog(LOG_NOTICE, "sending bulk update"); cache_iterate(STATE(mode)->internal->ct.data, NULL, do_cache_to_tx); + cache_iterate(STATE(mode)->internal->exp.data, + NULL, do_cache_to_tx); break; case STATS_RSQUEUE: ftfw_local_queue(fd); @@ -350,7 +352,10 @@ static int digest_msg(const struct nethdr *net) } else if (IS_RESYNC(net)) { dp("RESYNC ALL\n"); - cache_iterate(STATE(mode)->internal->ct.data, NULL, do_cache_to_tx); + cache_iterate(STATE(mode)->internal->ct.data, NULL, + do_cache_to_tx); + cache_iterate(STATE(mode)->internal->exp.data, NULL, + do_cache_to_tx); return MSG_CTL; } else if (IS_ALIVE(net)) diff --git a/src/sync-mode.c b/src/sync-mode.c index fa522c7..2505631 100644 --- a/src/sync-mode.c +++ b/src/sync-mode.c @@ -59,10 +59,29 @@ static struct nf_conntrack *msg2ct_alloc(struct nethdr *net, size_t remain) return ct; } +static struct nf_expect *msg2exp_alloc(struct nethdr *net, size_t remain) +{ + struct nf_expect *exp; + + /* TODO: add stats on ENOMEM errors in the future. */ + exp = nfexp_new(); + if (exp == NULL) + return NULL; + + if (msg2exp(exp, net, remain) == -1) { + STATE_SYNC(error).msg_rcv_malformed++; + STATE_SYNC(error).msg_rcv_bad_payload++; + nfexp_destroy(exp); + return NULL; + } + return exp; +} + static void do_channel_handler_step(int i, struct nethdr *net, size_t remain) { - struct nf_conntrack *ct; + struct nf_conntrack *ct = NULL; + struct nf_expect *exp = NULL; if (net->version != CONNTRACKD_PROTOCOL_VERSION) { STATE_SYNC(error).msg_rcv_malformed++; @@ -112,12 +131,33 @@ do_channel_handler_step(int i, struct nethdr *net, size_t remain) return; STATE_SYNC(external)->ct.del(ct); break; + case NET_T_STATE_EXP_NEW: + exp = msg2exp_alloc(net, remain); + if (exp == NULL) + return; + STATE_SYNC(external)->exp.new(exp); + break; + case NET_T_STATE_EXP_UPD: + exp = msg2exp_alloc(net, remain); + if (exp == NULL) + return; + STATE_SYNC(external)->exp.upd(exp); + break; + case NET_T_STATE_EXP_DEL: + exp = msg2exp_alloc(net, remain); + if (exp == NULL) + return; + STATE_SYNC(external)->exp.del(exp); + break; default: STATE_SYNC(error).msg_rcv_malformed++; STATE_SYNC(error).msg_rcv_bad_type++; break; } - nfct_destroy(ct); + if (ct != NULL) + nfct_destroy(ct); + if (exp != NULL) + nfexp_destroy(exp); } static char __net[65536]; /* XXX: maximum MTU for IPv4 */ @@ -351,7 +391,7 @@ static int init_sync(void) STATE(fds)) == -1) return -1; - STATE_SYNC(commit).h = nfct_open(CONNTRACK, 0); + STATE_SYNC(commit).h = nfct_open(CONFIG(netlink).subsys_id, 0); if (STATE_SYNC(commit).h == NULL) { dlog(LOG_ERR, "can't create handler to commit"); return -1; @@ -402,8 +442,30 @@ static void run_sync(fd_set *readfds) interface_handler(); if (FD_ISSET(get_read_evfd(STATE_SYNC(commit).evfd), readfds)) { + int ret; + read_evfd(STATE_SYNC(commit).evfd); - STATE_SYNC(external)->ct.commit(STATE_SYNC(commit).h, 0); + + ret = STATE_SYNC(commit).rq[0].cb(STATE_SYNC(commit).h, 0); + if (ret == 0) { + /* we still have things in the callback queue. */ + if (STATE_SYNC(commit).rq[1].cb) { + int fd = STATE_SYNC(commit).clientfd; + + STATE_SYNC(commit).rq[0].cb = + STATE_SYNC(commit).rq[1].cb; + + STATE_SYNC(commit).rq[1].cb = NULL; + + STATE_SYNC(commit).clientfd = -1; + STATE_SYNC(commit).rq[0].cb( + STATE_SYNC(commit).h, fd); + } else { + /* Close the client socket now, we're done. */ + close(STATE_SYNC(commit).clientfd); + STATE_SYNC(commit).clientfd = -1; + } + } } /* flush pending messages */ @@ -480,6 +542,27 @@ static void dump_stats_sync_extended(int fd) send(fd, buf, size, 0); } +static int local_commit(int fd) +{ + int ret; + + /* delete the reset alarm if any before committing */ + del_alarm(&STATE_SYNC(reset_cache_alarm)); + + ret = STATE_SYNC(commit).rq[0].cb(STATE_SYNC(commit).h, fd); + if (ret == -1) { + dlog(LOG_NOTICE, "commit already in progress, skipping"); + ret = LOCAL_RET_OK; + } else if (ret == 0) { + /* we've finished the commit. */ + ret = LOCAL_RET_OK; + } else { + /* Keep open the client, we want synchronous commit. */ + ret = LOCAL_RET_STOLEN; + } + return ret; +} + /* handler for requests coming via UNIX socket */ static int local_handler_sync(int fd, int type, void *data) { @@ -511,19 +594,10 @@ static int local_handler_sync(int fd, int type, void *data) } break; case CT_COMMIT: - /* delete the reset alarm if any before committing */ - del_alarm(&STATE_SYNC(reset_cache_alarm)); - - dlog(LOG_NOTICE, "committing external cache"); - ret = STATE_SYNC(external)->ct.commit(STATE_SYNC(commit).h, fd); - if (ret == 0) { - dlog(LOG_NOTICE, "commit already in progress, " - "skipping"); - ret = LOCAL_RET_OK; - } else { - /* Keep open the client, we want synchronous commit. */ - ret = LOCAL_RET_STOLEN; - } + dlog(LOG_NOTICE, "committing conntrack cache"); + STATE_SYNC(commit).rq[0].cb = STATE_SYNC(external)->ct.commit; + STATE_SYNC(commit).rq[1].cb = NULL; + ret = local_commit(fd); break; case RESET_TIMERS: if (!alarm_pending(&STATE_SYNC(reset_cache_alarm))) { @@ -575,6 +649,63 @@ static int local_handler_sync(int fd, int type, void *data) case STATS_QUEUE: queue_stats_show(fd); break; + case EXP_STATS: + if (!(CONFIG(flags) & CTD_EXPECT)) + break; + + STATE(mode)->internal->exp.stats(fd); + STATE_SYNC(external)->exp.stats(fd); + dump_traffic_stats(fd); + multichannel_stats(STATE_SYNC(channel), fd); + dump_stats_sync(fd); + break; + case EXP_DUMP_INTERNAL: + if (!(CONFIG(flags) & CTD_EXPECT)) + break; + + if (fork_process_new(CTD_PROC_ANY, 0, NULL, NULL) == 0) { + STATE(mode)->internal->exp.dump(fd, NFCT_O_PLAIN); + exit(EXIT_SUCCESS); + } + break; + case EXP_DUMP_EXTERNAL: + if (!(CONFIG(flags) & CTD_EXPECT)) + break; + + if (fork_process_new(CTD_PROC_ANY, 0, NULL, NULL) == 0) { + STATE_SYNC(external)->exp.dump(fd, NFCT_O_PLAIN); + exit(EXIT_SUCCESS); + } + break; + case EXP_COMMIT: + if (!(CONFIG(flags) & CTD_EXPECT)) + break; + + dlog(LOG_NOTICE, "committing expectation cache"); + STATE_SYNC(commit).rq[0].cb = STATE_SYNC(external)->exp.commit; + STATE_SYNC(commit).rq[1].cb = NULL; + local_commit(fd); + break; + case ALL_FLUSH_CACHE: + dlog(LOG_NOTICE, "flushing caches"); + STATE(mode)->internal->ct.flush(); + STATE_SYNC(external)->ct.flush(); + if (CONFIG(flags) & CTD_EXPECT) { + STATE(mode)->internal->exp.flush(); + STATE_SYNC(external)->exp.flush(); + } + break; + case ALL_COMMIT: + dlog(LOG_NOTICE, "committing all external caches"); + STATE_SYNC(commit).rq[0].cb = STATE_SYNC(external)->ct.commit; + if (CONFIG(flags) & CTD_EXPECT) { + STATE_SYNC(commit).rq[1].cb = + STATE_SYNC(external)->exp.commit; + } else { + STATE_SYNC(commit).rq[1].cb = NULL; + } + local_commit(fd); + break; default: if (STATE_SYNC(sync)->local) ret = STATE_SYNC(sync)->local(fd, type, data); diff --git a/src/sync-notrack.c b/src/sync-notrack.c index 06ad1f0..a7df4e7 100644 --- a/src/sync-notrack.c +++ b/src/sync-notrack.c @@ -102,7 +102,7 @@ static void kernel_resync(void) u_int32_t family = AF_UNSPEC; int ret; - h = nfct_open(CONNTRACK, 0); + h = nfct_open(CONFIG(netlink).subsys_id, 0); if (h == NULL) { dlog(LOG_ERR, "can't allocate memory for the internal cache"); return; @@ -131,6 +131,8 @@ static int notrack_local(int fd, int type, void *data) } else { cache_iterate(STATE(mode)->internal->ct.data, NULL, do_cache_to_tx); + cache_iterate(STATE(mode)->internal->exp.data, + NULL, do_cache_to_tx); } break; default: @@ -152,6 +154,8 @@ static int digest_msg(const struct nethdr *net) } else { cache_iterate(STATE(mode)->internal->ct.data, NULL, do_cache_to_tx); + cache_iterate(STATE(mode)->internal->exp.data, + NULL, do_cache_to_tx); } return MSG_CTL; } -- cgit v1.2.3