From c86e48dc7d688d97a6ee4697ce01e594fa70d7db Mon Sep 17 00:00:00 2001 From: "/C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=laforge/emailAddress=laforge@netfilter.org" Date: Sat, 16 Apr 2005 13:30:56 +0000 Subject: add pablo's conntrack tool --- src/conntrack.c | 472 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 472 insertions(+) create mode 100644 src/conntrack.c (limited to 'src/conntrack.c') diff --git a/src/conntrack.c b/src/conntrack.c new file mode 100644 index 0000000..dfb3849 --- /dev/null +++ b/src/conntrack.c @@ -0,0 +1,472 @@ +/* + * (C) 2005 by Pablo Neira Ayuso + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Note: + * Yes, portions of this code has been stolen from iptables ;) + * Special thanks to the the Netfilter Core Team. + * Thanks to Javier de Miguel Rodriguez + * for introducing me to advanced firewalling stuff. + * + * --pablo 13/04/2005 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "libctnetlink.h" +#include "libnfnetlink.h" +#include "linux_list.h" +#include "libct_proto.h" + +#define PROGNAME "conntrack" +#define VERSION "0.12" + +#if 0 +#define DEBUGP printf +#else +#define DEBUGP +#endif + +enum action { + CT_LIST_BIT = 0, + CT_LIST = (1 << CT_LIST_BIT), + + CT_CREATE_BIT = 1, + CT_CREATE = (1 << CT_CREATE_BIT), + + CT_DELETE_BIT = 2, + CT_DELETE = (1 << CT_DELETE_BIT), + + CT_GET_BIT = 3, + CT_GET = (1 << CT_GET_BIT), + + CT_FLUSH_BIT = 4, + CT_FLUSH = (1 << CT_FLUSH_BIT), + + CT_EVENT_BIT = 5, + CT_EVENT = (1 << CT_EVENT_BIT) +}; +#define NUMBER_OF_CMD 6 + +enum options { + CT_OPT_ORIG_SRC_BIT = 0, + CT_OPT_ORIG_SRC = (1 << CT_OPT_ORIG_SRC_BIT), + + CT_OPT_ORIG_DST_BIT = 1, + CT_OPT_ORIG_DST = (1 << CT_OPT_ORIG_DST_BIT), + + CT_OPT_ORIG = (CT_OPT_ORIG_SRC | CT_OPT_ORIG_DST), + + CT_OPT_REPL_SRC_BIT = 2, + CT_OPT_REPL_SRC = (1 << CT_OPT_REPL_SRC_BIT), + + CT_OPT_REPL_DST_BIT = 3, + CT_OPT_REPL_DST = (1 << CT_OPT_REPL_DST_BIT), + + CT_OPT_REPL = (CT_OPT_REPL_SRC | CT_OPT_REPL_DST), + + CT_OPT_PROTO_BIT = 4, + CT_OPT_PROTO = (1 << CT_OPT_PROTO_BIT), + + CT_OPT_ID_BIT = 5, + CT_OPT_ID = (1 << CT_OPT_ID_BIT), + + CT_OPT_TIMEOUT_BIT = 6, + CT_OPT_TIMEOUT = (1 << CT_OPT_TIMEOUT_BIT), + + CT_OPT_STATUS_BIT = 7, + CT_OPT_STATUS = (1 << CT_OPT_STATUS_BIT), +}; +#define NUMBER_OF_OPT 8 + +static const char optflags[NUMBER_OF_OPT] += { 's', 'd', 'r', 'q', 'p', 'i', 't', 'u'}; + +static struct option original_opts[] = { + {"dump", 1, 0, 'L'}, + {"create", 1, 0, 'I'}, + {"delete", 1, 0, 'D'}, + {"get", 1, 0, 'G'}, + {"flush", 1, 0, 'F'}, + {"event", 1, 0, 'E'}, + {"orig-src", 1, 0, 's'}, + {"orig-dst", 1, 0, 'd'}, + {"reply-src", 1, 0, 'r'}, + {"reply-dst", 1, 0, 'q'}, + {"protonum", 1, 0, 'p'}, + {"timeout", 1, 0, 't'}, + {"id", 1, 0, 'i'}, + {"status", 1, 0, 'u'}, + {0, 0, 0, 0} +}; + +#define OPTION_OFFSET 256 + +static struct option *opts = original_opts; +static unsigned int global_option_offset = 0; + +/* Table of legal combinations of commands and options. If any of the + * given commands make an option legal, that option is legal (applies to + * CMD_LIST and CMD_ZERO only). + * Key: + * + compulsory + * x illegal + * optional + */ + +static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = +/* Well, it's better than "Re: Linux vs FreeBSD" */ +{ + /* -s -d -r -q -p -i -t -u*/ +/*LIST*/ {'x','x','x','x','x','x','x','x'}, +/*CREATE*/ {'+','+','+','+','+','x','+','+'}, +/*DELETE*/ {' ',' ',' ',' ',' ','+','x','x'}, +/*GET*/ {' ',' ',' ',' ','+','+','x','x'}, +/*FLUSH*/ {'x','x','x','x','x','x','x','x'}, +/*EVENT*/ {'x','x','x','x','x','x','x','x'} +}; + +LIST_HEAD(proto_list); + +char *proto2str[] = { + [IPPROTO_TCP] = "tcp", + [IPPROTO_UDP] = "udp", + [IPPROTO_ICMP] = "icmp", + [IPPROTO_SCTP] = "sctp" +}; + +enum exittype { + OTHER_PROBLEM = 1, + PARAMETER_PROBLEM, + VERSION_PROBLEM +}; + +void +exit_tryhelp(int status) +{ + fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n", + PROGNAME, PROGNAME); + exit(status); +} + +static void +exit_error(enum exittype status, char *msg, ...) +{ + va_list args; + + /* On error paths, make sure that we don't leak the memory + * reserved during options merging */ + if (opts != original_opts) { + free(opts); + opts = original_opts; + global_option_offset = 0; + } + va_start(args, msg); + fprintf(stderr, "%s v%s: ", PROGNAME, VERSION); + vfprintf(stderr, msg, args); + va_end(args); + fprintf(stderr, "\n"); + if (status == PARAMETER_PROBLEM) + exit_tryhelp(status); + exit(status); +} + +static void +generic_opt_check(int command, int options) +{ + int i, j, legal = 0; + + /* Check that commands are valid with options. Complicated by the + * fact that if an option is legal with *any* command given, it is + * legal overall (ie. -z and -l). + */ + for (i = 0; i < NUMBER_OF_OPT; i++) { + legal = 0; /* -1 => illegal, 1 => legal, 0 => undecided. */ + + for (j = 0; j < NUMBER_OF_CMD; j++) { + if (!(command & (1<protonum; + reply.dst.protonum = h->protonum; + opts = merge_options(opts, h->opts, + &h->option_offset); + break; + case 'i': + options |= CT_OPT_ID; + id = atoi(optarg); + break; + case 't': + options |= CT_OPT_TIMEOUT; + if (optarg) + timeout = atol(optarg); + break; + case 'u': { + /* FIXME: NAT stuff, later... */ + if (!optarg) + continue; + + options |= CT_OPT_STATUS; + /* Just insert confirmed conntracks */ + status |= IPS_CONFIRMED; + if (strncmp("SEEN_REPLY", optarg, strlen("SEEN_REPLY")) == 0) + status |= IPS_SEEN_REPLY; + else if (strncmp("ASSURED", optarg, strlen("ASSURED")) == 0) + status |= IPS_ASSURED; + else + exit_error(PARAMETER_PROBLEM, "Invalid status" + "flag: %s\n", optarg); + break; + } + default: + if (h && !h->parse(c - h->option_offset, argv, + &orig, &reply)) + exit_error(PARAMETER_PROBLEM, "parse error\n"); + + /* Unknown argument... */ + if (!h) { + usage(argv[0]); + exit_error(PARAMETER_PROBLEM, "Missing " + "arguments...\n"); + } + break; + } + } + + generic_opt_check(command, options); + + switch(command) { + case CT_LIST: + printf("list\n"); + if (type == 0) + dump_conntrack_table(); + else + dump_expect_list(); + break; + case CT_CREATE: + printf("create\n"); + if (type == 0) + create_conntrack(&orig, &reply, timeout, + &proto, status); + else + not_implemented_yet(); + break; + case CT_DELETE: + printf("delete\n"); + if (type == 0) { + if (options & CT_OPT_ORIG) + delete_conntrack(&orig, CTA_ORIG, id); + else if (options & CT_OPT_REPL) + delete_conntrack(&reply, CTA_RPLY, id); + } else + not_implemented_yet(); + break; + case CT_GET: + printf("get\n"); + if (type == 0) { + if (options & CT_OPT_ORIG) + get_conntrack(&orig, CTA_ORIG, id); + else if (options & CT_OPT_REPL) + get_conntrack(&reply, CTA_RPLY, id); + } else + not_implemented_yet(); + break; + case CT_FLUSH: + not_implemented_yet(); + break; + case CT_EVENT: + printf("event\n"); + if (type == 0) + event_conntrack(); + else + /* and surely it won't ever... */ + not_implemented_yet(); + default: + usage(argv[0]); + break; + } + + if (opts != original_opts) { + free(opts); + opts = original_opts; + global_option_offset = 0; + } +} -- cgit v1.2.3