From da9b980f8d34c436b31d5a0a09b4ea27849c9c82 Mon Sep 17 00:00:00 2001 From: "/C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=pablo/emailAddress=pablo@netfilter.org" Date: Sun, 16 Oct 2005 21:13:29 +0000 Subject: See ChangeLog --- ChangeLog | 8 + Makefile.am | 2 +- configure.in | 4 +- extensions/libct_proto_icmp.c | 41 +-- extensions/libct_proto_sctp.c | 31 +- extensions/libct_proto_tcp.c | 49 +--- extensions/libct_proto_udp.c | 35 +-- include/libct_proto.h | 25 +- src/Makefile.am | 2 +- src/conntrack.c | 263 ++++++++++++----- src/libct.c | 660 ------------------------------------------ 11 files changed, 253 insertions(+), 867 deletions(-) delete mode 100644 src/libct.c diff --git a/ChangeLog b/ChangeLog index 1a44a43..2942f78 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2005-10-14 + + o Kill config.h.in, it's generated by the autocrap + o The conntrack tool now uses libnetfilter_conntrack :) + o libct.c has been killed, now it's in libnetfilter_conntrack + o Check if you're root or CAP_NET_ADMIN + o Bumped version number to 0.86 + 2005-10-07 o Fixed ICMP options diff --git a/Makefile.am b/Makefile.am index 18a67c6..8d9faf6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -9,7 +9,7 @@ EXTRA_DIST = $(man_MANS) INCLUDES = $(all_includes) -I$(top_srcdir)/include -I${KERNELDIR} SUBDIRS = src extensions DIST_SUBDIRS = include src extensions -LINKOPTS = -ldl -lnfnetlink -lnfnetlink_conntrack +LINKOPTS = -ldl -lnfnetlink -lnetfilter_conntrack AM_CFLAGS = -g $(OBJECTS): libtool diff --git a/configure.in b/configure.in index cd6d7b5..0f0fc5f 100644 --- a/configure.in +++ b/configure.in @@ -2,7 +2,7 @@ AC_INIT AC_CANONICAL_SYSTEM -AM_INIT_AUTOMAKE(conntrack, 0.81) +AM_INIT_AUTOMAKE(conntrack, 0.63) AM_CONFIG_HEADER(config.h) AC_PROG_CC @@ -22,7 +22,7 @@ dnl AC_CHECK_LIB([c], [main]) AC_CHECK_LIB([dl], [dlopen]) AC_CHECK_LIB([nfnetlink], [nfnl_listen]) -AC_CHECK_LIB([nfnetlink_conntrack], [ctnl_register_handler] ,,,[-lnfnetlink]) +AC_CHECK_LIB([netfilter_conntrack], [nfct_dump_conntrack_table] ,,,[-lnetfilter_conntrack]) # Checks for header files. dnl AC_HEADER_STDC diff --git a/extensions/libct_proto_icmp.c b/extensions/libct_proto_icmp.c index be81507..7142fa7 100644 --- a/extensions/libct_proto_icmp.c +++ b/extensions/libct_proto_icmp.c @@ -13,6 +13,7 @@ #include #include /* For htons */ #include +#include #include "libct_proto.h" static struct option opts[] = { @@ -52,10 +53,10 @@ static u_int8_t invmap[] [ICMP_ADDRESSREPLY] = ICMP_ADDRESS + 1}; int parse(char c, char *argv[], - struct ctnl_tuple *orig, - struct ctnl_tuple *reply, - struct ctnl_tuple *mask, - union ctnl_protoinfo *proto, + struct nfct_tuple *orig, + struct nfct_tuple *reply, + struct nfct_tuple *mask, + union nfct_protoinfo *proto, unsigned int *flags) { switch(c) { @@ -85,24 +86,9 @@ int parse(char c, char *argv[], return 1; } -void parse_proto(struct nfattr *cda[], struct ctnl_tuple *tuple) -{ - if (cda[CTA_PROTO_ICMP_TYPE-1]) - tuple->l4dst.icmp.type = - *(u_int8_t *)NFA_DATA(cda[CTA_PROTO_ICMP_TYPE-1]); - - if (cda[CTA_PROTO_ICMP_CODE-1]) - tuple->l4dst.icmp.code = - *(u_int8_t *)NFA_DATA(cda[CTA_PROTO_ICMP_CODE-1]); - - if (cda[CTA_PROTO_ICMP_ID-1]) - tuple->l4src.icmp.id = - *(u_int16_t *)NFA_DATA(cda[CTA_PROTO_ICMP_ID-1]); -} - int final_check(unsigned int flags, - struct ctnl_tuple *orig, - struct ctnl_tuple *reply) + struct nfct_tuple *orig, + struct nfct_tuple *reply) { if (!(flags & ICMP_TYPE)) return 0; @@ -112,21 +98,10 @@ int final_check(unsigned int flags, return 1; } -void print_proto(struct ctnl_tuple *t) -{ - fprintf(stdout, "type=%d code=%d ", t->l4dst.icmp.type, - t->l4dst.icmp.code); - /* ID only makes sense with ECHO */ - if (t->l4dst.icmp.type == 8) - fprintf(stdout, "id=%d ", t->l4src.icmp.id); -} - static struct ctproto_handler icmp = { .name = "icmp", - .protonum = 1, + .protonum = IPPROTO_ICMP, .parse_opts = parse, - .parse_proto = parse_proto, - .print_proto = print_proto, .final_check = final_check, .help = help, .opts = opts, diff --git a/extensions/libct_proto_sctp.c b/extensions/libct_proto_sctp.c index 9afb661..bc91966 100644 --- a/extensions/libct_proto_sctp.c +++ b/extensions/libct_proto_sctp.c @@ -12,9 +12,8 @@ #include #include #include /* For htons */ -#include #include "libct_proto.h" -#include +#include static struct option opts[] = { {"orig-port-src", 1, 0, '1'}, @@ -63,10 +62,10 @@ void help() } int parse_options(char c, char *argv[], - struct ctnl_tuple *orig, - struct ctnl_tuple *reply, - struct ctnl_tuple *mask, - union ctnl_protoinfo *proto, + struct nfct_tuple *orig, + struct nfct_tuple *reply, + struct nfct_tuple *mask, + union nfct_protoinfo *proto, unsigned int *flags) { switch(c) { @@ -100,7 +99,7 @@ int parse_options(char c, char *argv[], for (i=0; i<10; i++) { if (strcmp(optarg, states[i]) == 0) { /* FIXME: Add state to - * ctnl_protoinfo + * nfct_protoinfo proto->sctp.state = i; */ break; } @@ -116,8 +115,8 @@ int parse_options(char c, char *argv[], } int final_check(unsigned int flags, - struct ctnl_tuple *orig, - struct ctnl_tuple *reply) + struct nfct_tuple *orig, + struct nfct_tuple *reply) { if ((flags & (ORIG_SPORT|ORIG_DPORT)) && !(flags & (REPL_SPORT|REPL_DPORT))) { @@ -137,7 +136,7 @@ int final_check(unsigned int flags, return 0; } -void parse_proto(struct nfattr *cda[], struct ctnl_tuple *tuple) +void parse_proto(struct nfattr *cda[], struct nfct_tuple *tuple) { if (cda[CTA_PROTO_SRC_PORT-1]) tuple->l4src.sctp.port = @@ -147,7 +146,7 @@ void parse_proto(struct nfattr *cda[], struct ctnl_tuple *tuple) *(u_int16_t *)NFA_DATA(cda[CTA_PROTO_DST_PORT-1]); } -void parse_protoinfo(struct nfattr *cda[], struct ctnl_conntrack *ct) +void parse_protoinfo(struct nfattr *cda[], struct nfct_conntrack *ct) { /* if (cda[CTA_PROTOINFO_SCTP_STATE-1]) ct->protoinfo.sctp.state = @@ -155,12 +154,12 @@ void parse_protoinfo(struct nfattr *cda[], struct ctnl_conntrack *ct) */ } -void print_protoinfo(union ctnl_protoinfo *protoinfo) +void print_protoinfo(union nfct_protoinfo *protoinfo) { /* fprintf(stdout, "%s ", states[protoinfo->sctp.state]); */ } -void print_proto(struct ctnl_tuple *tuple) +void print_proto(struct nfct_tuple *tuple) { fprintf(stdout, "sport=%u dport=%u ", htons(tuple->l4src.sctp.port), htons(tuple->l4dst.sctp.port)); @@ -168,12 +167,8 @@ void print_proto(struct ctnl_tuple *tuple) static struct ctproto_handler sctp = { .name = "sctp", - .protonum = 132, + .protonum = IPPROTO_SCTP, .parse_opts = parse_options, - .parse_protoinfo = parse_protoinfo, - .parse_proto = parse_proto, - .print_proto = print_proto, - .print_protoinfo = print_protoinfo, .final_check = final_check, .help = help, .opts = opts, diff --git a/extensions/libct_proto_tcp.c b/extensions/libct_proto_tcp.c index 4f3094f..3b06aa2 100644 --- a/extensions/libct_proto_tcp.c +++ b/extensions/libct_proto_tcp.c @@ -12,8 +12,7 @@ #include #include #include /* For htons */ -#include -#include +#include #include "libct_proto.h" @@ -76,10 +75,10 @@ void help() } int parse_options(char c, char *argv[], - struct ctnl_tuple *orig, - struct ctnl_tuple *reply, - struct ctnl_tuple *mask, - union ctnl_protoinfo *proto, + struct nfct_tuple *orig, + struct nfct_tuple *reply, + struct nfct_tuple *mask, + union nfct_protoinfo *proto, unsigned int *flags) { switch(c) { @@ -139,8 +138,8 @@ int parse_options(char c, char *argv[], } int final_check(unsigned int flags, - struct ctnl_tuple *orig, - struct ctnl_tuple *reply) + struct nfct_tuple *orig, + struct nfct_tuple *reply) { if ((flags & (ORIG_SPORT|ORIG_DPORT)) && !(flags & (REPL_SPORT|REPL_DPORT))) { @@ -160,42 +159,10 @@ int final_check(unsigned int flags, return 0; } -void parse_proto(struct nfattr *cda[], struct ctnl_tuple *tuple) -{ - if (cda[CTA_PROTO_SRC_PORT-1]) - tuple->l4src.tcp.port = - *(u_int16_t *)NFA_DATA(cda[CTA_PROTO_SRC_PORT-1]); - if (cda[CTA_PROTO_DST_PORT-1]) - tuple->l4dst.tcp.port = - *(u_int16_t *)NFA_DATA(cda[CTA_PROTO_DST_PORT-1]); -} - -void parse_protoinfo(struct nfattr *cda[], struct ctnl_conntrack *ct) -{ - if (cda[CTA_PROTOINFO_TCP_STATE-1]) - ct->protoinfo.tcp.state = - *(u_int8_t *)NFA_DATA(cda[CTA_PROTOINFO_TCP_STATE-1]); -} - -void print_protoinfo(union ctnl_protoinfo *protoinfo) -{ - fprintf(stdout, "%s ", states[protoinfo->tcp.state]); -} - -void print_proto(struct ctnl_tuple *tuple) -{ - fprintf(stdout, "sport=%u dport=%u ", htons(tuple->l4src.tcp.port), - htons(tuple->l4dst.tcp.port)); -} - static struct ctproto_handler tcp = { .name = "tcp", - .protonum = 6, + .protonum = IPPROTO_TCP, .parse_opts = parse_options, - .parse_protoinfo = parse_protoinfo, - .parse_proto = parse_proto, - .print_proto = print_proto, - .print_protoinfo = print_protoinfo, .final_check = final_check, .help = help, .opts = opts, diff --git a/extensions/libct_proto_udp.c b/extensions/libct_proto_udp.c index ecde5f2..8e77f0c 100644 --- a/extensions/libct_proto_udp.c +++ b/extensions/libct_proto_udp.c @@ -11,9 +11,8 @@ #include #include #include /* For htons */ -#include #include "libct_proto.h" -#include +#include static struct option opts[] = { {"orig-port-src", 1, 0, '1'}, @@ -56,10 +55,10 @@ void help() } int parse_options(char c, char *argv[], - struct ctnl_tuple *orig, - struct ctnl_tuple *reply, - struct ctnl_tuple *mask, - union ctnl_protoinfo *proto, + struct nfct_tuple *orig, + struct nfct_tuple *reply, + struct nfct_tuple *mask, + union nfct_protoinfo *proto, unsigned int *flags) { switch(c) { @@ -104,8 +103,8 @@ int parse_options(char c, char *argv[], } int final_check(unsigned int flags, - struct ctnl_tuple *orig, - struct ctnl_tuple *reply) + struct nfct_tuple *orig, + struct nfct_tuple *reply) { if ((flags & (ORIG_SPORT|ORIG_DPORT)) && !(flags & (REPL_SPORT|REPL_DPORT))) { @@ -125,28 +124,10 @@ int final_check(unsigned int flags, return 0; } -void parse_proto(struct nfattr *cda[], struct ctnl_tuple *tuple) -{ - if (cda[CTA_PROTO_SRC_PORT-1]) - tuple->l4src.udp.port = - *(u_int16_t *)NFA_DATA(cda[CTA_PROTO_SRC_PORT-1]); - if (cda[CTA_PROTO_DST_PORT-1]) - tuple->l4dst.udp.port = - *(u_int16_t *)NFA_DATA(cda[CTA_PROTO_DST_PORT-1]); -} - -void print_proto(struct ctnl_tuple *tuple) -{ - fprintf(stdout, "sport=%u dport=%u ", htons(tuple->l4src.udp.port), - htons(tuple->l4dst.udp.port)); -} - static struct ctproto_handler udp = { .name = "udp", - .protonum = 17, + .protonum = IPPROTO_UDP, .parse_opts = parse_options, - .parse_proto = parse_proto, - .print_proto = print_proto, .final_check = final_check, .help = help, .opts = opts, diff --git a/include/libct_proto.h b/include/libct_proto.h index b358e1a..db434d6 100644 --- a/include/libct_proto.h +++ b/include/libct_proto.h @@ -1,11 +1,9 @@ #ifndef _LIBCT_PROTO_H #define _LIBCT_PROTO_H -/* FIXME: Rename this file pablo... */ - #include "linux_list.h" #include -#include +#include #define LIBCT_VERSION "0.1.0" @@ -16,8 +14,6 @@ #define IPS_DST_NAT_DONE (1 << 8) #define IPS_CONFIRMED (1 << 3) -struct cta_proto; - struct ctproto_handler { struct list_head head; @@ -28,20 +24,15 @@ struct ctproto_handler { enum ctattr_protoinfo protoinfo_attr; int (*parse_opts)(char c, char *argv[], - struct ctnl_tuple *orig, - struct ctnl_tuple *reply, - struct ctnl_tuple *mask, - union ctnl_protoinfo *proto, + struct nfct_tuple *orig, + struct nfct_tuple *reply, + struct nfct_tuple *mask, + union nfct_protoinfo *proto, unsigned int *flags); - void (*parse_proto)(struct nfattr *cda[], struct ctnl_tuple *tuple); - void (*parse_protoinfo)(struct nfattr *cda[], - struct ctnl_conntrack *ct); - void (*print_proto)(struct ctnl_tuple *t); - void (*print_protoinfo)(union ctnl_protoinfo *protoinfo); int (*final_check)(unsigned int flags, - struct ctnl_tuple *orig, - struct ctnl_tuple *reply); + struct nfct_tuple *orig, + struct nfct_tuple *reply); void (*help)(); @@ -53,8 +44,6 @@ struct ctproto_handler { extern void register_proto(struct ctproto_handler *h); extern void unregister_proto(struct ctproto_handler *h); -extern struct ctproto_handler *findproto(char *name); - #define NIPQUAD(addr) \ ((unsigned char *)&addr)[0], \ ((unsigned char *)&addr)[1], \ diff --git a/src/Makefile.am b/src/Makefile.am index ae3f429..71ad3d5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,5 +1,5 @@ bin_PROGRAMS = conntrack -conntrack_SOURCES = conntrack.c libct.c +conntrack_SOURCES = conntrack.c INCLUDES= $(all_includes) -I$(top_srcdir)/include -I${KERNELDIR} conntrack_LDFLAGS = $(all_libraries) -rdynamic diff --git a/src/conntrack.c b/src/conntrack.c index 1d5227e..8132dcb 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -1,5 +1,5 @@ /* - * (C) 2005 by Pablo Neira Ayuso + * (C) 2005 by Pablo Neira Ayuso * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -42,19 +42,14 @@ #include #include #include +#include #include -#include #include "linux_list.h" #include "libct_proto.h" +#include #define PROGNAME "conntrack" -#define VERSION "0.82" - -#if 0 -#define DEBUGP printf -#else -#define DEBUGP -#endif +#define VERSION "0.86" #ifndef PROC_SYS_MODPROBE #define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe" @@ -197,6 +192,7 @@ static struct option original_opts[] = { #define OPTION_OFFSET 256 +struct nfct_handle *cth; static struct option *opts = original_opts; static unsigned int global_option_offset = 0; @@ -236,12 +232,53 @@ char *lib_dir = CONNTRACK_LIB_DIR; LIST_HEAD(proto_list); -char *proto2str[IPPROTO_MAX] = { - [IPPROTO_TCP] = "tcp", - [IPPROTO_UDP] = "udp", - [IPPROTO_ICMP] = "icmp", - [IPPROTO_SCTP] = "sctp" -}; +void register_proto(struct ctproto_handler *h) +{ + if (strcmp(h->version, LIBCT_VERSION) != 0) { + fprintf(stderr, "plugin `%s': version %s (I'm %s)\n", + h->name, h->version, LIBCT_VERSION); + exit(1); + } + list_add(&h->head, &proto_list); +} + +void unregister_proto(struct ctproto_handler *h) +{ + list_del(&h->head); +} + +static struct nfct_proto *findproto(char *name) +{ + struct list_head *i; + struct nfct_proto *cur = NULL, *handler = NULL; + + if (!name) + return handler; + + lib_dir = getenv("CONNTRACK_LIB_DIR"); + if (!lib_dir) + lib_dir = CONNTRACK_LIB_DIR; + + list_for_each(i, &proto_list) { + cur = (struct nfct_proto *) i; + if (strcmp(cur->name, name) == 0) { + handler = cur; + break; + } + } + + if (!handler) { + char path[sizeof("libct_proto_.so") + + strlen(name) + strlen(lib_dir)]; + sprintf(path, "%s/libct_proto_%s.so", lib_dir, name); + if (dlopen(path, RTLD_NOW)) + handler = findproto(name); + else + fprintf(stderr, "%s\n", dlerror()); + } + + return handler; +} enum exittype { OTHER_PROBLEM = 1, @@ -383,7 +420,9 @@ err2str(int err, enum action command) { CT_GET, -EAFNOSUPPORT, "protocol not supported" }, { CT_CREATE, -ETIME, "conntrack has expired" }, { EXP_CREATE, -ENOENT, "master conntrack not found" }, - { EXP_CREATE, -EINVAL, "invalid parameters" } + { EXP_CREATE, -EINVAL, "invalid parameters" }, + { ~0UL, -EPERM, "sorry, you must be root or get " + "CAP_NET_ADMIN capability to do this"} }; for (i = 0; i < sizeof(table)/sizeof(struct table_struct); i++) { @@ -394,7 +433,7 @@ err2str(int err, enum action command) return strerror(err); } -static void dump_tuple(struct ctnl_tuple *tp) +static void dump_tuple(struct nfct_tuple *tp) { fprintf(stdout, "tuple %p: %u %u.%u.%u.%u:%hu -> %u.%u.%u.%u:%hu\n", tp, tp->protonum, @@ -553,7 +592,7 @@ int iptables_insmod(const char *modname, const char *modprobe) /* Shamelessly stolen from libipt_DNAT ;). Ranges expected in network order. */ static void -nat_parse(char *arg, int portok, struct ctnl_nat *range) +nat_parse(char *arg, int portok, struct nfct_nat *range) { char *colon, *dash, *error; unsigned long ip; @@ -625,6 +664,13 @@ nat_parse(char *arg, int portok, struct ctnl_nat *range) range->max_ip = range->min_ip; } +static void event_sighandler(int s) +{ + fprintf(stdout, "Now closing conntrack event dumping...\n"); + nfct_close(cth); + exit(0); +} + void usage(char *prog) { fprintf(stdout, "Tool to manipulate conntrack and expectations. Version %s\n", VERSION); fprintf(stdout, "Usage: %s [commands] [options]\n", prog); @@ -659,11 +705,11 @@ int main(int argc, char *argv[]) { char c; unsigned int command = 0, options = 0; - struct ctnl_tuple orig, reply, mask, *o = NULL, *r = NULL; - struct ctnl_tuple exptuple; + struct nfct_tuple orig, reply, mask, *o = NULL, *r = NULL; + struct nfct_tuple exptuple; struct ctproto_handler *h = NULL; - union ctnl_protoinfo proto; - struct ctnl_nat range; + union nfct_protoinfo proto; + struct nfct_nat range; unsigned long timeout = 0; unsigned int status = IPS_CONFIRMED; unsigned long id = 0; @@ -671,13 +717,13 @@ int main(int argc, char *argv[]) int manip = -1; int res = 0, retry = 2; - memset(&proto, 0, sizeof(union ctnl_protoinfo)); - memset(&orig, 0, sizeof(struct ctnl_tuple)); - memset(&reply, 0, sizeof(struct ctnl_tuple)); - memset(&mask, 0, sizeof(struct ctnl_tuple)); - memset(&exptuple, 0, sizeof(struct ctnl_tuple)); - memset(&range, 0, sizeof(struct ctnl_nat)); - + memset(&proto, 0, sizeof(union nfct_protoinfo)); + memset(&orig, 0, sizeof(struct nfct_tuple)); + memset(&reply, 0, sizeof(struct nfct_tuple)); + memset(&mask, 0, sizeof(struct nfct_tuple)); + memset(&exptuple, 0, sizeof(struct nfct_tuple)); + memset(&range, 0, sizeof(struct nfct_nat)); + while ((c = getopt_long(argc, argv, "L::I::U::D::G::E::F::hVs:d:r:q:p:t:u:e:a:z[:]:{:}:", opts, NULL)) != -1) { @@ -846,14 +892,24 @@ int main(int argc, char *argv[]) retry--; switch(command) { case CT_LIST: + cth = nfct_open(CONNTRACK, 0); + if (!cth) + exit_error(OTHER_PROBLEM, "Not enough memory"); + nfct_set_callback(cth, nfct_default_conntrack_display); if (options & CT_OPT_ZERO) - res = dump_conntrack_table(1); + res = nfct_dump_conntrack_table_zero(cth); else - res = dump_conntrack_table(0); + res = nfct_dump_conntrack_table(cth); break; + nfct_close(cth); case EXP_LIST: - res = dump_expect_list(); + cth = nfct_open(EXPECT, 0); + if (!cth) + exit_error(OTHER_PROBLEM, "Not enough memory"); + nfct_set_callback(cth, nfct_default_expect_display); + res = nfct_dump_expect_list(cth); + nfct_close(cth); break; case CT_CREATE: @@ -866,25 +922,43 @@ int main(int argc, char *argv[]) orig.src.v4 = reply.dst.v4; orig.dst.v4 = reply.src.v4; } + cth = nfct_open(CONNTRACK, 0); + if (!cth) + exit_error(OTHER_PROBLEM, "Not enough memory"); if (options & CT_OPT_NATRANGE) - res = create_conntrack(&orig, &reply, timeout, - &proto, status, &range); + res = nfct_create_conntrack_nat(cth, + &orig, + &reply, + timeout, + &proto, + status, + &range); else - res = create_conntrack(&orig, &reply, timeout, - &proto, status, NULL); + res = nfct_create_conntrack(cth, &orig, + &reply, + timeout, + &proto, + status); + nfct_close(cth); break; case EXP_CREATE: + cth = nfct_open(EXPECT, 0); + if (!cth) + exit_error(OTHER_PROBLEM, "Not enough memory"); if (options & CT_OPT_ORIG) - res = create_expectation(&orig, - &exptuple, - &mask, - timeout); + res = nfct_create_expectation(cth, + &orig, + &exptuple, + &mask, + timeout); else if (options & CT_OPT_REPL) - res = create_expectation(&reply, - &exptuple, - &mask, - timeout); + res = nfct_create_expectation(cth, + &reply, + &exptuple, + &mask, + timeout); + nfct_close(cth); break; case CT_UPDATE: @@ -897,60 +971,117 @@ int main(int argc, char *argv[]) orig.src.v4 = reply.dst.v4; orig.dst.v4 = reply.src.v4; } - res = update_conntrack(&orig, &reply, timeout, - &proto, status); + cth = nfct_open(CONNTRACK, 0); + if (!cth) + exit_error(OTHER_PROBLEM, "Not enough memory"); + res = nfct_update_conntrack(cth, &orig, &reply, + timeout, &proto, + status); + nfct_close(cth); break; case CT_DELETE: + cth = nfct_open(CONNTRACK, 0); + if (!cth) + exit_error(OTHER_PROBLEM, "Not enough memory"); if (options & CT_OPT_ORIG) - res = delete_conntrack(&orig, CTA_TUPLE_ORIG, - CTNL_DIR_ORIGINAL); + res = nfct_delete_conntrack(cth,&orig, + NFCT_DIR_ORIGINAL); else if (options & CT_OPT_REPL) - res = delete_conntrack(&reply, CTA_TUPLE_REPLY, - CTNL_DIR_REPLY); + res = nfct_delete_conntrack(cth,&reply, + NFCT_DIR_REPLY); + nfct_close(cth); break; case EXP_DELETE: + cth = nfct_open(EXPECT, 0); + if (!cth) + exit_error(OTHER_PROBLEM, "Not enough memory"); if (options & CT_OPT_ORIG) - res = delete_expectation(&orig); + res = nfct_delete_expectation(cth,&orig); else if (options & CT_OPT_REPL) - res = delete_expectation(&reply); + res = nfct_delete_expectation(cth,&reply); + nfct_close(cth); break; case CT_GET: + cth = nfct_open(CONNTRACK, 0); + if (!cth) + exit_error(OTHER_PROBLEM, "Not enough memory"); if (options & CT_OPT_ORIG) - res = get_conntrack(&orig, id); + res = nfct_get_conntrack(cth,&orig, id); else if (options & CT_OPT_REPL) - res = get_conntrack(&reply, id); + res = nfct_get_conntrack(cth,&reply, id); + nfct_close(cth); break; case EXP_GET: + cth = nfct_open(EXPECT, 0); + if (!cth) + exit_error(OTHER_PROBLEM, "Not enough memory"); if (options & CT_OPT_ORIG) - res = get_expect(&orig, CTA_TUPLE_ORIG); + res = nfct_get_expectation(cth,&orig); else if (options & CT_OPT_REPL) - res = get_expect(&reply, CTA_TUPLE_REPLY); + res = nfct_get_expectation(cth,&reply); + nfct_close(cth); break; case CT_FLUSH: - res = flush_conntrack(); + cth = nfct_open(CONNTRACK, 0); + if (!cth) + exit_error(OTHER_PROBLEM, "Not enough memory"); + res = nfct_flush_conntrack_table(cth); + nfct_close(cth); break; case EXP_FLUSH: - res = flush_expectation(); + cth = nfct_open(EXPECT, 0); + if (!cth) + exit_error(OTHER_PROBLEM, "Not enough memory"); + res = nfct_flush_expectation_table(cth); + nfct_close(cth); break; case CT_EVENT: - if (options & CT_OPT_EVENT_MASK) - res = event_conntrack(event_mask); - else - res = event_conntrack(~0U); + if (options & CT_OPT_EVENT_MASK) { + cth = nfct_open(CONNTRACK, event_mask); + if (!cth) + exit_error(OTHER_PROBLEM, + "Not enough memory"); + signal(SIGINT, event_sighandler); + nfct_set_callback(cth, nfct_default_conntrack_display); + res = nfct_event_conntrack(cth); + } else { + cth = nfct_open(CONNTRACK, ~0U); + if (!cth) + exit_error(OTHER_PROBLEM, + "Not enough memory"); + signal(SIGINT, event_sighandler); + nfct_set_callback(cth, nfct_default_conntrack_display); + res = nfct_event_conntrack(cth); + } + nfct_close(cth); break; case EXP_EVENT: - if (options & CT_OPT_EVENT_MASK) - res = event_expectation(event_mask); - else - res = event_expectation(~0U); + if (options & CT_OPT_EVENT_MASK) { + cth = nfct_open(EXPECT, event_mask); + if (!cth) + exit_error(OTHER_PROBLEM, + "Not enough memory"); + signal(SIGINT, event_sighandler); + nfct_set_callback(cth, nfct_default_expect_display); + res = nfct_event_expectation(cth); + } else { + cth = nfct_open(EXPECT, ~0U); + if (!cth) + exit_error(OTHER_PROBLEM, + "Not enough memory"); + signal(SIGINT, event_sighandler); + nfct_set_callback(cth, nfct_default_expect_display); + res = nfct_event_expectation(cth); + } + nfct_close(cth); break; case CT_VERSION: diff --git a/src/libct.c b/src/libct.c deleted file mode 100644 index 36aacbd..0000000 --- a/src/libct.c +++ /dev/null @@ -1,660 +0,0 @@ -/* - * (C) 2005 by Pablo Neira Ayuso - * Harald Welte - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ -#include -#include -#include -#include -#include -#include -#include -/* From kernel.h */ -#define INT_MAX ((int)(~0U>>1)) -#define INT_MIN (-INT_MAX - 1) -#include -#include "linux_list.h" -#include "libct_proto.h" - -#if 0 -#define DEBUGP printf -#else -#define DEBUGP -#endif - -static struct ctnl_handle cth; -extern char *lib_dir; -extern struct list_head proto_list; -extern char *proto2str[]; - -static void dump_tuple(struct ctnl_tuple *tp) -{ - fprintf(stdout, "tuple %p: %u %u.%u.%u.%u:%hu -> %u.%u.%u.%u:%hu\n", - tp, tp->protonum, - NIPQUAD(tp->src.v4), ntohs(tp->l4src.all), - NIPQUAD(tp->dst.v4), ntohs(tp->l4dst.all)); -} - -static void print_status(unsigned int status) -{ - if (status & IPS_ASSURED) - fprintf(stdout, "[ASSURED] "); - if (!(status & IPS_SEEN_REPLY)) - fprintf(stdout, "[UNREPLIED] "); -} - -static void parse_ip(struct nfattr *attr, struct ctnl_tuple *tuple) -{ - struct nfattr *tb[CTA_IP_MAX]; - - memset(tb, 0, CTA_IP_MAX * sizeof(struct nfattr *)); - - nfnl_parse_nested(tb, CTA_IP_MAX, attr); - if (tb[CTA_IP_V4_SRC-1]) - tuple->src.v4 = *(u_int32_t *)NFA_DATA(tb[CTA_IP_V4_SRC-1]); - - if (tb[CTA_IP_V4_DST-1]) - tuple->dst.v4 = *(u_int32_t *)NFA_DATA(tb[CTA_IP_V4_DST-1]); -} - -static void parse_proto(struct nfattr *attr, struct ctnl_tuple *tuple) -{ - struct nfattr *tb[CTA_PROTO_MAX]; - struct ctproto_handler *h; - int dir = CTNL_DIR_REPLY; - - memset(tb, 0, CTA_PROTO_MAX * sizeof(struct nfattr *)); - - nfnl_parse_nested(tb, CTA_PROTO_MAX, attr); - if (tb[CTA_PROTO_NUM-1]) - tuple->protonum = *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_NUM-1]); - - h = findproto(proto2str[tuple->protonum]); - if (h && h->parse_proto) - h->parse_proto(tb, tuple); -} - -static void parse_tuple(struct nfattr *attr, struct ctnl_tuple *tuple) -{ - struct nfattr *tb[CTA_TUPLE_MAX]; - - memset(tb, 0, CTA_TUPLE_MAX*sizeof(struct nfattr *)); - - nfnl_parse_nested(tb, CTA_TUPLE_MAX, attr); - if (tb[CTA_TUPLE_IP-1]) - parse_ip(tb[CTA_TUPLE_IP-1], tuple); - if (tb[CTA_TUPLE_PROTO-1]) - parse_proto(tb[CTA_TUPLE_PROTO-1], tuple); -} - -static void parse_protoinfo(struct nfattr *attr, struct ctnl_conntrack *ct) -{ - struct nfattr *tb[CTA_PROTOINFO_MAX]; - struct ctproto_handler *h; - - memset(tb, 0, CTA_PROTOINFO_MAX*sizeof(struct nfattr *)); - - nfnl_parse_nested(tb,CTA_PROTOINFO_MAX, attr); - - h = findproto(proto2str[ct->tuple[CTNL_DIR_ORIGINAL].protonum]); - if (h && h->parse_protoinfo) - h->parse_protoinfo(tb, ct); -} - -/* Pablo: What is the equivalence of be64_to_cpu in userspace? - * - * Harald: Good question. I don't think there's a standard way [yet?], - * so I'd suggest manually implementing it by "#if little endian" bitshift - * operations in C (at least for now). - * - * All the payload of any nfattr will always be in network byte order. - * This would allow easy transport over a real network in the future - * (e.g. jamal's netlink2). - * - * Pablo: I've called it __be64_to_cpu instead of be64_to_cpu, since maybe - * there will one in the userspace headers someday. We don't want to - * pollute POSIX space naming, - */ - -#include -#if __BYTE_ORDER == __BIG_ENDIAN -# define __be64_to_cpu(x) (x) -# else -# if __BYTE_ORDER == __LITTLE_ENDIAN -# define __be64_to_cpu(x) __bswap_64(x) -# endif -#endif - -static void parse_counters(struct nfattr *attr, struct ctnl_conntrack *ct, - enum ctattr_type parent) -{ - struct nfattr *tb[CTA_COUNTERS_MAX]; - int dir = (parent == CTA_COUNTERS_ORIG ? CTNL_DIR_REPLY - : CTNL_DIR_ORIGINAL); - - memset(tb, 0, CTA_COUNTERS_MAX*sizeof(struct nfattr *)); - - nfnl_parse_nested(tb, CTA_COUNTERS_MAX, attr); - if (tb[CTA_COUNTERS_PACKETS-1]) - ct->counters[dir].packets - = __be64_to_cpu(*(u_int64_t *) - NFA_DATA(tb[CTA_COUNTERS_PACKETS-1])); - if (tb[CTA_COUNTERS_BYTES-1]) - ct->counters[dir].bytes - = __be64_to_cpu(*(u_int64_t *) - NFA_DATA(tb[CTA_COUNTERS_BYTES-1])); -} - -/* Some people seem to like counting in decimal... */ -#define STATUS 1 -#define PROTOINFO 2 -#define TIMEOUT 4 -#define MARK 8 -#define COUNTERS 16 -#define USE 32 -#define ID 64 - -static int handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void *arg) -{ - struct nfgenmsg *nfmsg; - struct nfattr *nfa; - int min_len = sizeof(struct nfgenmsg);; - struct ctproto_handler *h = NULL; - struct nfattr *attr = NFM_NFA(NLMSG_DATA(nlh)); - int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); - struct ctnl_conntrack ct; - unsigned int flags = 0; - - memset(&ct, 0, sizeof(struct ctnl_conntrack)); - - nfmsg = NLMSG_DATA(nlh); - - if (nlh->nlmsg_len < min_len) - return -EINVAL; - - while (NFA_OK(attr, attrlen)) { - switch(attr->nfa_type) { - case CTA_TUPLE_ORIG: - parse_tuple(attr, &ct.tuple[CTNL_DIR_ORIGINAL]); - break; - case CTA_TUPLE_REPLY: - parse_tuple(attr, &ct.tuple[CTNL_DIR_REPLY]); - break; - case CTA_STATUS: - ct.status = ntohl(*(u_int32_t *)NFA_DATA(attr)); - flags |= STATUS; - break; - case CTA_PROTOINFO: - parse_protoinfo(attr, &ct); - flags |= PROTOINFO; - break; - case CTA_TIMEOUT: - ct.timeout = ntohl(*(u_int32_t *)NFA_DATA(attr)); - flags |= TIMEOUT; - break; - case CTA_MARK: - ct.mark = ntohl(*(u_int32_t *)NFA_DATA(attr)); - flags |= MARK; - break; - case CTA_COUNTERS_ORIG: - case CTA_COUNTERS_REPLY: - parse_counters(attr, &ct, attr->nfa_type-1); - flags |= COUNTERS; - break; - case CTA_USE: - ct.use = ntohl(*(u_int32_t *)NFA_DATA(attr)); - flags |= USE; - break; - case CTA_ID: - ct.id = ntohl(*(u_int32_t *)NFA_DATA(attr)); - flags |= ID; - break; - } - attr = NFA_NEXT(attr, attrlen); - } - - fprintf(stdout, "%-8s %u ", - proto2str[ct.tuple[CTNL_DIR_ORIGINAL].protonum] == NULL ? - "unknown" : proto2str[ct.tuple[CTNL_DIR_ORIGINAL].protonum], - ct.tuple[CTNL_DIR_ORIGINAL].protonum); - - if (flags & TIMEOUT) - fprintf(stdout, "%lu ", ct.timeout); - - h = findproto(proto2str[ct.tuple[CTNL_DIR_ORIGINAL].protonum]); - if ((flags & PROTOINFO) && h && h->print_protoinfo) - h->print_protoinfo(&ct.protoinfo); - - fprintf(stdout, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ", - NIPQUAD(ct.tuple[CTNL_DIR_ORIGINAL].src.v4), - NIPQUAD(ct.tuple[CTNL_DIR_ORIGINAL].dst.v4)); - - if (h && h->print_proto) - h->print_proto(&ct.tuple[CTNL_DIR_ORIGINAL]); - - if (flags & COUNTERS) - fprintf(stdout, "packets=%llu bytes=%llu ", - ct.counters[CTNL_DIR_ORIGINAL].packets, - ct.counters[CTNL_DIR_ORIGINAL].bytes); - - fprintf(stdout, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ", - NIPQUAD(ct.tuple[CTNL_DIR_REPLY].src.v4), - NIPQUAD(ct.tuple[CTNL_DIR_REPLY].dst.v4)); - - h = findproto(proto2str[ct.tuple[CTNL_DIR_ORIGINAL].protonum]); - if (h && h->print_proto) - h->print_proto(&ct.tuple[CTNL_DIR_REPLY]); - - if (flags & COUNTERS) - fprintf(stdout, "packets=%llu bytes=%llu ", - ct.counters[CTNL_DIR_REPLY].packets, - ct.counters[CTNL_DIR_REPLY].bytes); - - if (flags & STATUS) - print_status(ct.status); - - if (flags & MARK) - fprintf(stdout, "mark=%lu ", ct.mark); - if (flags & USE) - fprintf(stdout, "use=%u ", ct.use); - if (flags & ID) - fprintf(stdout, "id=%u ", ct.id); - - fprintf(stdout, "\n"); - - return 0; -} - -static char *typemsg2str(type, flags) -{ - char *ret = "[UNKNOWN]"; - - if (type == IPCTNL_MSG_CT_NEW) { - if (flags & NLM_F_CREATE) - ret = "[NEW]"; - else - ret = "[UPDATE]"; - } else if (type == IPCTNL_MSG_CT_DELETE) - ret = "[DESTROY]"; - - return ret; -} - -static int event_handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, - void *arg) -{ - int type = NFNL_MSG_TYPE(nlh->nlmsg_type); - fprintf(stdout, "%9s ", typemsg2str(type, nlh->nlmsg_flags)); - return handler(sock, nlh, arg); -} - -static int expect_handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void *arg) -{ - struct nfgenmsg *nfmsg; - struct nfattr *nfa; - int min_len = sizeof(struct nfgenmsg);; - struct ctproto_handler *h = NULL; - struct nfattr *attr = NFM_NFA(NLMSG_DATA(nlh)); - int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); - struct ctnl_tuple tuple, mask; - unsigned long timeout = 0; - u_int32_t id = 0; - unsigned int flags; - - memset(&tuple, 0, sizeof(struct ctnl_tuple)); - memset(&mask, 0, sizeof(struct ctnl_tuple)); - - nfmsg = NLMSG_DATA(nlh); - - if (nlh->nlmsg_len < min_len) - return -EINVAL; - - while (NFA_OK(attr, attrlen)) { - switch(attr->nfa_type) { - - case CTA_EXPECT_TUPLE: - parse_tuple(attr, &tuple); - break; - case CTA_EXPECT_MASK: - parse_tuple(attr, &mask); - break; - case CTA_EXPECT_TIMEOUT: - timeout = htonl(*(unsigned long *) - NFA_DATA(attr)); - break; - case CTA_EXPECT_ID: - id = htonl(*(u_int32_t *)NFA_DATA(attr)); - break; - } - attr = NFA_NEXT(attr, attrlen); - } - fprintf(stdout, "%ld proto=%d ", timeout, tuple.protonum); - - fprintf(stdout, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ", - NIPQUAD(tuple.src.v4), - NIPQUAD(tuple.dst.v4)); - - fprintf(stdout, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ", - NIPQUAD(mask.src.v4), - NIPQUAD(mask.dst.v4)); - - fprintf(stdout, "id=%u ", id); - - fputc('\n', stdout); - - return 0; -} - -int create_conntrack(struct ctnl_tuple *orig, - struct ctnl_tuple *reply, - unsigned long timeout, - union ctnl_protoinfo *proto, - unsigned int status, - struct ctnl_nat *range) -{ - struct ctnl_conntrack ct; - int ret; - - memset(&ct, 0, sizeof(struct ctnl_conntrack)); - ct.tuple[CTNL_DIR_ORIGINAL] = *orig; - ct.tuple[CTNL_DIR_REPLY] = *reply; - ct.timeout = htonl(timeout); - ct.status = status; - ct.protoinfo = *proto; - if (range) - ct.nat = *range; - - if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK, 0)) < 0) - return ret; - - ret = ctnl_new_conntrack(&cth, &ct); - - ctnl_close(&cth); - - return ret; -} - -int update_conntrack(struct ctnl_tuple *orig, - struct ctnl_tuple *reply, - unsigned long timeout, - union ctnl_protoinfo *proto, - unsigned int status) -{ - struct ctnl_conntrack ct; - int ret; - - memset(&ct, 0, sizeof(struct ctnl_conntrack)); - ct.tuple[CTNL_DIR_ORIGINAL] = *orig; - ct.tuple[CTNL_DIR_REPLY] = *reply; - ct.timeout = htonl(timeout); - ct.status = status; - ct.protoinfo = *proto; - - if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK, 0)) < 0) - return ret; - - ret = ctnl_upd_conntrack(&cth, &ct); - - ctnl_close(&cth); - - return ret; -} - -int delete_conntrack(struct ctnl_tuple *tuple, int dir) -{ - int ret; - - if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK, 0)) < 0) - return ret; - - ret = ctnl_del_conntrack(&cth, tuple, dir); - ctnl_close(&cth); - - return ret; -} - -/* get_conntrack_handler */ -int get_conntrack(struct ctnl_tuple *tuple, int dir) -{ - struct ctnl_msg_handler h = { - .type = 0, - .handler = handler - }; - int ret; - - if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK, 0)) < 0) - return ret; - - ctnl_register_handler(&cth, &h); - - ret = ctnl_get_conntrack(&cth, tuple, dir); - ctnl_close(&cth); - - return ret; -} - -int dump_conntrack_table(int zero) -{ - int ret; - struct ctnl_msg_handler h = { - .type = IPCTNL_MSG_CT_NEW, /* Hm... really? */ - .handler = handler - }; - - if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK, 0)) < 0) - return ret; - - ctnl_register_handler(&cth, &h); - - if (zero) { - ret = ctnl_list_conntrack_zero_counters(&cth, AF_INET); - } else - ret = ctnl_list_conntrack(&cth, AF_INET); - - ctnl_close(&cth); - - return ret; -} - -static void event_sighandler(int s) -{ - fprintf(stdout, "Now closing conntrack event dumping...\n"); - ctnl_close(&cth); - exit(0); -} - -int event_conntrack(unsigned int event_mask) -{ - struct ctnl_msg_handler hnew = { - .type = IPCTNL_MSG_CT_NEW, - .handler = event_handler - }; - struct ctnl_msg_handler hdestroy = { - .type = IPCTNL_MSG_CT_DELETE, - .handler = event_handler - }; - int ret; - - if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK, event_mask)) < 0) - return ret; - - signal(SIGINT, event_sighandler); - ctnl_register_handler(&cth, &hnew); - ctnl_register_handler(&cth, &hdestroy); - ret = ctnl_event_conntrack(&cth, AF_INET); - ctnl_close(&cth); - - return 0; -} - -struct ctproto_handler *findproto(char *name) -{ - void *h = NULL; - struct list_head *i; - struct ctproto_handler *cur = NULL, *handler = NULL; - - if (!name) - return handler; - - lib_dir = getenv("CONNTRACK_LIB_DIR"); - if (!lib_dir) - lib_dir = CONNTRACK_LIB_DIR; - - list_for_each(i, &proto_list) { - cur = (struct ctproto_handler *) i; - if (strcmp(cur->name, name) == 0) { - handler = cur; - break; - } - } - - if (!handler) { - char path[sizeof("libct_proto_.so") - + strlen(name) + strlen(lib_dir)]; - sprintf(path, "%s/libct_proto_%s.so", lib_dir, name); - if (dlopen(path, RTLD_NOW)) - handler = findproto(name); - else - DEBUGP(stderr, "%s\n", dlerror()); - } - - return handler; -} - -void register_proto(struct ctproto_handler *h) -{ - if (strcmp(h->version, LIBCT_VERSION) != 0) { - fprintf(stderr, "plugin `%s': version %s (I'm %s)\n", - h->name, h->version, LIBCT_VERSION); - exit(1); - } - list_add(&h->head, &proto_list); -} - -void unregister_proto(struct ctproto_handler *h) -{ - list_del(&h->head); -} - -int dump_expect_list() -{ - struct ctnl_msg_handler h = { - .type = IPCTNL_MSG_EXP_NEW, - .handler = expect_handler - }; - int ret; - - if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK_EXP, 0)) < 0) - return ret; - - ctnl_register_handler(&cth, &h); - - ret = ctnl_list_expect(&cth, AF_INET); - ctnl_close(&cth); - - return ret; -} - -int flush_conntrack() -{ - int ret; - - if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK, 0)) < 0) - return ret; - - ret = ctnl_flush_conntrack(&cth); - ctnl_close(&cth); - - return ret; -} - -int get_expect(struct ctnl_tuple *tuple) -{ - struct ctnl_msg_handler h = { - .type = IPCTNL_MSG_EXP_NEW, - .handler = expect_handler - }; - int ret; - - if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK_EXP, 0)) < 0) - return 0; - - ctnl_register_handler(&cth, &h); - - ret = ctnl_get_expect(&cth, tuple); - ctnl_close(&cth); - - return ret; -} - -int create_expectation(struct ctnl_tuple *tuple, - struct ctnl_tuple *exptuple, - struct ctnl_tuple *mask, - unsigned long timeout) -{ - int ret; - - if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK_EXP, 0)) < 0) - return ret; - - - ret = ctnl_new_expect(&cth, tuple, exptuple, mask, timeout); - ctnl_close(&cth); - - return ret; -} - -int delete_expectation(struct ctnl_tuple *tuple) -{ - int ret; - - if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK_EXP, 0)) < 0) - return ret; - - ret = ctnl_del_expect(&cth, tuple); - ctnl_close(&cth); - - return ret; -} - -int event_expectation(unsigned int event_mask) -{ - struct ctnl_msg_handler hnew = { - .type = IPCTNL_MSG_EXP_NEW, - .handler = expect_handler - }; - struct ctnl_msg_handler hdestroy = { - .type = IPCTNL_MSG_EXP_DELETE, - .handler = expect_handler - }; - int ret; - - if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK_EXP, event_mask)) < 0) - return ret; - - ctnl_register_handler(&cth, &hnew); - ctnl_register_handler(&cth, &hdestroy); - ret = ctnl_event_expect(&cth, AF_INET); - ctnl_close(&cth); - - return ret; -} - -int flush_expectation() -{ - int ret; - - if ((ret = ctnl_open(&cth, NFNL_SUBSYS_CTNETLINK_EXP, 0)) < 0) - return ret; - - ret = ctnl_flush_expect(&cth); - ctnl_close(&cth); - - return ret; -} - -- cgit v1.2.3