Make sure to use matches in the order they are given when calling do_command() multiple times.
diff --git a/iptables.c b/iptables.c
index c438d60..2c6282a 100644
--- a/iptables.c
+++ b/iptables.c
@@ -661,7 +661,7 @@
 }
 
 struct iptables_match *
-find_match(const char *name, enum ipt_tryload tryload)
+find_match(const char *name, enum ipt_tryload tryload, struct iptables_rule_match **matches)
 {
 	struct iptables_match *ptr;
 
@@ -678,7 +678,7 @@
 		if (dlopen(path, RTLD_NOW)) {
 			/* Found library.  If it didn't register itself,
 			   maybe they specified target as match. */
-			ptr = find_match(name, DONT_LOAD);
+			ptr = find_match(name, DONT_LOAD, NULL);
 
 			if (!ptr)
 				exit_error(PARAMETER_PROBLEM,
@@ -702,15 +702,24 @@
 	}
 #endif
 
-	if (ptr)
-		ptr->used = 1;
+	if (ptr && matches) {
+		struct iptables_rule_match **i;
+		struct iptables_rule_match *newentry;
+
+		newentry = fw_malloc(sizeof(struct iptables_rule_match));
+
+		for (i = matches; *i; i = &(*i)->next);
+		newentry->match = ptr;
+		newentry->next = NULL;
+		*i = newentry;
+	}
 
 	return ptr;
 }
 
 /* Christophe Burki wants `-p 6' to imply `-m tcp'.  */
 static struct iptables_match *
-find_proto(const char *pname, enum ipt_tryload tryload, int nolookup)
+find_proto(const char *pname, enum ipt_tryload tryload, int nolookup, struct iptables_rule_match **matches)
 {
 	unsigned int proto;
 
@@ -718,9 +727,9 @@
 		char *protoname = proto_to_name(proto, nolookup);
 
 		if (protoname)
-			return find_match(protoname, tryload);
+			return find_match(protoname, tryload, matches);
 	} else
-		return find_match(pname, tryload);
+		return find_match(pname, tryload, matches);
 
 	return NULL;
 }
@@ -1018,7 +1027,7 @@
 		exit(1);
 	}
 
