New fix for -j <match> and -m <target>.
diff --git a/iptables.c b/iptables.c
index cf6b04c..c4846fd 100644
--- a/iptables.c
+++ b/iptables.c
@@ -125,6 +125,14 @@
 	{ 0 }
 };
 
+#if 0
+static struct ipt_entry_target *
+ipt_get_target(struct ipt_entry *e)
+{
+	return (void *)e + e->target_offset;
+}
+#endif
+
 static struct option *opts = original_opts;
 static unsigned int global_option_offset = 0;
 
@@ -616,8 +624,15 @@
 		char path[sizeof(IPT_LIB_DIR) + sizeof("/libipt_.so")
 			 + strlen(name)];
 		sprintf(path, IPT_LIB_DIR "/libipt_%s.so", name);
-		dlopen(path, RTLD_NOW);
-		return find_match(name, 0);
+		if (dlopen(path, RTLD_NOW)) {
+			/* Found library.  If it didn't register itself,
+			   maybe they specified target as match. */
+			ptr = find_match(name, 0);
+			if (!ptr)
+				exit_error(PARAMETER_PROBLEM,
+					   "Couldn't load match `%s'\n",
+					   name);
+		}
 	}
 
 	return ptr;
@@ -842,8 +857,15 @@
 		char path[sizeof(IPT_LIB_DIR) + sizeof("/libipt_.so")
 			 + strlen(name)];
 		sprintf(path, IPT_LIB_DIR "/libipt_%s.so", name);
-		dlopen(path, RTLD_NOW);
-		return find_target(name, 0);
+		if (dlopen(path, RTLD_NOW)) {
+			/* Found library.  If it didn't register itself,
+			   maybe they specified match as a target. */
+			ptr = find_target(name, 0);
+			if (!ptr)
+				exit_error(PARAMETER_PROBLEM,
+					   "Couldn't load target `%s'\n",
+					   name);
+		}
 	}
 
 	return ptr;
@@ -935,8 +957,10 @@
 		printf(")\n");
 	} else {
 		unsigned int refs;
-		iptc_get_references(&refs, chain, handle);
-		printf(" (%u references)\n", refs);
+		if (!iptc_get_references(&refs, chain, handle))
+			printf(" (ERROR obtaining refs)\n");
+		else
+			printf(" (%u references)\n", refs);
 	}
 
 	if (format & FMT_LINENUMBERS)
@@ -1226,10 +1250,12 @@
 	for (m = iptables_matches; m; m = m->next)
 		size += sizeof(struct ipt_entry_match) + m->size;
 
-	mask = fw_calloc(1, size + iptables_target->size);
+	mask = fw_calloc(1, size
+			 + sizeof(struct ipt_entry_target)
+			 + iptables_targets->size);
 
