summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
author/C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=laforge/emailAddress=laforge@netfilter.org </C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=laforge/emailAddress=laforge@netfilter.org>2005-09-19 15:00:33 +0000
committer/C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=laforge/emailAddress=laforge@netfilter.org </C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=laforge/emailAddress=laforge@netfilter.org>2005-09-19 15:00:33 +0000
commit10163af3f4eb92a492fa99c95352bf8cd1a05e92 (patch)
treeb77c8d881be4ec2a0e701e5bbd78ac6c6f0df111
parente5f68b21a1c944aaa434d7ecc87fb5e98a9ee83a (diff)
Kernels higher than 2.6.10 don't support multiple --to arguments in
DNAT and SNAT targets. At present, the error is somewhat vague: # iptables -t nat -A foo -j SNAT --to 1.2.3.4 --to 2.3.4.5 iptables: Invalid argument But if we want current iptables to work with kernels <= 2.6.10, we cannot simply disallow this in all cases. So the below patch adds kernel version checking to iptables, and utilizes it in [DS]NAT. Now, users will see a more informative error: # iptables -t nat -A foo -j SNAT --to 1.2.3.4 --to 2.3.4.5 iptables v1.3.3: Multiple --to-source not supported This generic infrastructure (shamelessly lifted from procps btw) may come in handy in the future for other changes. This fixes bugzilla #367. (Phil Oester)
-rw-r--r--extensions/libipt_DNAT.c7
-rw-r--r--extensions/libipt_SNAT.c7
-rw-r--r--include/iptables.h9
-rw-r--r--iptables.c18
4 files changed, 41 insertions, 0 deletions
diff --git a/extensions/libipt_DNAT.c b/extensions/libipt_DNAT.c
index 3b0d146..bdc15eb 100644
--- a/extensions/libipt_DNAT.c
+++ b/extensions/libipt_DNAT.c
@@ -155,6 +155,13 @@ parse(int c, char **argv, int invert, unsigned int *flags,
exit_error(PARAMETER_PROBLEM,
"Unexpected `!' after --to-destination");
+ if (*flags) {
+ if (!kernel_version)
+ get_kernel_version();
+ if (kernel_version > LINUX_VERSION(2, 6, 10))
+ exit_error(PARAMETER_PROBLEM,
+ "Multiple --to-destination not supported");
+ }
*target = parse_to(optarg, portok, info);
*flags = 1;
return 1;
diff --git a/extensions/libipt_SNAT.c b/extensions/libipt_SNAT.c
index 7460760..867c9d0 100644
--- a/extensions/libipt_SNAT.c
+++ b/extensions/libipt_SNAT.c
@@ -155,6 +155,13 @@ parse(int c, char **argv, int invert, unsigned int *flags,
exit_error(PARAMETER_PROBLEM,
"Unexpected `!' after --to-source");
+ if (*flags) {
+ if (!kernel_version)
+ get_kernel_version();
+ if (kernel_version > LINUX_VERSION(2, 6, 10))
+ exit_error(PARAMETER_PROBLEM,
+ "Multiple --to-source not supported");
+ }
*target = parse_to(optarg, portok, info);
*flags = 1;
return 1;
diff --git a/include/iptables.h b/include/iptables.h
index f0cad8d..fbcf2eb 100644
--- a/include/iptables.h
+++ b/include/iptables.h
@@ -175,4 +175,13 @@ extern int flush_entries(const ipt_chainlabel chain, int verbose,
iptc_handle_t *handle);
extern int for_each_chain(int (*fn)(const ipt_chainlabel, int, iptc_handle_t *),
int verbose, int builtinstoo, iptc_handle_t *handle);
+
+/* kernel revision handling */
+extern int kernel_version;
+extern void get_kernel_version(void);
+#define LINUX_VERSION(x,y,z) (0x10000*(x) + 0x100*(y) + z)
+#define LINUX_VERSION_MAJOR(x) (((x)>>16) & 0xFF)
+#define LINUX_VERSION_MINOR(x) (((x)>> 8) & 0xFF)
+#define LINUX_VERSION_PATCH(x) ( (x) & 0xFF)
+
#endif /*_IPTABLES_USER_H*/
diff --git a/iptables.c b/iptables.c
index 7e8ba59..aec9613 100644
--- a/iptables.c
+++ b/iptables.c
@@ -39,6 +39,7 @@
#include <iptables.h>
#include <fcntl.h>
#include <sys/wait.h>
+#include <sys/utsname.h>
#ifndef TRUE
#define TRUE 1
@@ -193,6 +194,8 @@ const char *program_version;
const char *program_name;
char *lib_dir;
+int kernel_version;
+
/* Keeping track of external matches and targets: linked lists. */
struct iptables_match *iptables_matches = NULL;
struct iptables_target *iptables_targets = NULL;
@@ -1804,6 +1807,21 @@ static void set_revision(char *name, u_int8_t revision)
name[IPT_FUNCTION_MAXNAMELEN - 1] = revision;
}
+void
+get_kernel_version(void) {
+ static struct utsname uts;
+ int x = 0, y = 0, z = 0;
+
+ if (uname(&uts) == -1) {
+ fprintf(stderr, "Unable to retrieve kernel version.\n");
+ free_opts(1);
+ exit(1);
+ }
+
+ sscanf(uts.release, "%d.%d.%d", &x, &y, &z);
+ kernel_version = LINUX_VERSION(x, y, z);
+}
+
int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle)
{
struct ipt_entry fw, *e = NULL;