-	if (find_match(me->name, DONT_LOAD)) {
+	if (find_match(me->name, DONT_LOAD, NULL)) {
 		fprintf(stderr, "%s: match `%s' already registered.\n",
 			program_name, me->name);
 		exit(1);
@@ -1148,7 +1157,7 @@
 	    const struct ipt_ip *ip,
 	    int numeric)
 {
-	struct iptables_match *match = find_match(m->u.user.name, TRY_LOAD);
+	struct iptables_match *match = find_match(m->u.user.name, TRY_LOAD, NULL);
 
 	if (match) {
 		if (match->print)
@@ -1364,20 +1373,16 @@
 }
 
 static unsigned char *
-make_delete_mask(struct ipt_entry *fw)
+make_delete_mask(struct ipt_entry *fw, struct iptables_rule_match *matches)
 {
 	/* Establish mask for comparison */
 	unsigned int size;
-	struct iptables_match *m;
+	struct iptables_rule_match *matchp;
 	unsigned char *mask, *mptr;
 
 	size = sizeof(struct ipt_entry);
-	for (m = iptables_matches; m; m = m->next) {
-		if (!m->used)
-			continue;
-
-		size += IPT_ALIGN(sizeof(struct ipt_entry_match)) + m->size;
-	}
+	for (matchp = matches; matchp; matchp = matchp->next)
+		size += IPT_ALIGN(sizeof(struct ipt_entry_match)) + matchp->match->size;
 
 	mask = fw_calloc(1, size
 			 + IPT_ALIGN(sizeof(struct ipt_entry_target))
@@ -1386,14 +1391,11 @@
 	memset(mask, 0xFF, sizeof(struct ipt_entry));
 	mptr = mask + sizeof(struct ipt_entry);
 
-	for (m = iptables_matches; m; m = m->next) {
-		if (!m->used)
-			continue;
-
+	for (matchp = matches; matchp; matchp = matchp->next) {
 		memset(mptr, 0xFF,
 		       IPT_ALIGN(sizeof(struct ipt_entry_match))
-		       + m->userspacesize);
-		mptr += IPT_ALIGN(sizeof(struct ipt_entry_match)) + m->size;
+		       + matchp->match->userspacesize);
+		mptr += IPT_ALIGN(sizeof(struct ipt_entry_match)) + matchp->match->size;
 	}
 
 	memset(mptr, 0xFF,
@@ -1411,13 +1413,14 @@
 	     unsigned int ndaddrs,
 	     const struct in_addr daddrs[],
 	     int verbose,
-	     iptc_handle_t *handle)
+	     iptc_handle_t *handle,
+	     struct iptables_rule_match *matches)
 {
 	unsigned int i, j;
 	int ret = 1;
 	unsigned char *mask;
 
-	mask = make_delete_mask(fw);
+	mask = make_delete_mask(fw, matches);
 	for (i = 0; i < nsaddrs; i++) {
 		fw->ip.src.s_addr = saddrs[i].s_addr;
 		for (j = 0; j < ndaddrs; j++) {
@@ -1616,20 +1619,16 @@
 
 static struct ipt_entry *
 generate_entry(const struct ipt_entry *fw,
-	       struct iptables_match *matches,
+	       struct iptables_rule_match *matches,
 	       struct ipt_entry_target *target)
 {
 	unsigned int size;
-	struct iptables_match *m;
+	struct iptables_rule_match *matchp;
 	struct ipt_entry *e;
 
 	size = sizeof(struct ipt_entry);
-	for (m = matches; m; m = m->next) {
-		if (!m->used)
-			continue;
-
-		size += m->m->u.match_size;
-	}
+	for (matchp = matches; matchp; matchp = matchp->next)
+		size += matchp->match->m->u.match_size;
 
 	e = fw_malloc(size + target->u.target_size);
 	*e = *fw;
@@ -1637,18 +1636,28 @@
 	e->next_offset = size + target->u.target_size;
 
 	size = 0;
-	for (m = matches; m; m = m->next) {
-		if (!m->used)
-			continue;
-
-		memcpy(e->elems + size, m->m, m->m->u.match_size);
-		size += m->m->u.match_size;
+	for (matchp = matches; matchp; matchp = matchp->next) {
+		memcpy(e->elems + size, matchp->match->m, matchp->match->m->u.match_size);
+		size += matchp->match->m->u.match_size;
 	}
 	memcpy(e->elems + size, target, target->u.target_size);
 
 	return e;
 }
 
+void clear_rule_matches(struct iptables_rule_match **matches)
+{
+	struct iptables_rule_match *matchp, *tmp;
+
+	for (matchp = *matches; matchp;) {
+		tmp = matchp->next;
+		free(matchp);
+		matchp = tmp;
+	}
+
+	*matches = NULL;
+}
+
 int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle)
 {
 	struct ipt_entry fw, *e = NULL;
@@ -1664,6 +1673,8 @@
 	const char *pcnt = NULL, *bcnt = NULL;
 	int ret = 1;
 	struct iptables_match *m;
+	struct iptables_rule_match *matches = NULL;
+	struct iptables_rule_match *matchp;
 	struct iptables_target *target = NULL;
 	struct iptables_target *t;
 	const char *jumpto = "";
@@ -1682,10 +1693,8 @@
 
 	/* clear mflags in case do_command gets called a second time
 	 * (we clear the global list of all matches for security)*/
-	for (m = iptables_matches; m; m = m->next) {
+	for (m = iptables_matches; m; m = m->next)
 		m->mflags = 0;
-		m->used = 0;
-	}
 
 	for (t = iptables_targets; t; t = t->next) {
 		t->tflags = 0;
@@ -1826,7 +1835,7 @@
 
 			/* iptables -p icmp -h */
 			if (!iptables_matches && protocol)
-				find_match(protocol, TRY_LOAD);
+				find_match(protocol, TRY_LOAD, NULL);
 
 			exit_printhelp();
 
@@ -1931,7 +1940,7 @@
 				exit_error(PARAMETER_PROBLEM,
 					   "unexpected ! flag before --match");
 
-			m = find_match(optarg, LOAD_MUST_SUCCEED);
+			m = find_match(optarg, LOAD_MUST_SUCCEED, &matches);
 			size = IPT_ALIGN(sizeof(struct ipt_entry_match))
 					 + m->size;
 			m->m = fw_calloc(1, size);
@@ -2023,18 +2032,16 @@
 					       argv, invert,
 					       &target->tflags,
 					       &fw, &target->t))) {
-				for (m = iptables_matches; m; m = m->next) {
-					if (!m->used)
-						continue;
-
-					if (m->parse(c - m->option_offset,
+				for (matchp = matches; matchp; matchp = matchp->next) {
+					if (matchp->match->parse(c - matchp->match->option_offset,
 						     argv, invert,
-						     &m->mflags,
+						     &matchp->match->mflags,
 						     &fw,
 						     &fw.nfcache,
-						     &m->m))
+						     &matchp->match->m))
 						break;
 				}
+				m = matchp ? matchp->match : NULL;
 
 				/* If you listen carefully, you can
 				   actually hear this code suck. */
@@ -2062,13 +2069,13 @@
 				if (m == NULL
 				    && protocol
 				    && (!find_proto(protocol, DONT_LOAD,
-						   options&OPT_NUMERIC) 
+						   options&OPT_NUMERIC, NULL) 
 					|| (find_proto(protocol, DONT_LOAD,
-							options&OPT_NUMERIC)
+							options&OPT_NUMERIC, NULL)
 					    && (proto_used == 0))
 				       )
 				    && (m = find_proto(protocol, TRY_LOAD,
-						       options&OPT_NUMERIC))) {
+						       options&OPT_NUMERIC, &matches))) {
 					/* Try loading protocol */
 					size_t size;
 					
@@ -2097,12 +2104,8 @@
 		invert = FALSE;
 	}
 
-	for (m = iptables_matches; m; m = m->next) {
-		if (!m->used)
-			continue;
-
-		m->final_check(m->mflags);
-	}
+	for (matchp = matches; matchp; matchp = matchp->next)
+		matchp->match->final_check(matchp->match->mflags);
 
 	if (target)
 		target->final_check(target->tflags);
@@ -2220,7 +2223,7 @@
 			 * chain. */
 			find_target(jumpto, LOAD_MUST_SUCCEED);
 		} else {
-			e = generate_entry(&fw, iptables_matches, target->t);
+			e = generate_entry(&fw, matches, target->t);
 		}
 	}
 
@@ -2235,7 +2238,7 @@
 		ret = delete_entry(chain, e,
 				   nsaddrs, saddrs, ndaddrs, daddrs,
 				   options&OPT_VERBOSE,
-				   handle);
+				   handle, matches);
 		break;
 	case CMD_DELETE_NUM:
 		ret = iptc_delete_num_entry(chain, rulenum - 1, handle);
@@ -2296,5 +2299,7 @@
 	if (verbose > 1)
 		dump_entries(*handle);
 
+	clear_rule_matches(&matches);
+
 	return ret;
 }