-	memset(mask, 0xFF, sizeof(ipt_entry));
-	mptr = mask + sizeof(ipt_entry);
+	memset(mask, 0xFF, sizeof(struct ipt_entry));
+	mptr = mask + sizeof(struct ipt_entry);
 
 	for (m = iptables_matches; m; m = m->next) {
 		memset(mptr, 0xFF,
@@ -1239,7 +1265,7 @@
 
 	memset(mptr, 0xFF, sizeof(struct ipt_entry_target));
 	mptr += sizeof(struct ipt_entry_target);
-	memset(mptr, 0xFF, iptables_target->userspacesize);
+	memset(mptr, 0xFF, iptables_targets->userspacesize);
 
 	return mask;
 }
@@ -1302,15 +1328,37 @@
 
 static int
 for_each_chain(int (*fn)(const ipt_chainlabel, int, iptc_handle_t *),
-	       int verbose, iptc_handle_t *handle)
+	       int verbose, int builtinstoo, iptc_handle_t *handle)
 {
         int ret = 1;
-	const char *chain = NULL;
+	const char *chain;
+	char *chains;
+	unsigned int i, chaincount = 0;
 
-	while ((chain = iptc_next_chain(chain, handle))) {
-	        ret &= fn(chain, verbose, handle);
+	chain = iptc_first_chain(handle);
+	while (chain) {
+		chaincount++;
+		chain = iptc_next_chain(handle);
         }
 
+	chains = fw_malloc(sizeof(ipt_chainlabel) * chaincount);
+	i = 0;
+	chain = iptc_first_chain(handle);
+	while (chain) {
+		strcpy(chains + i*sizeof(ipt_chainlabel), chain);
+		i++;
+		chain = iptc_next_chain(handle);
+        }
+
+	for (i = 0; i < chaincount; i++) {
+		if (!builtinstoo
+		    && iptc_builtin(chains + i*sizeof(ipt_chainlabel),
+				    *handle))
+			continue;
+	        ret &= fn(chains + i*sizeof(ipt_chainlabel), verbose, handle);
+	}
+
+	free(chains);
         return ret;
 }
 
@@ -1319,7 +1367,7 @@
 	      iptc_handle_t *handle)
 {
 	if (!chain)
-		return for_each_chain(flush_entries, verbose, handle);
+		return for_each_chain(flush_entries, verbose, 1, handle);
 
 	if (verbose)
 		fprintf(stdout, "Flushing chain `%s'\n", chain);
@@ -1331,7 +1379,7 @@
 	     iptc_handle_t *handle)
 {
 	if (!chain)
-		return for_each_chain(zero_entries, verbose, handle);
+		return for_each_chain(zero_entries, verbose, 1, handle);
 
 	if (verbose)
 		fprintf(stdout, "Zeroing chain `%s'\n", chain);
@@ -1342,33 +1390,8 @@
 delete_chain(const ipt_chainlabel chain, int verbose,
 	     iptc_handle_t *handle)
 {
-	if (!chain) {
-		const char *i, *last = NULL;
-		int ret = 1;
-
-		/* Iterate over built-ins */
-		for (i = iptc_next_chain(NULL, handle);
-		     i && iptc_builtin(i, *handle);
-		     i = iptc_next_chain(i, handle))
-			last = i;
-
-		/* No user-defined chains? */
-		if (!i)
-			return ret;
-
-		/* Be careful iterating: it isn't safe during delete. */
-		/* Re-iterate after each delete successful */
-		while ((i = iptc_next_chain(last, handle)) != NULL) {
-			/* Skip over builtins. */
-			if (!delete_chain(i, verbose, handle)) {
-				/* Delete failed; start next
-				   iteration from here */
-				last = i;
-				ret = 0;
-			}
-		}
-		return ret;
-	}
+	if (!chain)
+		return for_each_chain(delete_chain, verbose, 0, handle);
 
 	if (verbose)
 	        fprintf(stdout, "Deleting chain `%s'\n", chain);
@@ -1380,8 +1403,8 @@
 	     int expanded, int linenumbers, iptc_handle_t *handle)
 {
 	int found = 0;
-	unsigned int i, format;
-	const char *this = NULL;
+	unsigned int format;
+	const char *this;
 
 	format = FMT_OPTIONS;
 	if (!verbose)
@@ -1398,20 +1421,29 @@
 	if (linenumbers)
 		format |= FMT_LINENUMBERS;
 
+	for (this = iptc_first_chain(handle);
+	     this;
+	     this = iptc_next_chain(handle)) {
+		const struct ipt_entry *i;
+		unsigned int num;
 
-	while ((this = iptc_next_chain(this, handle)) != NULL) {
 		if (chain && strcmp(chain, this) != 0)
 			continue;
 
 		if (found) printf("\n");
 
 		print_header(format, this, handle);
-		for (i = 0; i < iptc_num_rules(this, handle); i++)
-			print_firewall(iptc_get_rule(this, i, handle),
-				       iptc_get_target(this, i, handle),
-				       i,
+		i = iptc_first_rule(this, handle);
+
+		num = 0;
+		while (i) {
+			print_firewall(i,
+				       iptc_get_target(i, handle),
+				       num++,
 				       format,
 				       *handle);
+			i = iptc_next_rule(i, handle);
+		}
 		found = 1;
 	}
 
@@ -1430,7 +1462,7 @@
 
 	size = sizeof(struct ipt_entry);
 	for (m = matches; m; m = m->next)
-		size += m->m ? m->m->match_size : 0;
+		size += m->m->match_size;
 
 	e = fw_malloc(size + target->target_size);
 	*e = *fw;
@@ -1439,10 +1471,8 @@
 
 	size = 0;
 	for (m = matches; m; m = m->next) {
-		if (m->m) {
-			memcpy(e->elems + size, m->m, m->m->match_size);
-			size += m->m->match_size;
-		}
+		memcpy(e->elems + size, m->m, m->m->match_size);
+		size += m->m->match_size;
 	}
 	memcpy(e->elems + size, target, target->target_size);
 
@@ -1754,6 +1784,7 @@
 				optarg[0] = '\0';
 				continue;
 			}
+			printf("Bad argument `%s'\n", optarg);
 			exit_tryhelp(2);
 
 		default:
@@ -1776,8 +1807,9 @@
 
 				/* If you listen carefully, you can
 				   acually hear this code suck. */
-				if (!iptables_matches
+				if (m == NULL
 				    && protocol
+				    && !find_match(protocol, 0)
 				    && (m = find_match(protocol, 1))) {
 					/* Try loading protocol */
 					size_t size = sizeof(struct ipt_entry_match)