summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoszef Kadlecsik <kadlec@blackhole.kfki.hu>2006-03-03 09:36:50 +0000
committerJoszef Kadlecsik <kadlec@blackhole.kfki.hu>2006-03-03 09:36:50 +0000
commita258ad7002ae4b4f366800f512db938fb78d0661 (patch)
treea219981be0b1354e72a323b25cc044a692234d2c
parentcbe1ec7f1592be8ff2d71fd93374593dceabf3c0 (diff)
Multiple matches of the same type can be specified on the commandline.
If two or more matches of the same type are detected then the options are assumed to be grouped in order to tell which option belongs to which match: ... -m foo ... <options0> ... -m foo ... <options1> ... Otherwise the commandline parsing is unmodified.
-rw-r--r--include/ip6tables.h4
-rw-r--r--include/iptables.h4
-rw-r--r--ip6tables.c69
-rw-r--r--iptables.c39
4 files changed, 84 insertions, 32 deletions
diff --git a/include/ip6tables.h b/include/ip6tables.h
index 549e0415..d5ea878e 100644
--- a/include/ip6tables.h
+++ b/include/ip6tables.h
@@ -13,6 +13,10 @@ struct ip6tables_rule_match
struct ip6tables_rule_match *next;
struct ip6tables_match *match;
+
+ /* Multiple matches of the same type: the ones before
+ the current one are completed from parsing point of view */
+ unsigned int completed;
};
/* Include file for additions: new matches and targets. */
diff --git a/include/iptables.h b/include/iptables.h
index bf71e526..c56a0057 100644
--- a/include/iptables.h
+++ b/include/iptables.h
@@ -29,6 +29,10 @@ struct iptables_rule_match
struct iptables_rule_match *next;
struct iptables_match *match;
+
+ /* Multiple matches of the same type: the ones before
+ the current one are completed from parsing point of view */
+ unsigned int completed;
};
/* Include file for additions: new matches and targets. */
diff --git a/ip6tables.c b/ip6tables.c
index 9396d034..dcf7d367 100644
--- a/ip6tables.c
+++ b/ip6tables.c
@@ -709,37 +709,46 @@ parse_hostnetworkmask(const char *name, struct in6_addr **addrpp,
}
struct ip6tables_match *
-find_match(const char *name, enum ip6t_tryload tryload, struct ip6tables_rule_match **matches)
+find_match(const char *match_name, enum ip6t_tryload tryload, struct ip6tables_rule_match **matches)
{
struct ip6tables_match *ptr;
- int icmphack = 0;
+ const char *icmp6 = "icmp6";
+ const char *name;
/* This is ugly as hell. Nonetheless, there is no way of changing
* this without hurting backwards compatibility */
- if ( (strcmp(name,"icmpv6") == 0) ||
- (strcmp(name,"ipv6-icmp") == 0) ||
- (strcmp(name,"icmp6") == 0) ) icmphack = 1;
+ if ( (strcmp(match_name,"icmpv6") == 0) ||
+ (strcmp(match_name,"ipv6-icmp") == 0) ||
+ (strcmp(match_name,"icmp6") == 0) )
+ name = icmp6;
+ else
+ name = match_name;
- if (!icmphack) {
- for (ptr = ip6tables_matches; ptr; ptr = ptr->next) {
- if (strcmp(name, ptr->name) == 0)
- break;
- }
- } else {
- for (ptr = ip6tables_matches; ptr; ptr = ptr->next) {
- if (strcmp("icmp6", ptr->name) == 0)
- break;
- }
- }
+ for (ptr = ip6tables_matches; ptr; ptr = ptr->next) {
+ if (strcmp(name, ptr->name) == 0) {
+ struct ip6tables_match *clone;
+
+ /* First match of this type: */
+ if (ptr->m == NULL)
+ break;
+
+ /* Second and subsequent clones */
+ clone = fw_malloc(sizeof(struct ip6tables_match));
+ memcpy(clone, ptr, sizeof(struct ip6tables_match));
+ clone->mflags = 0;
+ /* This is a clone: */
+ clone->next = clone;
+
+ ptr = clone;
+ break;
+ }
+ }
#ifndef NO_SHARED_LIBS
if (!ptr && tryload != DONT_LOAD && tryload != DURING_LOAD) {
char path[strlen(lib_dir) + sizeof("/libip6t_.so")
+ strlen(name)];
- if (!icmphack)
- sprintf(path, "%s/libip6t_%s.so", lib_dir, name);
- else
- sprintf(path, "%s/libip6t_%s.so", lib_dir, "icmpv6");
+ sprintf(path, "%s/libip6t_%s.so", lib_dir, name);
if (dlopen(path, RTLD_NOW)) {
/* Found library. If it didn't register itself,
maybe they specified target as match. */
@@ -773,8 +782,12 @@ find_match(const char *name, enum ip6t_tryload tryload, struct ip6tables_rule_ma
newentry = fw_malloc(sizeof(struct ip6tables_rule_match));
- for (i = matches; *i; i = &(*i)->next);
+ for (i = matches; *i; i = &(*i)->next) {
+ if (strcmp(name, (*i)->match->name) == 0)
+ (*i)->completed = 1;
+ }
newentry->match = ptr;
+ newentry->completed = 0;
newentry->next = NULL;
*i = newentry;
}
@@ -1701,6 +1714,10 @@ void clear_rule_matches(struct ip6tables_rule_match **matches)
free(matchp->match->m);
matchp->match->m = NULL;
}
+ if (matchp->match == matchp->match->next) {
+ free(matchp->match);
+ matchp->match = NULL;
+ }
free(matchp);
matchp = tmp;
}
@@ -1988,7 +2005,9 @@ int do_command6(int argc, char *argv[], char **table, ip6tc_handle_t *handle)
strcpy(m->m->u.user.name, m->name);
if (m->init != NULL)
m->init(m->m, &fw.nfcache);
- opts = merge_options(opts, m->extra_opts, &m->option_offset);
+ if (m != m->next)
+ /* Merge options for non-cloned matches */
+ opts = merge_options(opts, m->extra_opts, &m->option_offset);
}
break;
@@ -2066,14 +2085,14 @@ int do_command6(int argc, char *argv[], char **table, ip6tc_handle_t *handle)
exit_tryhelp(2);
default:
- /* FIXME: This scheme doesn't allow two of the same
- matches --RR */
if (!target
|| !(target->parse(c - target->option_offset,
argv, invert,
&target->tflags,
&fw, &target->t))) {
for (matchp = matches; matchp; matchp = matchp->next) {
+ if (matchp->completed)
+ continue;
if (matchp->match->parse(c - matchp->match->option_offset,
argv, invert,
&matchp->match->mflags,
@@ -2088,7 +2107,7 @@ int do_command6(int argc, char *argv[], char **table, ip6tc_handle_t *handle)
actually hear this code suck. */
/* some explanations (after four different bugs
- * in 3 different releases): If we encountere a
+ * in 3 different releases): If we encounter a
* parameter, that has not been parsed yet,
* it's not an option of an explicitly loaded
* match or a target. However, we support
diff --git a/iptables.c b/iptables.c
index c8ab71ec..e79d64f1 100644
--- a/iptables.c
+++ b/iptables.c
@@ -679,9 +679,24 @@ find_match(const char *name, enum ipt_tryload tryload, struct iptables_rule_matc
struct iptables_match *ptr;
for (ptr = iptables_matches; ptr; ptr = ptr->next) {
- if (strcmp(name, ptr->name) == 0)
+ if (strcmp(name, ptr->name) == 0) {
+ struct iptables_match *clone;
+
+ /* First match of this type: */
+ if (ptr->m == NULL)
+ break;
+
+ /* Second and subsequent clones */
+ clone = fw_malloc(sizeof(struct iptables_match));
+ memcpy(clone, ptr, sizeof(struct iptables_match));
+ clone->mflags = 0;
+ /* This is a clone: */
+ clone->next = clone;
+
+ ptr = clone;
break;
- }
+ }
+ }
#ifndef NO_SHARED_LIBS
if (!ptr && tryload != DONT_LOAD && tryload != DURING_LOAD) {
@@ -721,8 +736,12 @@ find_match(const char *name, enum ipt_tryload tryload, struct iptables_rule_matc
newentry = fw_malloc(sizeof(struct iptables_rule_match));
- for (i = matches; *i; i = &(*i)->next);
+ for (i = matches; *i; i = &(*i)->next) {
+ if (strcmp(name, (*i)->match->name) == 0)
+ (*i)->completed = 1;
+ }
newentry->match = ptr;
+ newentry->completed = 0;
newentry->next = NULL;
*i = newentry;
}
@@ -1810,6 +1829,10 @@ void clear_rule_matches(struct iptables_rule_match **matches)
free(matchp->match->m);
matchp->match->m = NULL;
}
+ if (matchp->match == matchp->match->next) {
+ free(matchp->match);
+ matchp->match = NULL;
+ }
free(matchp);
matchp = tmp;
}
@@ -2134,7 +2157,9 @@ int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle)
set_revision(m->m->u.user.name, m->revision);
if (m->init != NULL)
m->init(m->m, &fw.nfcache);
- opts = merge_options(opts, m->extra_opts, &m->option_offset);
+ if (m != m->next)
+ /* Merge options for non-cloned matches */
+ opts = merge_options(opts, m->extra_opts, &m->option_offset);
}
break;
@@ -2212,14 +2237,14 @@ int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle)
exit_tryhelp(2);
default:
- /* FIXME: This scheme doesn't allow two of the same
- matches --RR */
if (!target
|| !(target->parse(c - target->option_offset,
argv, invert,
&target->tflags,
&fw, &target->t))) {
for (matchp = matches; matchp; matchp = matchp->next) {
+ if (matchp->completed)
+ continue;
if (matchp->match->parse(c - matchp->match->option_offset,
argv, invert,
&matchp->match->mflags,
@@ -2234,7 +2259,7 @@ int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle)
actually hear this code suck. */
/* some explanations (after four different bugs
- * in 3 different releases): If we encountere a
+ * in 3 different releases): If we encounter a
* parameter, that has not been parsed yet,
* it's not an option of an explicitly loaded
* match or a target. However, we support