From 9ab85762233756f1e828f7c4c6007d25ac26f494 Mon Sep 17 00:00:00 2001 From: "/C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=pablo/emailAddress=pablo@netfilter.org" Date: Tue, 12 Jul 2005 23:24:06 +0000 Subject: o Use conntrack netlink attributes: Major change o Kill action setting: Mask based dumping --- src/conntrack.c | 535 +++++++++++++++++++++++++++++++++++++------------------- src/libct.c | 526 +++++++++++++++++++++++++++++++++++-------------------- 2 files changed, 693 insertions(+), 368 deletions(-) (limited to 'src') diff --git a/src/conntrack.c b/src/conntrack.c index dfedf68..a6efd8b 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -41,7 +41,6 @@ #include #include #include -#include #include #include "libctnetlink.h" #include "libnfnetlink.h" @@ -62,34 +61,60 @@ #endif enum action { + CT_NONE = 0, + CT_LIST_BIT = 0, CT_LIST = (1 << CT_LIST_BIT), CT_CREATE_BIT = 1, CT_CREATE = (1 << CT_CREATE_BIT), + + CT_UPDATE_BIT = 2, + CT_UPDATE = (1 << CT_UPDATE_BIT), - CT_DELETE_BIT = 2, + CT_DELETE_BIT = 3, CT_DELETE = (1 << CT_DELETE_BIT), - CT_GET_BIT = 3, + CT_GET_BIT = 4, CT_GET = (1 << CT_GET_BIT), - CT_FLUSH_BIT = 4, + CT_FLUSH_BIT = 5, CT_FLUSH = (1 << CT_FLUSH_BIT), - CT_EVENT_BIT = 5, + CT_EVENT_BIT = 6, CT_EVENT = (1 << CT_EVENT_BIT), - CT_ACTION_BIT = 6, - CT_ACTION = (1 << CT_ACTION_BIT), - CT_VERSION_BIT = 7, CT_VERSION = (1 << CT_VERSION_BIT), CT_HELP_BIT = 8, CT_HELP = (1 << CT_HELP_BIT), + + EXP_LIST_BIT = 9, + EXP_LIST = (1 << EXP_LIST_BIT), + + EXP_CREATE_BIT = 10, + EXP_CREATE = (1 << EXP_CREATE_BIT), + + EXP_DELETE_BIT = 11, + EXP_DELETE = (1 << EXP_DELETE_BIT), + + EXP_GET_BIT = 12, + EXP_GET = (1 << EXP_GET_BIT), + + EXP_FLUSH_BIT = 13, + EXP_FLUSH = (1 << EXP_FLUSH_BIT), + + EXP_EVENT_BIT = 14, + EXP_EVENT = (1 << EXP_EVENT_BIT), }; -#define NUMBER_OF_CMD 9 +#define NUMBER_OF_CMD 15 + +static const char cmdflags[NUMBER_OF_CMD] += {'L','I','U','D','G','F','E','V','h','L','I','D','G','F','E'}; + +static const char cmd_need_param[NUMBER_OF_CMD] += {' ','x','x','x','x',' ',' ',' ',' ',' ','x','x','x',' ',' '}; enum options { CT_OPT_ORIG_SRC_BIT = 0, @@ -120,36 +145,34 @@ enum options { CT_OPT_ZERO_BIT = 7, CT_OPT_ZERO = (1 << CT_OPT_ZERO_BIT), - CT_OPT_DUMP_MASK_BIT = 8, - CT_OPT_DUMP_MASK = (1 << CT_OPT_DUMP_MASK_BIT), - - CT_OPT_GROUP_MASK_BIT = 9, - CT_OPT_GROUP_MASK = (1 << CT_OPT_GROUP_MASK_BIT), - - CT_OPT_EVENT_MASK_BIT = 10, + CT_OPT_EVENT_MASK_BIT = 8, CT_OPT_EVENT_MASK = (1 << CT_OPT_EVENT_MASK_BIT), - CT_OPT_TUPLE_SRC_BIT = 11, - CT_OPT_TUPLE_SRC = (1 << CT_OPT_TUPLE_SRC_BIT), + CT_OPT_EXP_SRC_BIT = 9, + CT_OPT_EXP_SRC = (1 << CT_OPT_EXP_SRC_BIT), - CT_OPT_TUPLE_DST_BIT = 12, - CT_OPT_TUPLE_DST = (1 << CT_OPT_TUPLE_DST_BIT), + CT_OPT_EXP_DST_BIT = 10, + CT_OPT_EXP_DST = (1 << CT_OPT_EXP_DST_BIT), - CT_OPT_MASK_SRC_BIT = 13, + CT_OPT_MASK_SRC_BIT = 11, CT_OPT_MASK_SRC = (1 << CT_OPT_MASK_SRC_BIT), - CT_OPT_MASK_DST_BIT = 14, + CT_OPT_MASK_DST_BIT = 12, CT_OPT_MASK_DST = (1 << CT_OPT_MASK_DST_BIT), + + CT_OPT_NATRANGE_BIT = 13, + CT_OPT_NATRANGE = (1 << CT_OPT_NATRANGE_BIT), }; -#define NUMBER_OF_OPT 15 +#define NUMBER_OF_OPT 14 static const char optflags[NUMBER_OF_OPT] -= { 's', 'd', 'r', 'q', 'p', 't', 'u', 'z','m','g','e', '[',']','{','}'}; += {'s','d','r','q','p','t','u','z','e','[',']','{','}','a'}; static struct option original_opts[] = { {"dump", 2, 0, 'L'}, {"create", 1, 0, 'I'}, {"delete", 1, 0, 'D'}, + {"update", 1, 0, 'U'}, {"get", 1, 0, 'G'}, {"flush", 1, 0, 'F'}, {"event", 1, 0, 'E'}, @@ -164,13 +187,12 @@ static struct option original_opts[] = { {"timeout", 1, 0, 't'}, {"status", 1, 0, 'u'}, {"zero", 0, 0, 'z'}, - {"dump-mask", 1, 0, 'm'}, - {"groups", 1, 0, 'g'}, {"event-mask", 1, 0, 'e'}, {"tuple-src", 1, 0, '['}, {"tuple-dst", 1, 0, ']'}, {"mask-src", 1, 0, '{'}, {"mask-dst", 1, 0, '}'}, + {"nat-range", 1, 0, 'a'}, {0, 0, 0, 0} }; @@ -188,22 +210,29 @@ static unsigned int global_option_offset = 0; * optional */ +/* FIXME: I'd need something different than this table to catch up some + * particular cases. Better later Pablo */ static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = /* Well, it's better than "Re: Linux vs FreeBSD" */ { - /* -s -d -r -q -p -t -u -z -m -g -e ts td ms md */ -/*LIST*/ {'x','x','x','x','x','x','x',' ','x','x','x','x','x','x','x'}, -/*CREATE*/ {'+','+','+','+','+','+','+','x','x','x','x','+','+','+','+'}, -/*DELETE*/ {' ',' ',' ',' ',' ','x','x','x','x','x','x',' ',' ',' ',' '}, -/*GET*/ {' ',' ',' ',' ','+','x','x','x','x','x','x',' ',' ',' ',' '}, -/*FLUSH*/ {'x','x','x','x','x','x','x','x','x','x','x','x','x','x','x'}, -/*EVENT*/ {'x','x','x','x','x','x','x','x','x',' ','x','x','x','x','x'}, -/*ACTION*/ {'x','x','x','x','x','x','x','x',' ','x',' ','x','x','x','x'}, -/*VERSION*/ {'x','x','x','x','x','x','x','x','x','x','x','x','x','x','x'}, -/*HELP*/ {'x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x'}, + /* -s -d -r -q -p -t -u -z -e -x -y -k -l -a */ +/*CT_LIST*/ {'x','x','x','x','x','x','x',' ','x','x','x','x','x','x'}, +/*CT_CREATE*/ {' ',' ',' ',' ','+','+','+','x','x','x','x','x','x',' '}, +/*CT_UPDATE*/ {' ',' ',' ',' ','+','+','+','x','x','x','x','x','x','x'}, +/*CT_DELETE*/ {' ',' ',' ',' ',' ','x','x','x','x','x','x','x','x','x'}, +/*CT_GET*/ {' ',' ',' ',' ','+','x','x','x','x','x','x','x','x','x'}, +/*CT_FLUSH*/ {'x','x','x','x','x','x','x','x','x','x','x','x','x','x'}, +/*CT_EVENT*/ {'x','x','x','x','x','x','x','x',' ','x','x','x','x','x'}, +/*VERSION*/ {'x','x','x','x','x','x','x','x','x','x','x','x','x','x'}, +/*HELP*/ {'x','x','x','x',' ','x','x','x','x','x','x','x','x','x'}, +/*EXP_LIST*/ {'x','x','x','x','x','x','x','x','x','x','x','x','x','x'}, +/*EXP_CREATE*/{'+','+',' ',' ','+','+',' ','x','x','+','+','+','+','x'}, +/*EXP_DELETE*/{'+','+',' ',' ','+','x','x','x','x','x','x','x','x','x'}, +/*EXP_GET*/ {'+','+',' ',' ','+','x','x','x','x','x','x','x','x','x'}, +/*EXP_FLUSH*/ {'x','x','x','x','x','x','x','x','x','x','x','x','x','x'}, +/*EXP_EVENT*/ {'x','x','x','x','x','x','x','x','x','x','x','x','x','x'}, }; -/* FIXME: hardcoded!, this must be defined during compilation time */ char *lib_dir = CONNTRACK_LIB_DIR; LIST_HEAD(proto_list); @@ -258,6 +287,22 @@ exit_error(enum exittype status, char *msg, ...) exit(status); } +static void +generic_cmd_check(int command, int options) +{ + int i; + + for (i = 0; i < NUMBER_OF_CMD; i++) { + if (!(command & (1< %u.%u.%u.%u:%hu\n", - tp, tp->dst.protonum, - NIPQUAD(tp->src.ip), ntohs(tp->src.u.all), - NIPQUAD(tp->dst.ip), ntohs(tp->dst.u.all)); + tp, tp->protonum, + NIPQUAD(tp->src.v4), ntohs(tp->l4src.all), + NIPQUAD(tp->dst.v4), ntohs(tp->l4dst.all)); } -void not_implemented_yet() -{ - exit_error(OTHER_PROBLEM, "Sorry, not implemented yet :(\n"); -} - - #define PARSE_STATUS 0 -#define PARSE_GROUP 1 -#define PARSE_EVENT 2 -#define PARSE_DUMP 3 -#define PARSE_MAX PARSE_DUMP+1 +#define PARSE_EVENT 1 +#define PARSE_MAX 2 static struct parse_parameter { - char *parameter[10]; + char *parameter[5]; size_t size; - unsigned int value[10]; + unsigned int value[5]; } parse_array[PARSE_MAX] = { - { {"EXPECTED", "ASSURED", "SEEN_REPLY", "CONFIRMED", "SNAT", "DNAT", - "SEQ_ADJUST", "UNSET"}, - 8, - { IPS_EXPECTED, IPS_ASSURED, IPS_SEEN_REPLY, IPS_CONFIRMED, - IPS_SRC_NAT, IPS_DST_NAT, IPS_SEQ_ADJUST, 0} }, - { {"ALL", "TCP", "UDP", "ICMP"}, - 4, - {~0U, NFGRP_IPV4_CT_TCP, NFGRP_IPV4_CT_UDP, NFGRP_IPV4_CT_ICMP} }, - { {"ALL", "NEW", "RELATED", "DESTROY", "REFRESH", "STATUS", - "PROTOINFO", "HELPER", "HELPINFO", "NATINFO"}, - 10, - {~0U, IPCT_NEW, IPCT_RELATED, IPCT_DESTROY, IPCT_REFRESH, IPCT_STATUS, - IPCT_PROTOINFO, IPCT_HELPER, IPCT_HELPINFO, IPCT_NATINFO} }, - { {"ALL", "TUPLE", "STATUS", "TIMEOUT", "PROTOINFO", "HELPINFO", - "COUNTERS", "MARK"}, 8, - {~0U, DUMP_TUPLE, DUMP_STATUS, DUMP_TIMEOUT, DUMP_PROTOINFO, - DUMP_HELPINFO, DUMP_COUNTERS, DUMP_MARK} } + { {"ASSURED", "SEEN_REPLY", "UNSET", "SRC_NAT", "DST_NAT"}, 5, + { IPS_ASSURED, IPS_SEEN_REPLY, 0, + IPS_SRC_NAT_DONE, IPS_DST_NAT_DONE} }, + { {"ALL", "NEW", "UPDATES", "DESTROY"}, 4, + {~0U, NF_NETLINK_CONNTRACK_NEW, NF_NETLINK_CONNTRACK_UPDATE, + NF_NETLINK_CONNTRACK_DESTROY} }, }; static int @@ -425,6 +454,14 @@ parse_parameter(const char *arg, unsigned int *status, int parse_type) exit_error(PARAMETER_PROBLEM, "Bad parameter `%s'", arg); } +static void +add_command(int *cmd, const int newcmd, const int othercmds) +{ + if (*cmd & (~othercmds)) + exit_error(PARAMETER_PROBLEM, "Invalid commands combination\n"); + *cmd |= newcmd; +} + unsigned int check_type(int argc, char *argv[]) { char *table = NULL; @@ -515,15 +552,90 @@ int iptables_insmod(const char *modname, const char *modprobe) return -1; } +/* Shamelessly stolen from libipt_DNAT ;). Ranges expected in network order. */ +static void +nat_parse(char *arg, int portok, struct ctnl_nat *range) +{ + char *colon, *dash, *error; + unsigned long ip; + + memset(range, 0, sizeof(range)); + colon = strchr(arg, ':'); + + if (colon) { + int port; + + if (!portok) + exit_error(PARAMETER_PROBLEM, + "Need TCP or UDP with port specification"); + + port = atoi(colon+1); + if (port == 0 || port > 65535) + exit_error(PARAMETER_PROBLEM, + "Port `%s' not valid\n", colon+1); + + error = strchr(colon+1, ':'); + if (error) + exit_error(PARAMETER_PROBLEM, + "Invalid port:port syntax - use dash\n"); + + dash = strchr(colon, '-'); + if (!dash) { + range->l4min.tcp.port + = range->l4max.tcp.port + = htons(port); + } else { + int maxport; + + maxport = atoi(dash + 1); + if (maxport == 0 || maxport > 65535) + exit_error(PARAMETER_PROBLEM, + "Port `%s' not valid\n", dash+1); + if (maxport < port) + // People are stupid. + exit_error(PARAMETER_PROBLEM, + "Port range `%s' funky\n", colon+1); + range->l4min.tcp.port = htons(port); + range->l4max.tcp.port = htons(maxport); + } + // Starts with a colon? No IP info... + if (colon == arg) + return; + *colon = '\0'; + } + + dash = strchr(arg, '-'); + if (colon && dash && dash > colon) + dash = NULL; + + if (dash) + *dash = '\0'; + + ip = inet_addr(arg); + if (!ip) + exit_error(PARAMETER_PROBLEM, "Bad IP address `%s'\n", + arg); + range->min_ip = ip; + if (dash) { + ip = inet_addr(dash+1); + if (!ip) + exit_error(PARAMETER_PROBLEM, "Bad IP address `%s'\n", + dash+1); + range->max_ip = ip; + } else + range->max_ip = range->min_ip; +} + void usage(char *prog) { fprintf(stdout, "Tool to manipulate conntrack and expectations. Version %s\n", VERSION); fprintf(stdout, "Usage: %s [commands] [options]\n", prog); fprintf(stdout, "\n"); fprintf(stdout, "Commands:\n"); fprintf(stdout, "-L [table] [-z] List conntrack or expectation table\n"); -fprintf(stdout, "-G [table] parameters Get conntrack or expectation\n"); +fprintf(stdout, "-G [table] parameters Get conntrack or expectation\n"); fprintf(stdout, "-D [table] parameters Delete conntrack or expectation\n"); fprintf(stdout, "-I [table] parameters Create a conntrack or expectation\n"); +fprintf(stdout, "-U [table] parameters Update a conntrack\n"); fprintf(stdout, "-E [table] [options] Show events\n"); fprintf(stdout, "-F [table] Flush table\n"); fprintf(stdout, "-A [table] [options] Set action\n"); @@ -535,108 +647,127 @@ fprintf(stdout, "--reply-src ip Source addres from reply direction\n"); fprintf(stdout, "--reply-dst ip Destination address from reply direction\n"); fprintf(stdout, "--tuple-src ip Source address in expect tuple\n"); fprintf(stdout, "--tuple-dst ip Destination address in expect tuple\n"); -fprintf(stdout, "--mask-src ip Source mask in expect\n"); -fprintf(stdout, "--mask-dst ip Destination mask in expect\n"); +fprintf(stdout, "--mask-src ip Source mask address for expectation\n"); +fprintf(stdout, "--mask-dst ip Destination mask address for expectations\n"); fprintf(stdout, "-p proto Layer 4 Protocol\n"); fprintf(stdout, "-t timeout Set timeout\n"); fprintf(stdout, "-u status Set status\n"); fprintf(stdout, "-m dumpmask Set dump mask\n"); fprintf(stdout, "-g groupmask Set group mask\n"); fprintf(stdout, "-e eventmask Set event mask\n"); +fprintf(stdout, "-a min_ip[-max_ip] NAT ip range\n"); fprintf(stdout, "-z Zero Counters\n"); } int main(int argc, char *argv[]) { - int c; + char c; unsigned int command = 0, options = 0; - struct ip_conntrack_tuple orig, reply, tuple, mask, *o = NULL, *r = NULL; + struct ctnl_tuple orig, reply, mask, *o = NULL, *r = NULL; + struct ctnl_tuple exptuple; struct ctproto_handler *h = NULL; - union ip_conntrack_proto proto; + union ctnl_protoinfo proto; + struct ctnl_nat range; unsigned long timeout = 0; - unsigned int status = 0, group_mask = 0; + unsigned int status = IPS_CONFIRMED; unsigned long id = 0; unsigned int type = 0, dump_mask = 0, extra_flags = 0, event_mask = 0; + int manip = -1; int res = 0, retry = 2; - memset(&proto, 0, sizeof(union ip_conntrack_proto)); - memset(&orig, 0, sizeof(struct ip_conntrack_tuple)); - memset(&reply, 0, sizeof(struct ip_conntrack_tuple)); - orig.dst.dir = IP_CT_DIR_ORIGINAL; - reply.dst.dir = IP_CT_DIR_REPLY; + memset(&proto, 0, sizeof(union ctnl_protoinfo)); + memset(&orig, 0, sizeof(struct ctnl_tuple)); + memset(&reply, 0, sizeof(struct ctnl_tuple)); + memset(&mask, 0, sizeof(struct ctnl_tuple)); + memset(&range, 0, sizeof(struct ctnl_nat)); while ((c = getopt_long(argc, argv, - "L::I::D::G::E::A::F::hVs:d:r:q:p:t:u:m:g:e:z[:]:{:}:", + "L::I::U::D::G::E::A::F::hVs:d:r:q:p:t:u:e:a:z[:]:{:}:", opts, NULL)) != -1) { switch(c) { case 'L': - command |= CT_LIST; type = check_type(argc, argv); + if (type == 0) + add_command(&command, CT_LIST, CT_NONE); + else if (type == 1) + add_command(&command, EXP_LIST, CT_NONE); break; case 'I': - command |= CT_CREATE; type = check_type(argc, argv); + if (type == 0) + add_command(&command, CT_CREATE, CT_NONE); + else if (type == 1) + add_command(&command, EXP_CREATE, CT_NONE); + break; + case 'U': + type = check_type(argc, argv); + if (type == 0) + add_command(&command, CT_UPDATE, CT_NONE); + else + exit_error(PARAMETER_PROBLEM, "Can't update " + "expectations"); break; case 'D': - command |= CT_DELETE; type = check_type(argc, argv); + if (type == 0) + add_command(&command, CT_DELETE, CT_NONE); + else if (type == 1) + add_command(&command, EXP_DELETE, CT_NONE); break; case 'G': - command |= CT_GET; type = check_type(argc, argv); + if (type == 0) + add_command(&command, CT_GET, CT_NONE); + else if (type == 1) + add_command(&command, EXP_GET, CT_NONE); break; case 'F': - command |= CT_FLUSH; type = check_type(argc, argv); + if (type == 0) + add_command(&command, CT_FLUSH, CT_NONE); + else if (type == 1) + add_command(&command, EXP_FLUSH, CT_NONE); break; case 'E': - command |= CT_EVENT; - type = check_type(argc, argv); - break; - case 'A': - command |= CT_ACTION; type = check_type(argc, argv); + if (type == 0) + add_command(&command, CT_EVENT, CT_NONE); + else if (type == 1) + add_command(&command, EXP_EVENT, CT_NONE); break; case 'V': - command |= CT_VERSION; + add_command(&command, CT_VERSION, CT_NONE); break; case 'h': - command |= CT_HELP; - break; - case 'm': - if (!optarg) - continue; - - options |= CT_OPT_DUMP_MASK; - parse_parameter(optarg, &dump_mask, PARSE_DUMP); + add_command(&command, CT_HELP, CT_NONE); break; case 's': options |= CT_OPT_ORIG_SRC; if (optarg) - orig.src.ip = inet_addr(optarg); + orig.src.v4 = inet_addr(optarg); break; case 'd': options |= CT_OPT_ORIG_DST; if (optarg) - orig.dst.ip = inet_addr(optarg); + orig.dst.v4 = inet_addr(optarg); break; case 'r': options |= CT_OPT_REPL_SRC; if (optarg) - reply.src.ip = inet_addr(optarg); + reply.src.v4 = inet_addr(optarg); break; case 'q': options |= CT_OPT_REPL_DST; if (optarg) - reply.dst.ip = inet_addr(optarg); + reply.dst.v4 = inet_addr(optarg); break; case 'p': options |= CT_OPT_PROTO; h = findproto(optarg); if (!h) exit_error(PARAMETER_PROBLEM, "proto needed\n"); - orig.dst.protonum = h->protonum; - reply.dst.protonum = h->protonum; + orig.protonum = h->protonum; + reply.protonum = h->protonum; opts = merge_options(opts, h->opts, &h->option_offset); break; @@ -646,20 +777,13 @@ int main(int argc, char *argv[]) timeout = atol(optarg); break; case 'u': { - /* FIXME: NAT stuff, later... */ if (!optarg) continue; options |= CT_OPT_STATUS; parse_parameter(optarg, &status, PARSE_STATUS); - /* Just insert confirmed conntracks */ - status |= IPS_CONFIRMED; break; } - case 'g': - options |= CT_OPT_GROUP_MASK; - parse_parameter(optarg, &group_mask, PARSE_GROUP); - break; case 'e': options |= CT_OPT_EVENT_MASK; parse_parameter(optarg, &event_mask, PARSE_EVENT); @@ -667,30 +791,35 @@ int main(int argc, char *argv[]) case 'z': options |= CT_OPT_ZERO; break; - case '[': - options |= CT_OPT_TUPLE_SRC; + case 'k': + options |= CT_OPT_MASK_SRC; if (optarg) - tuple.src.ip = inet_addr(optarg); + mask.src.v4 = inet_addr(optarg); break; - case ']': - options |= CT_OPT_TUPLE_DST; + case 'l': + options |= CT_OPT_MASK_DST; if (optarg) - tuple.dst.ip = inet_addr(optarg); + mask.dst.v4 = inet_addr(optarg); break; - case '{': - options |= CT_OPT_MASK_SRC; + case 'x': + options |= CT_OPT_EXP_SRC; if (optarg) - mask.src.ip = inet_addr(optarg); + exptuple.src.v4 = inet_addr(optarg); break; - case '}': - options |= CT_OPT_MASK_DST; + case 'y': + options |= CT_OPT_EXP_DST; if (optarg) - mask.dst.ip = inet_addr(optarg); + exptuple.dst.v4 = inet_addr(optarg); + break; + case 'a': + options |= CT_OPT_NATRANGE; + nat_parse(optarg, 1, &range); break; default: - if (h && h->parse && !h->parse(c - h->option_offset, - argv, &orig, &reply, - &proto, &extra_flags)) + if (h && h->parse_opts + &&!h->parse_opts(c - h->option_offset, argv, &orig, + &reply, &mask, &proto, + &extra_flags)) exit_error(PARAMETER_PROBLEM, "parse error\n"); /* Unknown argument... */ @@ -703,10 +832,12 @@ int main(int argc, char *argv[]) } } + generic_cmd_check(command, options); generic_opt_check(command, options); if (!(command & CT_HELP) - && h && h->final_check && !h->final_check(extra_flags)) { + && h && h->final_check + && !h->final_check(extra_flags, &orig, &reply)) { usage(argv[0]); extension_help(h); exit_error(PARAMETER_PROBLEM, "Missing protocol arguments!\n"); @@ -716,71 +847,115 @@ int main(int argc, char *argv[]) retry--; switch(command) { case CT_LIST: - if (type == 0) { - if (options & CT_OPT_ZERO) - res = dump_conntrack_table(1); - else - res = dump_conntrack_table(0); - } else - res = dump_expect_list(); + if (options & CT_OPT_ZERO) + res = dump_conntrack_table(1); + else + res = dump_conntrack_table(0); + break; + + case EXP_LIST: + res = dump_expect_list(); break; case CT_CREATE: - if (type == 0) + if ((options & CT_OPT_ORIG) + && !(options & CT_OPT_REPL)) { + reply.src.v4 = orig.dst.v4; + reply.dst.v4 = orig.src.v4; + } else if (!(options & CT_OPT_ORIG) + && (options & CT_OPT_REPL)) { + orig.src.v4 = reply.dst.v4; + orig.dst.v4 = reply.src.v4; + } + if (options & CT_OPT_NATRANGE) res = create_conntrack(&orig, &reply, timeout, - &proto, status); + &proto, status, &range); else - res = create_expect(&tuple, &mask, &orig, - &reply, timeout); + res = create_conntrack(&orig, &reply, timeout, + &proto, status, NULL); + break; + + case EXP_CREATE: + if (options & CT_OPT_ORIG) + res = create_expectation(&orig, + CTA_TUPLE_ORIG, + &exptuple, + &mask, + timeout); + else if (options & CT_OPT_REPL) + res = create_expectation(&reply, + CTA_TUPLE_RPLY, + &exptuple, + &mask, + timeout); + break; + + case CT_UPDATE: + if ((options & CT_OPT_ORIG) + && !(options & CT_OPT_REPL)) { + reply.src.v4 = orig.dst.v4; + reply.dst.v4 = orig.src.v4; + } else if (!(options & CT_OPT_ORIG) + && (options & CT_OPT_REPL)) { + orig.src.v4 = reply.dst.v4; + orig.dst.v4 = reply.src.v4; + } + res = update_conntrack(&orig, &reply, timeout, + &proto, status); break; case CT_DELETE: - if (type == 0) { - if (options & CT_OPT_ORIG) - res =delete_conntrack(&orig, CTA_ORIG, - id); - else if (options & CT_OPT_REPL) - res = delete_conntrack(&reply, CTA_RPLY, - id); - } else - not_implemented_yet(); + if (options & CT_OPT_ORIG) + res = delete_conntrack(&orig, CTA_TUPLE_ORIG, + CTNL_DIR_ORIGINAL); + else if (options & CT_OPT_REPL) + res = delete_conntrack(&reply, CTA_TUPLE_RPLY, + CTNL_DIR_REPLY); break; - + + case EXP_DELETE: + if (options & CT_OPT_ORIG) + res = delete_expectation(&orig, CTA_TUPLE_ORIG); + else if (options & CT_OPT_REPL) + res = delete_expectation(&reply, CTA_TUPLE_RPLY); + break; + case CT_GET: - if (type == 0) { - if (options & CT_OPT_ORIG) - res = get_conntrack(&orig, CTA_ORIG, - id); - else if (options & CT_OPT_REPL) - res = get_conntrack(&reply, CTA_RPLY, - id); - } else - not_implemented_yet(); + if (options & CT_OPT_ORIG) + res = get_conntrack(&orig, CTA_TUPLE_ORIG, id); + else if (options & CT_OPT_REPL) + res = get_conntrack(&reply, CTA_TUPLE_RPLY, id); break; - + + case EXP_GET: + if (options & CT_OPT_ORIG) + res = get_expect(&orig, CTA_TUPLE_ORIG); + else if (options & CT_OPT_REPL) + res = get_expect(&reply, CTA_TUPLE_RPLY); + break; + case CT_FLUSH: - if (type == 0) - res = flush_conntrack(); - else - not_implemented_yet(); + res = flush_conntrack(); + break; + + case EXP_FLUSH: + res = flush_expectation(); break; case CT_EVENT: - if (type == 0) { - if (options & CT_OPT_GROUP_MASK) - res = event_conntrack(group_mask); - else - res = event_conntrack(~0U); - } else - not_implemented_yet(); - - case CT_ACTION: - if (type == 0) - if (options & CT_OPT_DUMP_MASK) - res = set_mask(dump_mask, 0); - else if (options & CT_OPT_EVENT_MASK) - res = set_mask(event_mask, 1); + if (options & CT_OPT_EVENT_MASK) + res = event_conntrack(event_mask); + else + res = event_conntrack(~0U); break; + + case EXP_EVENT: + if (options & CT_OPT_EVENT_MASK) + res = event_expectation(event_mask); + else + res = event_expectation(~0U); + break; + case CT_VERSION: fprintf(stdout, "%s v%s\n", PROGNAME, VERSION); break; diff --git a/src/libct.c b/src/libct.c index 0555ec8..94e5b24 100644 --- a/src/libct.c +++ b/src/libct.c @@ -1,5 +1,5 @@ /* - * (C) 2005 by Pablo Neira Ayuso , + * (C) 2005 by Pablo Neira Ayuso * Harald Welte * * This program is free software; you can redistribute it and/or modify @@ -11,9 +11,13 @@ #include #include #include +#include #include -#include +/* From kernel.h */ +#define INT_MAX ((int)(~0U>>1)) +#define INT_MIN (-INT_MAX - 1) #include +#include #include "libctnetlink.h" #include "libnfnetlink.h" #include "linux_list.h" @@ -25,6 +29,7 @@ #define DEBUGP #endif +static struct ctnl_handle cth; extern char *lib_dir; extern struct list_head proto_list; extern char *proto2str[]; @@ -37,89 +42,192 @@ static void print_status(unsigned int status) fprintf(stdout, "[UNREPLIED] "); } +static void parse_ip(struct nfattr *attr, struct ctnl_tuple *tuple) +{ + struct nfattr *tb[CTA_IP_MAX]; + + memset(tb, 0, CTA_IP_MAX * sizeof(struct nfattr *)); + + nfnl_parse_attr(tb, CTA_IP_MAX, NFA_DATA(attr), NFA_PAYLOAD(attr)); + if (tb[CTA_IP_V4_SRC-1]) + tuple->src.v4 = *(u_int32_t *)NFA_DATA(tb[CTA_IP_V4_SRC-1]); + + if (tb[CTA_IP_V4_DST-1]) + tuple->dst.v4 = *(u_int32_t *)NFA_DATA(tb[CTA_IP_V4_DST-1]); +} + +static void parse_proto(struct nfattr *attr, struct ctnl_tuple *tuple) +{ + struct nfattr *tb[CTA_PROTO_MAX]; + struct ctproto_handler *h; + int dir = CTNL_DIR_REPLY; + + memset(tb, 0, CTA_PROTO_MAX * sizeof(struct nfattr *)); + + nfnl_parse_attr(tb, CTA_IP_MAX, NFA_DATA(attr), NFA_PAYLOAD(attr)); + if (tb[CTA_PROTO_NUM-1]) + tuple->protonum = *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_NUM-1]); + + h = findproto(proto2str[tuple->protonum]); + if (h && h->parse_proto) + h->parse_proto(tb, tuple); +} + +static void parse_tuple(struct nfattr *attr, struct ctnl_tuple *tuple) +{ + struct nfattr *tb[CTA_TUPLE_MAX]; + + memset(tb, 0, CTA_TUPLE_MAX*sizeof(struct nfattr *)); + + nfnl_parse_attr(tb, CTA_TUPLE_MAX, NFA_DATA(attr), NFA_PAYLOAD(attr)); + if (tb[CTA_TUPLE_IP-1]) + parse_ip(tb[CTA_TUPLE_IP-1], tuple); + if (tb[CTA_TUPLE_PROTO-1]) + parse_proto(tb[CTA_TUPLE_PROTO-1], tuple); +} + +static void parse_protoinfo(struct nfattr *attr, struct ctnl_conntrack *ct) +{ + struct nfattr *tb[CTA_PROTOINFO_MAX]; + struct ctproto_handler *h; + + memset(tb, 0, CTA_PROTOINFO_MAX*sizeof(struct nfattr *)); + + nfnl_parse_attr(tb,CTA_PROTOINFO_MAX,NFA_DATA(attr), NFA_PAYLOAD(attr)); + + h = findproto(proto2str[ct->tuple[CTNL_DIR_ORIGINAL].protonum]); + if (h && h->parse_protoinfo) + h->parse_protoinfo(tb, ct); +} + +static void parse_counters(struct nfattr *attr, struct ctnl_conntrack *ct, + enum ctattr_type parent) +{ + struct nfattr *tb[CTA_COUNTERS_MAX]; + + memset(tb, 0, CTA_COUNTERS_MAX*sizeof(struct nfattr *)); + + nfnl_parse_attr(tb, CTA_COUNTERS_MAX, NFA_DATA(attr),NFA_PAYLOAD(attr)); + if (tb[CTA_COUNTERS_PACKETS_ORIG-1]) + ct->counters[CTNL_DIR_ORIGINAL].packets + = *(u_int64_t *)NFA_DATA(tb[CTA_COUNTERS_PACKETS_ORIG-1]); + if (tb[CTA_COUNTERS_BYTES_ORIG-1]) + ct->counters[CTNL_DIR_ORIGINAL].bytes + = *(u_int64_t *)NFA_DATA(tb[CTA_COUNTERS_BYTES_ORIG-1]); + if (tb[CTA_COUNTERS_PACKETS_RPLY-1]) + ct->counters[CTNL_DIR_REPLY].packets + = *(u_int64_t *)NFA_DATA(tb[CTA_COUNTERS_PACKETS_RPLY-1]); + if (tb[CTA_COUNTERS_BYTES_RPLY-1]) + ct->counters[CTNL_DIR_REPLY].bytes + = *(u_int64_t *)NFA_DATA(tb[CTA_COUNTERS_BYTES_RPLY-1]); +} + +#define STATUS 1 +#define PROTOINFO 2 +#define TIMEOUT 4 +#define MARK 8 +#define COUNTERS 16 +#define USE 32 + static int handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void *arg) { struct nfgenmsg *nfmsg; struct nfattr *nfa; - int min_len = 0; + int min_len = sizeof(struct nfgenmsg);; struct ctproto_handler *h = NULL; struct nfattr *attr = NFM_NFA(NLMSG_DATA(nlh)); int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); + struct ctnl_conntrack ct; + unsigned int flags = 0; - struct ip_conntrack_tuple *orig, *reply; - struct cta_counters *ctr; - unsigned long *status, *timeout; - struct cta_proto *proto; - unsigned long *id, *mark; - - DEBUGP("netlink header\n"); - DEBUGP("len: %d type: %d flags: %d seq: %d pid: %d\n", - nlh->nlmsg_len, nlh->nlmsg_type, nlh->nlmsg_flags, - nlh->nlmsg_seq, nlh->nlmsg_pid); + memset(&ct, 0, sizeof(struct ctnl_conntrack)); nfmsg = NLMSG_DATA(nlh); - DEBUGP("nfmsg->nfgen_family: %d\n", nfmsg->nfgen_family); +// min_len = sizeof(struct nfgenmsg); - min_len = sizeof(struct nfgenmsg); if (nlh->nlmsg_len < min_len) return -EINVAL; - DEBUGP("size:%d\n", nlh->nlmsg_len); - while (NFA_OK(attr, attrlen)) { switch(attr->nfa_type) { - case CTA_ORIG: - orig = NFA_DATA(attr); - fprintf(stdout, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ", - NIPQUAD(orig->src.ip), - NIPQUAD(orig->dst.ip)); - h = findproto(proto2str[orig->dst.protonum]); - if (h && h->print_tuple) - h->print_tuple(orig); + case CTA_TUPLE_ORIG: + parse_tuple(attr, &ct.tuple[CTNL_DIR_ORIGINAL]); break; - case CTA_RPLY: - reply = NFA_DATA(attr); - fprintf(stdout, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ", - NIPQUAD(reply->src.ip), - NIPQUAD(reply->dst.ip)); - h = findproto(proto2str[reply->dst.protonum]); - if (h && h->print_tuple) - h->print_tuple(reply); + case CTA_TUPLE_RPLY: + parse_tuple(attr, &ct.tuple[CTNL_DIR_REPLY]); break; case CTA_STATUS: - status = NFA_DATA(attr); - print_status(*status); + ct.status = *(unsigned int *)NFA_DATA(attr); + flags |= STATUS; break; case CTA_PROTOINFO: - proto = NFA_DATA(attr); - if (proto2str[proto->num_proto]) { - fprintf(stdout, "%s %d ", proto2str[proto->num_proto], proto->num_proto); - h = findproto(proto2str[proto->num_proto]); - if (h && h->print_proto) - h->print_proto(&proto->proto); - } else - fprintf(stdout, "unknown %d ", proto->num_proto); + parse_protoinfo(attr, &ct); + flags |= PROTOINFO; break; case CTA_TIMEOUT: - timeout = NFA_DATA(attr); - fprintf(stdout, "timeout=%lu ", *timeout); + ct.timeout = *(unsigned long *)NFA_DATA(attr); + flags |= TIMEOUT; break; case CTA_MARK: - mark = NFA_DATA(attr); - fprintf(stdout, "mark=%lu ", *mark); + ct.mark = *(unsigned long *)NFA_DATA(attr); + flags |= MARK; break; case CTA_COUNTERS: - ctr = NFA_DATA(attr); - fprintf(stdout, "orig_packets=%llu orig_bytes=%llu, " - "reply_packets=%llu reply_bytes=%llu ", - ctr->orig.packets, ctr->orig.bytes, - ctr->reply.packets, ctr->reply.bytes); + parse_counters(attr, &ct, CTA_COUNTERS-1); + flags |= COUNTERS; + break; + case CTA_USE: + ct.use = *(unsigned int *)NFA_DATA(attr); + flags |= USE; break; } - DEBUGP("nfa->nfa_type: %d\n", attr->nfa_type); - DEBUGP("nfa->nfa_len: %d\n", attr->nfa_len); attr = NFA_NEXT(attr, attrlen); } + + fprintf(stdout, "%-8s %u ", + proto2str[ct.tuple[CTNL_DIR_ORIGINAL].protonum] == NULL ? + "unknown" : proto2str[ct.tuple[CTNL_DIR_ORIGINAL].protonum], + ct.tuple[CTNL_DIR_ORIGINAL].protonum); + + if (flags & TIMEOUT) + fprintf(stdout, "%lu ", ct.timeout); + + h = findproto(proto2str[ct.tuple[CTNL_DIR_ORIGINAL].protonum]); + if ((flags & PROTOINFO) && h && h->print_protoinfo) + h->print_protoinfo(&ct.protoinfo); + + fprintf(stdout, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ", + NIPQUAD(ct.tuple[CTNL_DIR_ORIGINAL].src.v4), + NIPQUAD(ct.tuple[CTNL_DIR_ORIGINAL].dst.v4)); + + if (h && h->print_proto) + h->print_proto(&ct.tuple[CTNL_DIR_ORIGINAL]); + + if (flags & COUNTERS) + fprintf(stdout, "packets=%llu bytes=%llu ", + ct.counters[CTNL_DIR_ORIGINAL].packets, + ct.counters[CTNL_DIR_ORIGINAL].bytes); + + fprintf(stdout, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ", + NIPQUAD(ct.tuple[CTNL_DIR_REPLY].src.v4), + NIPQUAD(ct.tuple[CTNL_DIR_REPLY].dst.v4)); + + h = findproto(proto2str[ct.tuple[CTNL_DIR_ORIGINAL].protonum]); + if (h && h->print_proto) + h->print_proto(&ct.tuple[CTNL_DIR_REPLY]); + + if (flags & COUNTERS) + fprintf(stdout, "packets=%llu bytes=%llu ", + ct.counters[CTNL_DIR_REPLY].packets, + ct.counters[CTNL_DIR_REPLY].bytes); + + print_status(ct.status); + + if (flags & MARK) + fprintf(stdout, "mark=%lu ", ct.mark); + if (flags & USE) + fprintf(stdout, "use=%u ", ct.use); + fprintf(stdout, "\n"); return 0; @@ -148,140 +256,133 @@ static int event_handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, return handler(sock, nlh, arg); } +void parse_expect(struct nfattr *attr, struct ctnl_tuple *tuple, + struct ctnl_tuple *mask, unsigned long *timeout) +{ + struct nfattr *tb[CTA_EXPECT_MAX]; + + memset(tb, 0, CTA_EXPECT_MAX*sizeof(struct nfattr *)); + + nfnl_parse_attr(tb, CTA_EXPECT_MAX, NFA_DATA(attr), NFA_PAYLOAD(attr)); + if (tb[CTA_EXPECT_TUPLE-1]) + parse_tuple(tb[CTA_EXPECT_TUPLE-1], tuple); + if (tb[CTA_EXPECT_MASK-1]) + parse_tuple(tb[CTA_EXPECT_MASK-1], mask); + if (tb[CTA_EXPECT_TIMEOUT-1]) + *timeout = *(unsigned long *)NFA_DATA(tb[CTA_EXPECT_TIMEOUT-1]); +} + static int expect_handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void *arg) { struct nfgenmsg *nfmsg; struct nfattr *nfa; - int min_len = 0; + int min_len = sizeof(struct nfgenmsg);; struct ctproto_handler *h = NULL; struct nfattr *attr = NFM_NFA(NLMSG_DATA(nlh)); int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len); + struct ctnl_tuple tuple, mask; + unsigned long timeout = 0; - struct ip_conntrack_tuple *exp, *mask; - unsigned long *timeout; - - DEBUGP("netlink header\n"); - DEBUGP("len: %d type: %d flags: %d seq: %d pid: %d\n", - nlh->nlmsg_len, nlh->nlmsg_type, nlh->nlmsg_flags, - nlh->nlmsg_seq, nlh->nlmsg_pid); + memset(&tuple, 0, sizeof(struct ctnl_tuple)); + memset(&mask, 0, sizeof(struct ctnl_tuple)); nfmsg = NLMSG_DATA(nlh); - DEBUGP("nfmsg->nfgen_family: %d\n", nfmsg->nfgen_family); - min_len = sizeof(struct nfgenmsg); if (nlh->nlmsg_len < min_len) return -EINVAL; - DEBUGP("size:%d\n", nlh->nlmsg_len); - while (NFA_OK(attr, attrlen)) { switch(attr->nfa_type) { - case CTA_EXP_TUPLE: - exp = NFA_DATA(attr); - fprintf(stdout, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ", - NIPQUAD(exp->src.ip), - NIPQUAD(exp->dst.ip)); - h = findproto(proto2str[exp->dst.protonum]); - if (h && h->print_tuple) - h->print_tuple(exp); - break; - case CTA_EXP_MASK: - mask = NFA_DATA(attr); - fprintf(stdout, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ", - NIPQUAD(mask->src.ip), - NIPQUAD(mask->dst.ip)); - h = findproto(proto2str[mask->dst.protonum]); - if (h && h->print_tuple) - h->print_tuple(mask); - break; - case CTA_EXP_TIMEOUT: - timeout = NFA_DATA(attr); - fprintf(stdout, "timeout:%lu ", *timeout); - break; + case CTA_EXPECT: + parse_expect(attr, &tuple, &mask, &timeout); + break; } - DEBUGP("nfa->nfa_type: %d\n", attr->nfa_type); - DEBUGP("nfa->nfa_len: %d\n", attr->nfa_len); attr = NFA_NEXT(attr, attrlen); } - fprintf(stdout, "\n"); + fprintf(stdout, "%ld proto=%d ", timeout, tuple.protonum); + + fprintf(stdout, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ", + NIPQUAD(tuple.src.v4), + NIPQUAD(tuple.dst.v4)); + + fprintf(stdout, "src=%u.%u.%u.%u dst=%u.%u.%u.%u\n", + NIPQUAD(mask.src.v4), + NIPQUAD(mask.dst.v4)); return 0; } -int create_conntrack(struct ip_conntrack_tuple *orig, - struct ip_conntrack_tuple *reply, +int create_conntrack(struct ctnl_tuple *orig, + struct ctnl_tuple *reply, unsigned long timeout, - union ip_conntrack_proto *proto, - unsigned int status) + union ctnl_protoinfo *proto, + unsigned int status, + struct ctnl_nat *range) { - struct cta_proto cta; - struct nfattr *cda[CTA_MAX]; - struct ctnl_handle cth; + struct ctnl_conntrack ct; int ret; + + memset(&ct, 0, sizeof(struct ctnl_conntrack)); + ct.tuple[CTNL_DIR_ORIGINAL] = *orig; + ct.tuple[CTNL_DIR_REPLY] = *reply; + ct.timeout = timeout; + ct.status = status; + ct.protoinfo = *proto; + if (range) + ct.nat = *range; - cta.num_proto = orig->dst.protonum; - memcpy(&cta.proto, proto, sizeof(*proto)); if ((ret = ctnl_open(&cth, 0)) < 0) return ret; - if ((ret = ctnl_new_conntrack(&cth, orig, reply, timeout, &cta, - status)) < 0) - return ret; + ret = ctnl_new_conntrack(&cth, &ct); - if ((ret = ctnl_close(&cth)) < 0) - return ret; + ctnl_close(&cth); - return 0; + return ret; } -int create_expect(struct ip_conntrack_tuple *tuple, - struct ip_conntrack_tuple *mask, - struct ip_conntrack_tuple *master_tuple_orig, - struct ip_conntrack_tuple *master_tuple_reply, - unsigned long timeout) +int update_conntrack(struct ctnl_tuple *orig, + struct ctnl_tuple *reply, + unsigned long timeout, + union ctnl_protoinfo *proto, + unsigned int status) { - struct ctnl_handle cth; + struct ctnl_conntrack ct; int ret; + memset(&ct, 0, sizeof(struct ctnl_conntrack)); + ct.tuple[CTNL_DIR_ORIGINAL] = *orig; + ct.tuple[CTNL_DIR_REPLY] = *reply; + ct.timeout = timeout; + ct.status = status; + ct.protoinfo = *proto; + if ((ret = ctnl_open(&cth, 0)) < 0) return ret; - if ((ret = ctnl_new_expect(&cth, tuple, mask, master_tuple_orig, - master_tuple_reply, timeout)) < 0) - return ret; - - if ((ret = ctnl_close(&cth)) < 0) - return ret; + ret = ctnl_upd_conntrack(&cth, &ct); - return -1; + ctnl_close(&cth); + + return ret; } -int delete_conntrack(struct ip_conntrack_tuple *tuple, - enum ctattr_type_t t) +int delete_conntrack(struct ctnl_tuple *tuple, int dir) { - struct nfattr *cda[CTA_MAX]; - struct ctnl_handle cth; int ret; if ((ret = ctnl_open(&cth, 0)) < 0) return ret; - if ((ret = ctnl_del_conntrack(&cth, tuple, t)) < 0) - return ret; - - if ((ret = ctnl_close(&cth)) < 0) - return ret; + ret = ctnl_del_conntrack(&cth, tuple, dir); + ctnl_close(&cth); - return 0; + return ret; } /* get_conntrack_handler */ -int get_conntrack(struct ip_conntrack_tuple *tuple, - enum ctattr_type_t t, - unsigned long id) +int get_conntrack(struct ctnl_tuple *tuple, int dir) { - struct nfattr *cda[CTA_MAX]; - struct ctnl_handle cth; struct ctnl_msg_handler h = { .type = 0, .handler = handler @@ -293,22 +394,17 @@ int get_conntrack(struct ip_conntrack_tuple *tuple, ctnl_register_handler(&cth, &h); - /* FIXME!!!! get_conntrack_handler returns -100 */ - if ((ret = ctnl_get_conntrack(&cth, tuple, t)) != -100) - return ret; - - if ((ret = ctnl_close(&cth)) < 0) - return ret; + ret = ctnl_get_conntrack(&cth, tuple, dir); + ctnl_close(&cth); - return 0; + return ret; } int dump_conntrack_table(int zero) { int ret; - struct ctnl_handle cth; struct ctnl_msg_handler h = { - .type = 0, /* Hm... really? */ + .type = IPCTNL_MSG_CT_NEW, /* Hm... really? */ .handler = handler }; @@ -322,38 +418,37 @@ int dump_conntrack_table(int zero) } else ret = ctnl_list_conntrack(&cth, AF_INET); - if (ret != -100) - return ret; + ctnl_close(&cth); - if ((ret = ctnl_close(&cth)) < 0) - return ret; + return ret; +} - return 0; +static void event_sighandler(int s) +{ + fprintf(stdout, "Now closing conntrack event dumping...\n"); + ctnl_close(&cth); } int event_conntrack(unsigned int event_mask) { - struct ctnl_handle cth; struct ctnl_msg_handler hnew = { - .type = 0, /* new */ + .type = IPCTNL_MSG_CT_NEW, .handler = event_handler }; struct ctnl_msg_handler hdestroy = { - .type = 2, /* destroy */ + .type = IPCTNL_MSG_CT_DELETE, .handler = event_handler }; int ret; - + if ((ret = ctnl_open(&cth, event_mask)) < 0) return ret; + signal(SIGINT, event_sighandler); ctnl_register_handler(&cth, &hnew); ctnl_register_handler(&cth, &hdestroy); - if ((ret = ctnl_event_conntrack(&cth, AF_INET)) < 0) - return ret; - - if ((ret = ctnl_close(&cth)) < 0) - return ret; + ret = ctnl_event_conntrack(&cth, AF_INET); + ctnl_close(&cth); return 0; } @@ -404,9 +499,8 @@ void unregister_proto(struct ctproto_handler *h) int dump_expect_list() { - struct ctnl_handle cth; struct ctnl_msg_handler h = { - .type = 5, /* Hm... really? */ + .type = IPCTNL_MSG_EXP_NEW, .handler = expect_handler }; int ret; @@ -416,58 +510,114 @@ int dump_expect_list() ctnl_register_handler(&cth, &h); - if ((ret = ctnl_list_expect(&cth, AF_INET)) != -100) - return ret; + ret = ctnl_list_expect(&cth, AF_INET); + ctnl_close(&cth); + + return ret; +} - if ((ret = ctnl_close(&cth)) < 0) +int flush_conntrack() +{ + int ret; + + if ((ret = ctnl_open(&cth, 0)) < 0) return ret; - return 0; + ret = ctnl_flush_conntrack(&cth); + ctnl_close(&cth); + + return ret; } -int set_mask(unsigned int mask, int type) +int get_expect(struct ctnl_tuple *tuple, + enum ctattr_type t) { - struct ctnl_handle cth; - enum ctattr_type_t cta_type; + /* + struct ctnl_msg_handler h = { + .type = IPCTNL_MSG_EXP_NEW, + .handler = expect_handler + }; int ret; - switch(type) { - case 0: - cta_type = CTA_DUMPMASK; - break; - case 1: - cta_type = CTA_EVENTMASK; - break; - default: - /* Shouldn't happen */ - return -1; - } + if ((ret = ctnl_open(&cth, 0)) < 0) + return 0; + + ctnl_register_handler(&cth, &h); + + ret = ctnl_get_expect(&cth, tuple, t); + ctnl_close(&cth); + + return ret; + */ +} +int create_expectation(struct ctnl_tuple *tuple, + enum ctattr_type t, + struct ctnl_tuple *exptuple, + struct ctnl_tuple *mask, + unsigned long timeout) +{ + /* + int ret; + if ((ret = ctnl_open(&cth, 0)) < 0) return ret; + + ret = ctnl_new_expect(&cth, tuple, t, exptuple, mask, timeout); + ctnl_close(&cth); + + return ret; + */ +} + +int delete_expectation(struct ctnl_tuple *tuple, enum ctattr_type t) +{ + /* + int ret; - if ((ret = ctnl_set_mask(&cth, mask, cta_type)) < 0) + if ((ret = ctnl_open(&cth, 0)) < 0) return ret; + + ret = ctnl_del_expect(&cth, tuple, t); + ctnl_close(&cth); + + return ret; + */ +} + +int event_expectation(unsigned int event_mask) +{ + struct ctnl_msg_handler hnew = { + .type = IPCTNL_MSG_EXP_NEW, + .handler = expect_handler + }; + struct ctnl_msg_handler hdestroy = { + .type = IPCTNL_MSG_EXP_DELETE, + .handler = expect_handler + }; + int ret; - if ((ret = ctnl_close(&cth)) < 0) + if ((ret = ctnl_open(&cth, event_mask)) < 0) return ret; - return 0; + ctnl_register_handler(&cth, &hnew); + ctnl_register_handler(&cth, &hdestroy); + ret = ctnl_event_expect(&cth, AF_INET); + ctnl_close(&cth); + + return ret; } -int flush_conntrack() +int flush_expectation() { - struct ctnl_handle cth; int ret; if ((ret = ctnl_open(&cth, 0)) < 0) return ret; - if ((ret = ctnl_flush_conntrack(&cth)) < 0) - return ret; + ret = ctnl_flush_expect(&cth); + ctnl_close(&cth); - if ((ret = ctnl_close(&cth)) < 0) - return ret; - - return 0; + return ret; } + -- cgit v1.2.3