diff options
-rw-r--r-- | iptables/ip6tables.c | 35 | ||||
-rw-r--r-- | iptables/iptables.8.in | 7 | ||||
-rw-r--r-- | iptables/iptables.c | 35 | ||||
-rw-r--r-- | iptables/xshared.c | 56 | ||||
-rw-r--r-- | iptables/xshared.h | 4 | ||||
-rw-r--r-- | iptables/xtables.c | 29 |
6 files changed, 149 insertions, 17 deletions
diff --git a/iptables/ip6tables.c b/iptables/ip6tables.c index c48ddf9e..66df8e99 100644 --- a/iptables/ip6tables.c +++ b/iptables/ip6tables.c @@ -103,6 +103,7 @@ static struct option original_opts[] = { {.name = "out-interface", .has_arg = 1, .val = 'o'}, {.name = "verbose", .has_arg = 0, .val = 'v'}, {.name = "wait", .has_arg = 2, .val = 'w'}, + {.name = "wait-interval", .has_arg = 2, .val = 'W'}, {.name = "exact", .has_arg = 0, .val = 'x'}, {.name = "version", .has_arg = 0, .val = 'V'}, {.name = "help", .has_arg = 2, .val = 'h'}, @@ -259,7 +260,10 @@ exit_printhelp(const struct xtables_rule_match *matches) " network interface name ([+] for wildcard)\n" " --table -t table table to manipulate (default: `filter')\n" " --verbose -v verbose mode\n" -" --wait -w [seconds] wait for the xtables lock\n" +" --wait -w [seconds] maximum wait to acquire xtables lock before give up\n" +" --wait-interval -W [usecs] wait time to try to acquire xtables lock\n" +" interval to wait for xtables lock\n" +" default is 1 second\n" " --line-numbers print line numbers when listing\n" " --exact -x expand numbers (display exact values)\n" /*"[!] --fragment -f match second or further fragments only\n"*/ @@ -1325,6 +1329,10 @@ int do_command6(int argc, char *argv[], char **table, int verbose = 0; int wait = 0; + struct timeval wait_interval = { + .tv_sec = 1, + }; + bool wait_interval_set = false; const char *chain = NULL; const char *shostnetworkmask = NULL, *dhostnetworkmask = NULL; const char *policy = NULL, *newname = NULL; @@ -1360,7 +1368,7 @@ int do_command6(int argc, char *argv[], char **table, opts = xt_params->orig_opts; while ((cs.c = getopt_long(argc, argv, - "-:A:C:D:R:I:L::S::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:bvw::nt:m:xc:g:46", + "-:A:C:D:R:I:L::S::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:bvw::W::nt:m:xc:g:46", opts, NULL)) != -1) { switch (cs.c) { /* @@ -1616,6 +1624,23 @@ int do_command6(int argc, char *argv[], char **table, "wait seconds not numeric"); break; + case 'W': + if (restore) { + xtables_error(PARAMETER_PROBLEM, + "You cannot use `-W' from " + "ip6tables-restore"); + } + if (optarg) + parse_wait_interval(optarg, &wait_interval); + else if (optind < argc && + argv[optind][0] != '-' && + argv[optind][0] != '!') + parse_wait_interval(argv[optind++], + &wait_interval); + + wait_interval_set = true; + break; + case 'm': command_match(&cs); break; @@ -1720,6 +1745,10 @@ int do_command6(int argc, char *argv[], char **table, cs.invert = FALSE; } + if (!wait && wait_interval_set) + xtables_error(PARAMETER_PROBLEM, + "--wait-interval only makes sense with --wait\n"); + if (strcmp(*table, "nat") == 0 && ((policy != NULL && strcmp(policy, "DROP") == 0) || (cs.jumpto != NULL && strcmp(cs.jumpto, "DROP") == 0))) @@ -1770,7 +1799,7 @@ int do_command6(int argc, char *argv[], char **table, generic_opt_check(command, cs.options); /* Attempt to acquire the xtables lock */ - if (!restore && !xtables_lock(wait)) { + if (!restore && !xtables_lock(wait, &wait_interval)) { fprintf(stderr, "Another app is currently holding the xtables lock. "); if (wait == 0) fprintf(stderr, "Perhaps you want to use the -w option?\n"); diff --git a/iptables/iptables.8.in b/iptables/iptables.8.in index 5a8c7ae1..a9c6b252 100644 --- a/iptables/iptables.8.in +++ b/iptables/iptables.8.in @@ -370,6 +370,13 @@ the program will exit if the lock cannot be obtained. This option will make the program wait (indefinitely or for optional \fIseconds\fP) until the exclusive lock can be obtained. .TP +\fB\-W\fP, \fB\-\-wait-interval\fP \fImicroseconds\fP +Interval to wait per each iteration. +When running latency sensitive applications, waiting for the xtables lock +for extended durations may not be acceptable. This option will make each +iteration take the amount of time specified. The default interval is +1 second. This option only works with \fB\-w\fP. +.TP \fB\-n\fP, \fB\-\-numeric\fP Numeric output. IP addresses and port numbers will be printed in numeric format. diff --git a/iptables/iptables.c b/iptables/iptables.c index 91617c24..540d1116 100644 --- a/iptables/iptables.c +++ b/iptables/iptables.c @@ -100,6 +100,7 @@ static struct option original_opts[] = { {.name = "out-interface", .has_arg = 1, .val = 'o'}, {.name = "verbose", .has_arg = 0, .val = 'v'}, {.name = "wait", .has_arg = 2, .val = 'w'}, + {.name = "wait-interval", .has_arg = 2, .val = 'W'}, {.name = "exact", .has_arg = 0, .val = 'x'}, {.name = "fragments", .has_arg = 0, .val = 'f'}, {.name = "version", .has_arg = 0, .val = 'V'}, @@ -253,7 +254,9 @@ exit_printhelp(const struct xtables_rule_match *matches) " network interface name ([+] for wildcard)\n" " --table -t table table to manipulate (default: `filter')\n" " --verbose -v verbose mode\n" -" --wait -w [seconds] wait for the xtables lock\n" +" --wait -w [seconds] maximum wait to acquire xtables lock before give up\n" +" --wait-interval -W [usecs] wait time to try to acquire xtables lock\n" +" default is 1 second\n" " --line-numbers print line numbers when listing\n" " --exact -x expand numbers (display exact values)\n" "[!] --fragment -f match second or further fragments only\n" @@ -1318,7 +1321,10 @@ int do_command4(int argc, char *argv[], char **table, unsigned int nsaddrs = 0, ndaddrs = 0; struct in_addr *saddrs = NULL, *smasks = NULL; struct in_addr *daddrs = NULL, *dmasks = NULL; - + struct timeval wait_interval = { + .tv_sec = 1, + }; + bool wait_interval_set = false; int verbose = 0; int wait = 0; const char *chain = NULL; @@ -1355,7 +1361,7 @@ int do_command4(int argc, char *argv[], char **table, opterr = 0; opts = xt_params->orig_opts; while ((cs.c = getopt_long(argc, argv, - "-:A:C:D:R:I:L::S::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:fbvw::nt:m:xc:g:46", + "-:A:C:D:R:I:L::S::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:fbvw::W::nt:m:xc:g:46", opts, NULL)) != -1) { switch (cs.c) { /* @@ -1609,6 +1615,23 @@ int do_command4(int argc, char *argv[], char **table, "wait seconds not numeric"); break; + case 'W': + if (restore) { + xtables_error(PARAMETER_PROBLEM, + "You cannot use `-W' from " + "iptables-restore"); + } + if (optarg) + parse_wait_interval(optarg, &wait_interval); + else if (optind < argc && + argv[optind][0] != '-' && + argv[optind][0] != '!') + parse_wait_interval(argv[optind++], + &wait_interval); + + wait_interval_set = true; + break; + case 'm': command_match(&cs); break; @@ -1709,6 +1732,10 @@ int do_command4(int argc, char *argv[], char **table, cs.invert = FALSE; } + if (!wait && wait_interval_set) + xtables_error(PARAMETER_PROBLEM, + "--wait-interval only makes sense with --wait\n"); + if (strcmp(*table, "nat") == 0 && ((policy != NULL && strcmp(policy, "DROP") == 0) || (cs.jumpto != NULL && strcmp(cs.jumpto, "DROP") == 0))) @@ -1759,7 +1786,7 @@ int do_command4(int argc, char *argv[], char **table, generic_opt_check(command, cs.options); /* Attempt to acquire the xtables lock */ - if (!restore && !xtables_lock(wait)) { + if (!restore && !xtables_lock(wait, &wait_interval)) { fprintf(stderr, "Another app is currently holding the xtables lock. "); if (wait == 0) fprintf(stderr, "Perhaps you want to use the -w option?\n"); diff --git a/iptables/xshared.c b/iptables/xshared.c index 81c2581f..cccb8aec 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -9,12 +9,15 @@ #include <sys/file.h> #include <sys/socket.h> #include <sys/un.h> +#include <sys/time.h> #include <unistd.h> #include <fcntl.h> #include <xtables.h> +#include <math.h> #include "xshared.h" #define XT_LOCK_NAME "/run/xtables.lock" +#define BASE_MICROSECONDS 100000 /* * Print out any special helps. A user might like to be able to add a --help @@ -244,9 +247,15 @@ void xs_init_match(struct xtables_match *match) match->init(match->m); } -bool xtables_lock(int wait) +bool xtables_lock(int wait, struct timeval *wait_interval) { - int fd, waited = 0, i = 0; + struct timeval time_left, wait_time, waited_time; + int fd, i = 0; + + time_left.tv_sec = wait; + time_left.tv_usec = 0; + waited_time.tv_sec = 0; + waited_time.tv_usec = 0; fd = open(XT_LOCK_NAME, O_CREAT, 0600); if (fd < 0) @@ -255,12 +264,43 @@ bool xtables_lock(int wait) while (1) { if (flock(fd, LOCK_EX | LOCK_NB) == 0) return true; - else if (wait >= 0 && waited >= wait) + if (++i % 10 == 0) { + if (wait != -1) + fprintf(stderr, "Another app is currently holding the xtables lock; " + "still %lds %ldus time ahead to have a chance to grab the lock...\n", + time_left.tv_sec, time_left.tv_usec); + else + fprintf(stderr, "Another app is currently holding the xtables lock; " + "waiting for it to exit...\n"); + } + + wait_time = *wait_interval; + select(0, NULL, NULL, NULL, &wait_time); + if (wait == -1) + continue; + + timeradd(&waited_time, wait_interval, &waited_time); + timersub(&time_left, wait_interval, &time_left); + if (!timerisset(&time_left)) return false; - if (++i % 2 == 0) - fprintf(stderr, "Another app is currently holding the xtables lock; " - "waiting (%ds) for it to exit...\n", waited); - waited++; - sleep(1); } } + +void parse_wait_interval(const char *str, struct timeval *wait_interval) +{ + unsigned int usec; + int ret; + + ret = sscanf(str, "%u", &usec); + if (ret == 1) { + if (usec > 999999) + xtables_error(PARAMETER_PROBLEM, + "too long usec wait %u > 999999 usec", + usec); + + wait_interval->tv_sec = 0; + wait_interval->tv_usec = usec; + return; + } + xtables_error(PARAMETER_PROBLEM, "wait interval not numeric"); +} diff --git a/iptables/xshared.h b/iptables/xshared.h index 40dd9154..6eb8eb86 100644 --- a/iptables/xshared.h +++ b/iptables/xshared.h @@ -85,7 +85,9 @@ extern struct xtables_match *load_proto(struct iptables_command_state *); extern int subcmd_main(int, char **, const struct subcommand *); extern void xs_init_target(struct xtables_target *); extern void xs_init_match(struct xtables_match *); -extern bool xtables_lock(int wait); +bool xtables_lock(int wait, struct timeval *wait_interval); + +void parse_wait_interval(const char *str, struct timeval *wait_interval); extern const struct xtables_afinfo *afinfo; diff --git a/iptables/xtables.c b/iptables/xtables.c index ecd577c3..48b9c51c 100644 --- a/iptables/xtables.c +++ b/iptables/xtables.c @@ -86,6 +86,7 @@ static struct option original_opts[] = { {.name = "out-interface", .has_arg = 1, .val = 'o'}, {.name = "verbose", .has_arg = 0, .val = 'v'}, {.name = "wait", .has_arg = 2, .val = 'w'}, + {.name = "wait-interval", .has_arg = 2, .val = 'W'}, {.name = "exact", .has_arg = 0, .val = 'x'}, {.name = "fragments", .has_arg = 0, .val = 'f'}, {.name = "version", .has_arg = 0, .val = 'V'}, @@ -239,6 +240,9 @@ exit_printhelp(const struct xtables_rule_match *matches) " network interface name ([+] for wildcard)\n" " --table -t table table to manipulate (default: `filter')\n" " --verbose -v verbose mode\n" +" --wait -w [seconds] maximum wait to acquire xtables lock before give up\n" +" --wait-interval -W [usecs] wait time to try to acquire xtables lock\n" +" default is 1 second\n" " --line-numbers print line numbers when listing\n" " --exact -x expand numbers (display exact values)\n" "[!] --fragment -f match second or further fragments only\n" @@ -685,6 +689,8 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], { struct xtables_match *m; struct xtables_rule_match *matchp; + bool wait_interval_set = false; + struct timeval wait_interval; struct xtables_target *t; int wait = 0; @@ -716,7 +722,7 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], opts = xt_params->orig_opts; while ((cs->c = getopt_long(argc, argv, - "-:A:C:D:R:I:L::S::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:fbvw::nt:m:xc:g:46", + "-:A:C:D:R:I:L::S::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:fbvw::W::nt:m:xc:g:46", opts, NULL)) != -1) { switch (cs->c) { /* @@ -1019,6 +1025,23 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], "wait seconds not numeric"); break; + case 'W': + if (p->restore) { + xtables_error(PARAMETER_PROBLEM, + "You cannot use `-W' from " + "iptables-restore"); + } + if (optarg) + parse_wait_interval(optarg, &wait_interval); + else if (optind < argc && + argv[optind][0] != '-' && + argv[optind][0] != '!') + parse_wait_interval(argv[optind++], + &wait_interval); + + wait_interval_set = true; + break; + case '0': set_option(&cs->options, OPT_LINENUMBERS, &args->invflags, cs->invert); @@ -1101,6 +1124,10 @@ void do_parse(struct nft_handle *h, int argc, char *argv[], "\nThe \"nat\" table is not intended for filtering, " "the use of DROP is therefore inhibited.\n\n"); + if (!wait && wait_interval_set) + xtables_error(PARAMETER_PROBLEM, + "--wait-interval only makes sense with --wait\n"); + for (matchp = cs->matches; matchp; matchp = matchp->next) xtables_option_mfcall(matchp->match); if (cs->target != NULL) |