summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--iptables.c70
1 files changed, 55 insertions, 15 deletions
diff --git a/iptables.c b/iptables.c
index cd3c1fe2..fa570c5c 100644
--- a/iptables.c
+++ b/iptables.c
@@ -1659,6 +1659,7 @@ int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle)
const char *jumpto = "";
char *protocol = NULL;
const char *modprobe = NULL;
+ int proto_used = 0;
memset(&fw, 0, sizeof(fw));
@@ -1686,7 +1687,7 @@ int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle)
opterr = 0;
while ((c = getopt_long(argc, argv,
- "-A:C:D:R:I:L::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:fbvnt:m:xc:",
+ "-A:D:R:I:L::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:fbvnt:m:xc:",
opts, NULL)) != -1) {
switch (c) {
/*
@@ -1839,20 +1840,6 @@ int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle)
exit_error(PARAMETER_PROBLEM,
"rule would never match protocol");
fw.nfcache |= NFC_IP_PROTO;
-
- /* try to load match with protocol name */
- if ((m = find_proto(protocol, TRY_LOAD,
- options&OPT_NUMERIC))) {
- size_t size;
- size = IPT_ALIGN(sizeof(struct ipt_entry_match))
- + m->size;
- m->m = fw_calloc(1, size);
- m->m->u.match_size = size;
- strcpy(m->m->u.user.name, m->name);
- m->init(m->m, &fw.nfcache);
- opts = merge_options(opts, m->extra_opts, &m->option_offset);
- }
-
break;
case 's':
@@ -2038,6 +2025,59 @@ int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle)
&m->m))
break;
}
+
+ /* If you listen carefully, you can
+ actually hear this code suck. */
+
+ /* some explanations (after four different bugs
+ * in 3 different releases): If we encountere a
+ * parameter, that has not been parsed yet,
+ * it's not an option of an explicitly loaded
+ * match or a target. However, we support
+ * implicit loading of the protocol match
+ * extension. '-p tcp' means 'l4 proto 6' and
+ * at the same time 'load tcp protocol match on
+ * demand if we specify --dport'.
+ *
+ * To make this work, we need to make sure:
+ * - the parameter has not been parsed by
+ * a match (m above)
+ * - a protocol has been specified
+ * - the protocol extension has not been
+ * loaded yet, or is loaded and unused
+ * [think of iptables-restore!]
+ * - the protocol extension can be successively
+ * loaded
+ */
+ if (m == NULL
+ && protocol
+ && (!find_proto(protocol, DONT_LOAD,
+ options&OPT_NUMERIC)
+ || (find_proto(protocol, DONT_LOAD,
+ options&OPT_NUMERIC)
+ && (proto_used == 0))
+ )
+ && (m = find_proto(protocol, TRY_LOAD,
+ options&OPT_NUMERIC))) {
+ /* Try loading protocol */
+ size_t size;
+
+ proto_used = 1;
+
+ size = IPT_ALIGN(sizeof(struct ipt_entry_match))
+ + m->size;
+
+ m->m = fw_calloc(1, size);
+ m->m->u.match_size = size;
+ strcpy(m->m->u.user.name, m->name);
+ m->init(m->m, &fw.nfcache);
+
+ opts = merge_options(opts,
+ m->extra_opts, &m->option_offset);
+
+ optind--;
+ continue;
+ }
if (!m)
exit_error(PARAMETER_PROBLEM,
"Unknown arg `%s'",