diff options
| author | /C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org </C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org> | 2008-04-13 01:25:48 +0000 | 
|---|---|---|
| committer | /C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org </C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org> | 2008-04-13 01:25:48 +0000 | 
| commit | de56472737c5aa007f775bc475570f49c0e55fb3 (patch) | |
| tree | 865d86427e9283cf302b2c5578e8e587f942d234 | |
| parent | 15c3aa58b5f1011e0116fe4d277c4f8a9c5704c2 (diff) | |
| download | conntrack-tools-de56472737c5aa007f775bc475570f49c0e55fb3.tar.gz conntrack-tools-de56472737c5aa007f775bc475570f49c0e55fb3.zip  | |
This is a major improvement of the conntrack command line tool:
o check for missing source/address IP/ports in creation and get operations
o way more flexible conntrack updates and deletions
o fix NAT filtering via --src-nat and --dst-nat (reported by K.Oledzki)
o show display counters to stderr
o minor cleanups
| -rw-r--r-- | ChangeLog | 20 | ||||
| -rw-r--r-- | configure.in | 2 | ||||
| -rw-r--r-- | src/conntrack.c | 289 | 
3 files changed, 233 insertions, 78 deletions
@@ -1,20 +1,24 @@  version 0.9.7 (yet unreleased)  ------------------------------ -Pablo Neira Ayuso <pablo@netfilter.org>:  o remove .svn directory from make distcheck tarballs (reported by B.Benjamini)  o fix minor compilation issue in amd64 with gcc4.3 (reported by Daniel Schepler) -o fix asymmetric path support (reported by Gary Richards) -o improve netlink overrun handling  o update manpages with the new URL: http://conntrack-tools.netfilter.org + += conntrack = +o fix minor compilation warning (Krzysztof Oledzki) +o add ICMPv6 (-p icmpv6) support (Krzysztof Oledzki) +o distinguish between invalid (unknown) and empty proto (Krzysztof Oledzki)  o simplify parameter-handling code -o check for missing source/address IP/ports +o check for missing source/address IP/ports in creation and get operations +o way more flexible conntrack updates and deletions +o fix NAT filtering via --src-nat and --dst-nat (reported by K.Oledzki) +o show display counters to stderr  o minor cleanups -Krzysztof Oledzki <ole@ans.pl>: -o fix minor compilation warning -o add ICMPv6 (-p icmpv6) support -o add possibility to distinguish between invalid (unknown) and empty proto += conntrackd = +o fix asymmetric path support (reported by Gary Richards) +o improve netlink overrun handling  version 0.9.6 (2008/03/08)  ------------------------------ diff --git a/configure.in b/configure.in index a98a324..92a0389 100644 --- a/configure.in +++ b/configure.in @@ -18,7 +18,7 @@ esac  dnl Dependencies  LIBNFNETLINK_REQUIRED=0.0.32 -LIBNETFILTER_CONNTRACK_REQUIRED=0.0.89 +LIBNETFILTER_CONNTRACK_REQUIRED=0.0.91  PKG_CHECK_MODULES(LIBNFNETLINK, libnfnetlink >= $LIBNFNETLINK_REQUIRED,,          AC_MSG_ERROR(Cannot find libnfnetlink >= $LIBNFNETLINK_REQUIRED)) diff --git a/src/conntrack.c b/src/conntrack.c index 4fa5c9a..f4dfec7 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -1,5 +1,5 @@  /* - * (C) 2005-2007 by Pablo Neira Ayuso <pablo@netfilter.org> + * (C) 2005-2008 by Pablo Neira Ayuso <pablo@netfilter.org>   *   *      This program is free software; you can redistribute it and/or modify   *      it under the terms of the GNU General Public License as published by @@ -31,7 +31,8 @@   * 	Remove remaints of "-A"   * 2007-04-22 Pablo Neira Ayuso <pablo@netfilter.org>:   * 	Ported to the new libnetfilter_conntrack API - * + * 2008-04-13 Pablo Neira Ayuso <pablo@netfilter.org>: + *	Way more flexible update and delete operations   */  #include "conntrack.h" @@ -103,7 +104,7 @@ static struct option original_opts[] = {  #define OPTION_OFFSET 256 -static struct nfct_handle *cth; +static struct nfct_handle *cth, *ith;  static struct option *opts = original_opts;  static unsigned int global_option_offset = 0; @@ -122,8 +123,8 @@ static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] =            /*   s d r q p t u z e [ ] { } a m i f n g o c */  /*CT_LIST*/   {2,2,2,2,2,0,0,2,0,0,0,0,0,0,2,2,2,2,2,2,2},  /*CT_CREATE*/ {2,2,2,2,1,1,1,0,0,0,0,0,0,2,2,0,0,2,2,0,2}, -/*CT_UPDATE*/ {2,2,2,2,1,2,2,0,0,0,0,0,0,0,2,2,0,0,0,0,2}, -/*CT_DELETE*/ {2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0}, +/*CT_UPDATE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,2}, +/*CT_DELETE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,2},  /*CT_GET*/    {2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,2,0,0,0,2,0},  /*CT_FLUSH*/  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},  /*CT_EVENT*/  {2,2,2,2,2,0,0,0,2,0,0,0,0,0,2,0,0,2,2,2,2}, @@ -499,14 +500,6 @@ nat_parse(char *arg, int portok, struct nf_conntrack *obj, int type)  		nfct_set_attr_u32(obj, ATTR_DNAT_IPV4, parse.v4);  } -static void __attribute__((noreturn)) -event_sighandler(int s) -{ -	fprintf(stdout, "Now closing conntrack event dumping...\n"); -	nfct_close(cth); -	exit(0); -} -  static const char usage_commands[] =  	"Commands:\n"  	"  -L [table] [options]\t\tList conntrack or expectation table\n" @@ -566,82 +559,207 @@ usage(char *prog)  static unsigned int output_mask; +static int ignore_nat(const struct nf_conntrack *obj, +		      const struct nf_conntrack *ct) +{ +	uint32_t ip; + +	if (options & CT_OPT_SRC_NAT && options & CT_OPT_DST_NAT) { +		if (!nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT) && +		    !nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) +			return 1; + +		if (nfct_attr_is_set(obj, ATTR_SNAT_IPV4)) { +			ip = nfct_get_attr_u32(obj, ATTR_SNAT_IPV4); +			if (ip != nfct_get_attr_u32(ct, ATTR_REPL_IPV4_DST)) +				return 1; +		} + +		if (nfct_attr_is_set(obj, ATTR_DNAT_IPV4)) { +			ip = nfct_get_attr_u32(obj, ATTR_DNAT_IPV4); +			if (ip != nfct_get_attr_u32(ct, ATTR_REPL_IPV4_SRC)) +				return 1; +		} +	} else if (options & CT_OPT_SRC_NAT) { +		if (!nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) +		  	return 1; + +		if (nfct_attr_is_set(obj, ATTR_SNAT_IPV4)) { +			ip = nfct_get_attr_u32(obj, ATTR_SNAT_IPV4); +			if (ip != nfct_get_attr_u32(ct, ATTR_REPL_IPV4_DST)) +				return 1; +		} +	} else if (options & CT_OPT_DST_NAT) { +		if (!nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) +			return 1; + +		if (nfct_attr_is_set(obj, ATTR_DNAT_IPV4)) { +			ip = nfct_get_attr_u32(obj, ATTR_DNAT_IPV4); +			if (ip != nfct_get_attr_u32(ct, ATTR_REPL_IPV4_SRC)) +				return 1; +		} +	} + +	return 0; +} + +static int events_counter; + +static void __attribute__((noreturn)) +event_sighandler(int s) +{ +	fprintf(stderr, "%s v%s: ", PROGNAME, VERSION); +	fprintf(stderr, "%d flow events has been shown.\n", events_counter); +	nfct_close(cth); +	exit(0); +} +  static int event_cb(enum nf_conntrack_msg_type type,  		    struct nf_conntrack *ct,  		    void *data)  {  	char buf[1024];  	struct nf_conntrack *obj = data; -	unsigned int output_type = NFCT_O_DEFAULT; -	unsigned int output_flags = 0; +	unsigned int op_type = NFCT_O_DEFAULT; +	unsigned int op_flags = 0; -	if (options & CT_OPT_SRC_NAT && options & CT_OPT_DST_NAT) { -		if (!nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT) && -		    !nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) -			return NFCT_CB_CONTINUE; -	} else if (options & CT_OPT_SRC_NAT &&  -		   !nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) { -	 	return NFCT_CB_CONTINUE; -	} else if (options & CT_OPT_DST_NAT && -		   !nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) { +	if (ignore_nat(obj, ct))  		return NFCT_CB_CONTINUE; -	} -	if (options & CT_COMPARISON && !nfct_compare(obj, ct)) +	if (options & CT_COMPARISON && !nfct_cmp(obj, ct, NFCT_CMP_ALL))  		return NFCT_CB_CONTINUE;  	if (output_mask & _O_XML) -		output_type = NFCT_O_XML; +		op_type = NFCT_O_XML;  	if (output_mask & _O_EXT) -		output_flags = NFCT_OF_SHOW_LAYER3; +		op_flags = NFCT_OF_SHOW_LAYER3;  	if (output_mask & _O_TMS) {  		if (!(output_mask & _O_XML)) {  			struct timeval tv;  			gettimeofday(&tv, NULL);  			printf("[%-8ld.%-6ld]\t", tv.tv_sec, tv.tv_usec);  		} else -			output_flags |= NFCT_OF_TIME; +			op_flags |= NFCT_OF_TIME;  	}	 -	nfct_snprintf(buf, 1024, ct, type, output_type, output_flags); +	nfct_snprintf(buf, 1024, ct, type, op_type, op_flags);  	printf("%s\n", buf);  	fflush(stdout); +	events_counter++; +  	return NFCT_CB_CONTINUE;  } +static int list_counter; +  static int dump_cb(enum nf_conntrack_msg_type type,  		   struct nf_conntrack *ct,  		   void *data)  {  	char buf[1024];  	struct nf_conntrack *obj = data; -	unsigned int output_type = NFCT_O_DEFAULT; -	unsigned int output_flags = 0; +	unsigned int op_type = NFCT_O_DEFAULT; +	unsigned int op_flags = 0; -	if (options & CT_OPT_SRC_NAT && options & CT_OPT_DST_NAT) { -		if (!nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT) && -		    !nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) -			return NFCT_CB_CONTINUE; -	} else if (options & CT_OPT_SRC_NAT &&  -		   !nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) { -	 	return NFCT_CB_CONTINUE; -	} else if (options & CT_OPT_DST_NAT && -		   !nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) { +	if (ignore_nat(obj, ct))  		return NFCT_CB_CONTINUE; -	} -	if (options & CT_COMPARISON && !nfct_compare(obj, ct)) +	if (options & CT_COMPARISON && !nfct_cmp(obj, ct, NFCT_CMP_ALL))  		return NFCT_CB_CONTINUE;  	if (output_mask & _O_XML) -		output_type = NFCT_O_XML; +		op_type = NFCT_O_XML;  	if (output_mask & _O_EXT) -		output_flags = NFCT_OF_SHOW_LAYER3; +		op_flags = NFCT_OF_SHOW_LAYER3; -	nfct_snprintf(buf, 1024, ct, NFCT_T_UNKNOWN, output_type, output_flags); +	nfct_snprintf(buf, 1024, ct, NFCT_T_UNKNOWN, op_type, op_flags);  	printf("%s\n", buf); +	list_counter++; + +	return NFCT_CB_CONTINUE; +} + +static int delete_counter; + +static int delete_cb(enum nf_conntrack_msg_type type, +		     struct nf_conntrack *ct, +		     void *data) +{ +	int res; +	char buf[1024]; +	struct nf_conntrack *obj = data; +	unsigned int op_type = NFCT_O_DEFAULT; +	unsigned int op_flags = 0; + +	if (ignore_nat(obj, ct)) +		return NFCT_CB_CONTINUE; + +	if (options & CT_COMPARISON && !nfct_cmp(obj, ct, NFCT_CMP_ALL)) +		return NFCT_CB_CONTINUE; + +	res = nfct_query(ith, NFCT_Q_DESTROY, ct); +	if (res < 0) +		exit_error(OTHER_PROBLEM, +			   "Operation failed: %s", +			   err2str(errno, CT_DELETE)); + +	if (output_mask & _O_XML) +		op_type = NFCT_O_XML; +	if (output_mask & _O_EXT) +		op_flags = NFCT_OF_SHOW_LAYER3; + +	nfct_snprintf(buf, 1024, ct, NFCT_T_UNKNOWN, op_type, op_flags); +	printf("%s\n", buf); + +	delete_counter++; + +	return NFCT_CB_CONTINUE; +} + +static int update_counter; + +static int update_cb(enum nf_conntrack_msg_type type, +		     struct nf_conntrack *ct, +		     void *data) +{ +	int res; +	char buf[1024]; +	struct nf_conntrack *obj = data; +	char __tmp[nfct_maxsize()]; +	struct nf_conntrack *tmp = (struct nf_conntrack *) (void *)__tmp; +	unsigned int op_type = NFCT_O_DEFAULT; +	unsigned int op_flags = 0; + +	memcpy(tmp, obj, sizeof(__tmp)); + +	if (ignore_nat(tmp, ct)) +		return NFCT_CB_CONTINUE; + +	if (options & CT_OPT_ORIG && !nfct_cmp(tmp, ct, NFCT_CMP_ORIG)) +		return NFCT_CB_CONTINUE; +	if (options & CT_OPT_REPL && !nfct_cmp(tmp, ct, NFCT_CMP_REPL)) +		return NFCT_CB_CONTINUE; + +	nfct_copy(tmp, ct, NFCT_CP_ORIG); + +	res = nfct_query(ith, NFCT_Q_UPDATE, tmp); +	if (res < 0) +		exit_error(OTHER_PROBLEM, +			   "Operation failed: %s", +			   err2str(errno, CT_UPDATE)); + +	if (output_mask & _O_XML) +		op_type = NFCT_O_XML; +	if (output_mask & _O_EXT) +		op_flags = NFCT_OF_SHOW_LAYER3; + +	nfct_snprintf(buf, 1024, ct, NFCT_T_UNKNOWN, op_type, op_flags); +	printf("%s\n", buf); + +	update_counter++; +  	return NFCT_CB_CONTINUE;  } @@ -665,6 +783,7 @@ static const int cmd2type[][2] = {  	['D']	= { CT_DELETE,	EXP_DELETE },  	['G']	= { CT_GET,	EXP_GET },  	['F']	= { CT_FLUSH,	EXP_FLUSH }, +	['E']	= { CT_EVENT,	EXP_EVENT },  	['V']	= { CT_VERSION,	CT_VERSION },  	['h']	= { CT_HELP,	CT_HELP },  }; @@ -714,7 +833,8 @@ int main(int argc, char *argv[])  	char __exptuple[nfct_maxsize()];  	char __mask[nfct_maxsize()];  	struct nf_conntrack *obj = (struct nf_conntrack *)(void*) __obj; -	struct nf_conntrack *exptuple = (struct nf_conntrack *)(void*) __exptuple; +	struct nf_conntrack *exptuple =  +		(struct nf_conntrack *)(void*) __exptuple;  	struct nf_conntrack *mask = (struct nf_conntrack *)(void*) __mask;  	char __exp[nfexp_maxsize()];  	struct nf_expect *exp = (struct nf_expect *)(void*) __exp; @@ -869,15 +989,24 @@ int main(int argc, char *argv[])  			options |= CT_OPT_ZERO;  			break;  		case 'n': -		case 'g': -			if (!optarg) -				exit_error(PARAMETER_PROBLEM,  -					   "-%c requires an IP", c); +		case 'g': { +			char *tmp = NULL;  			options |= opt2type[c]; + +			if (optarg) +				continue; +			else if (optind < argc && argv[optind][0] != '-' +				 && argv[optind][0] != '!') +				tmp = argv[optind++]; + +			if (tmp == NULL) +				continue; +  			set_family(&family, AF_INET); -			nat_parse(optarg, 1, obj, opt2type[c]); +			nat_parse(tmp, 1, obj, opt2type[c]);  			break; +		}  		case 'm':  		case 'c':  			options |= opt2type[c]; @@ -930,7 +1059,7 @@ int main(int argc, char *argv[])  			  commands_v_options[cmd],  			  optflags); -	if (command & (CT_CREATE|CT_UPDATE|CT_DELETE|CT_GET) && +	if (command & (CT_CREATE|CT_GET) &&  	    !((options & CT_OPT_ORIG_SRC && options & CT_OPT_ORIG_DST) ||  	      (options & CT_OPT_REPL_SRC && options & CT_OPT_REPL_DST)))  	      exit_error(PARAMETER_PROBLEM, "missing IP address"); @@ -958,6 +1087,10 @@ int main(int argc, char *argv[])  			res = nfct_query(cth, NFCT_Q_DUMP, &family);  		nfct_close(cth); + +		fprintf(stderr, "%s v%s: ", PROGNAME, VERSION); +		fprintf(stderr, "%d flow entries has been shown.\n", +			list_counter);  		break;  	case EXP_LIST: @@ -982,6 +1115,9 @@ int main(int argc, char *argv[])  		res = nfct_query(cth, NFCT_Q_CREATE, obj);  		nfct_close(cth); +		fprintf(stderr, "%s v%s: ", PROGNAME, VERSION); +		fprintf(stderr, "%d flow entry has been created.\n", +			res == -1 ? 0 : 1);  		break;  	case EXP_CREATE: @@ -998,29 +1134,38 @@ int main(int argc, char *argv[])  		break;  	case CT_UPDATE: -		if ((options & CT_OPT_ORIG) && !(options & CT_OPT_REPL)) -		    	nfct_setobjopt(obj, NFCT_SOPT_SETUP_REPLY); -		else if (!(options & CT_OPT_ORIG) && (options & CT_OPT_REPL)) -			nfct_setobjopt(obj, NFCT_SOPT_SETUP_ORIGINAL); -  		cth = nfct_open(CONNTRACK, 0); -		if (!cth) +		/* internal handler for delete_cb, otherwise we hit EILSEQ */ +		ith = nfct_open(CONNTRACK, 0); +		if (!cth || !ith)  			exit_error(OTHER_PROBLEM, "Can't open handler"); -		res = nfct_query(cth, NFCT_Q_UPDATE, obj); +		nfct_callback_register(cth, NFCT_T_ALL, update_cb, obj); + +		res = nfct_query(cth, NFCT_Q_DUMP, &family); +		nfct_close(ith);  		nfct_close(cth); + +		fprintf(stderr, "%s v%s: ", PROGNAME, VERSION); +		fprintf(stderr, "%d flow entries has been updated.\n", +			update_counter);  		break;  	case CT_DELETE: -		if (!(options & CT_OPT_ORIG) && !(options & CT_OPT_REPL)) -			exit_error(PARAMETER_PROBLEM, "Can't kill conntracks " -						      "just by its ID");  		cth = nfct_open(CONNTRACK, 0); -		if (!cth) +		ith = nfct_open(CONNTRACK, 0); +		if (!cth || !ith)  			exit_error(OTHER_PROBLEM, "Can't open handler"); -		res = nfct_query(cth, NFCT_Q_DESTROY, obj); +		nfct_callback_register(cth, NFCT_T_ALL, delete_cb, obj); + +		res = nfct_query(cth, NFCT_Q_DUMP, &family); +		nfct_close(ith);  		nfct_close(cth); + +		fprintf(stderr, "%s v%s: ", PROGNAME, VERSION); +		fprintf(stderr, "%d flow entries has been deleted.\n",  +			delete_counter);  		break;  	case EXP_DELETE: @@ -1042,6 +1187,9 @@ int main(int argc, char *argv[])  		nfct_callback_register(cth, NFCT_T_ALL, dump_cb, obj);  		res = nfct_query(cth, NFCT_Q_GET, obj);  		nfct_close(cth); +		fprintf(stderr, "%s v%s: ", PROGNAME, VERSION); +		fprintf(stderr, "%d flow entry has been shown.\n", +			res == -1 ? 0 : 1);  		break;  	case EXP_GET: @@ -1062,6 +1210,8 @@ int main(int argc, char *argv[])  			exit_error(OTHER_PROBLEM, "Can't open handler");  		res = nfct_query(cth, NFCT_Q_FLUSH, &family);  		nfct_close(cth); +		fprintf(stderr, "%s v%s: ", PROGNAME, VERSION); +		fprintf(stderr,"connection tracking table has been emptied.\n");  		break;  	case EXP_FLUSH: @@ -1081,6 +1231,7 @@ int main(int argc, char *argv[])  		if (!cth)  			exit_error(OTHER_PROBLEM, "Can't open handler");  		signal(SIGINT, event_sighandler); +		signal(SIGTERM, event_sighandler);  		nfct_callback_register(cth, NFCT_T_ALL, event_cb, obj);  		res = nfct_catch(cth);  		nfct_close(cth); @@ -1091,6 +1242,7 @@ int main(int argc, char *argv[])  		if (!cth)  			exit_error(OTHER_PROBLEM, "Can't open handler");  		signal(SIGINT, event_sighandler); +		signal(SIGTERM, event_sighandler);  		nfexp_callback_register(cth, NFCT_T_ALL, dump_exp_cb, NULL);  		res = nfexp_catch(cth);  		nfct_close(cth); @@ -1115,10 +1267,9 @@ int main(int argc, char *argv[])  		global_option_offset = 0;  	} -	if (res < 0) { -		fprintf(stderr, "Operation failed: %s\n", err2str(errno, command)); -		exit(OTHER_PROBLEM); -	} +	if (res < 0) +		exit_error(OTHER_PROBLEM, "Operation failed: %s", +			   err2str(errno, command));  	return 0;  }  | 
