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 --- include/conntrack.h | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 include/conntrack.h (limited to 'include/conntrack.h') 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 -- 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 'include/conntrack.h') 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 'include/conntrack.h') 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 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 'include/conntrack.h') 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 'include/conntrack.h') 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 ba2a63e1b8e18e0d1f383af50d3d40c2eb785d3e 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 19:57:50 +0000 Subject: See ChangeLog --- ChangeLog | 3 +++ extensions/libct_proto_sctp.c | 10 ++++++++-- extensions/libct_proto_tcp.c | 10 ++++++++-- include/conntrack.h | 2 +- 4 files changed, 20 insertions(+), 5 deletions(-) (limited to 'include/conntrack.h') diff --git a/ChangeLog b/ChangeLog index 7ce1169..51bdeb5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,9 @@ 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 Bumped version to 0.96 2005-11-01 diff --git a/extensions/libct_proto_sctp.c b/extensions/libct_proto_sctp.c index 2b1a337..5e96391 100644 --- a/extensions/libct_proto_sctp.c +++ b/extensions/libct_proto_sctp.c @@ -108,6 +108,7 @@ int parse_options(char c, char *argv[], printf("doh?\n"); return 0; } + *flags |= STATE; } break; } @@ -118,19 +119,24 @@ int final_check(unsigned int flags, struct nfct_tuple *orig, struct nfct_tuple *reply) { + int ret = 0; + 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; + ret = 1; } 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; + ret = 1; } if ((flags & (ORIG_SPORT|ORIG_DPORT)) && ((flags & (REPL_SPORT|REPL_DPORT)))) + ret = 1; + + if (ret & (flags & STATE)) return 1; return 0; diff --git a/extensions/libct_proto_tcp.c b/extensions/libct_proto_tcp.c index 4aa6587..7c1e605 100644 --- a/extensions/libct_proto_tcp.c +++ b/extensions/libct_proto_tcp.c @@ -131,6 +131,7 @@ int parse_options(char c, char *argv[], printf("doh?\n"); return 0; } + *flags |= STATE; } break; } @@ -141,19 +142,24 @@ int final_check(unsigned int flags, struct nfct_tuple *orig, struct nfct_tuple *reply) { + int ret = 0; + 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; + ret = 1; } 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; + ret = 1; } if ((flags & (ORIG_SPORT|ORIG_DPORT)) && ((flags & (REPL_SPORT|REPL_DPORT)))) + ret = 1; + + if (ret && (flags & STATE)) return 1; return 0; diff --git a/include/conntrack.h b/include/conntrack.h index 58a9170..efe4417 100644 --- a/include/conntrack.h +++ b/include/conntrack.h @@ -6,7 +6,7 @@ #include #define PROGNAME "conntrack" -#define CONNTRACK_VERSION "0.95" +#define CONNTRACK_VERSION "0.96" /* FIXME: These should be independent from kernel space */ #define IPS_ASSURED (1 << 2) -- 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 'include/conntrack.h') 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 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 'include/conntrack.h') 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 4385f3c343220fde2dfab637a75767be9e9f98d0 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 17:12:31 +0000 Subject: some libc's don't have IPPROTO_SCTP yet --- include/conntrack.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'include/conntrack.h') diff --git a/include/conntrack.h b/include/conntrack.h index fd51880..98f96f2 100644 --- a/include/conntrack.h +++ b/include/conntrack.h @@ -7,6 +7,11 @@ #define PROGNAME "conntrack" +#include +#ifndef IPPROTO_SCTP +#define IPPROTO_SCTP 132 +#endif + enum action { CT_NONE = 0, -- cgit v1.2.3 From 2082ea8a70a1c3b7c8b47115f00fcbe70fac9ffa 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, 22 Nov 2005 17:29:07 +0000 Subject: Fixed oversized number of options (Marcus Sundberg) --- ChangeLog | 4 ++++ include/conntrack.h | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'include/conntrack.h') diff --git a/ChangeLog b/ChangeLog index 6662998..7909f74 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +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 diff --git a/include/conntrack.h b/include/conntrack.h index 98f96f2..1de5b34 100644 --- a/include/conntrack.h +++ b/include/conntrack.h @@ -115,9 +115,9 @@ enum options { CT_OPT_ID_BIT = 15, CT_OPT_ID = (1 << CT_OPT_ID_BIT), - CT_OPT_MAX = CT_OPT_ID + CT_OPT_MAX_BIT = CT_OPT_ID_BIT }; -#define NUMBER_OF_OPT CT_OPT_MAX +#define NUMBER_OF_OPT CT_OPT_MAX_BIT+1 struct ctproto_handler { struct list_head head; -- 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 'include/conntrack.h') 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 'include/conntrack.h') 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 d5c8cbab19aac1db05b20b9179e80f03803adb5f 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, 19 Jun 2006 16:18:00 +0000 Subject: [PATCH] fix conntrack compilation (Eric Leblond ) --- include/conntrack.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'include/conntrack.h') diff --git a/include/conntrack.h b/include/conntrack.h index 9f5768d..fb3b9b6 100644 --- a/include/conntrack.h +++ b/include/conntrack.h @@ -1,6 +1,10 @@ #ifndef _CONNTRACK_H #define _CONNTRACK_H +#ifdef HAVE_CONFIG_H +#include "../config.h" +#endif + #include "linux_list.h" #include #include -- 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 'include/conntrack.h') 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 'include/conntrack.h') 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 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 'include/conntrack.h') 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 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 'include/conntrack.h') 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 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 'include/conntrack.h') 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 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 'include/conntrack.h') 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 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 'include/conntrack.h') 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 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 'include/conntrack.h') 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 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 'include/conntrack.h') 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 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 'include/conntrack.h') 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 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 'include/conntrack.h') 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 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 'include/conntrack.h') 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 'include/conntrack.h') 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 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 'include/conntrack.h') 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 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 'include/conntrack.h') 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 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 'include/conntrack.h') 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 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 'include/conntrack.h') 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 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 'include/conntrack.h') 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 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 'include/conntrack.h') 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: 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 'include/conntrack.h') 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 'include/conntrack.h') 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 'include/conntrack.h') 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 'include/conntrack.h') 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: 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 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 'include/conntrack.h') 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 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 'include/conntrack.h') 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 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 'include/conntrack.h') 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