diff options
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 |
commit | 10163af3f4eb92a492fa99c95352bf8cd1a05e92 (patch) | |
tree | b77c8d881be4ec2a0e701e5bbd78ac6c6f0df111 | |
parent | e5f68b21a1c944aaa434d7ecc87fb5e98a9ee83a (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.c | 7 | ||||
-rw-r--r-- | extensions/libipt_SNAT.c | 7 | ||||
-rw-r--r-- | include/iptables.h | 9 | ||||
-rw-r--r-- | iptables.c | 18 |
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*/ @@ -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; |