diff --git a/docs/changes.txt b/docs/changes.txt index ac9e913..f9d2934 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -168,3 +168,4 @@ v0.8.1 * nfqws2, zapret-lib: gzip compression and decompression * nfqws2: ignore trailing spaces and tabs in hostlists and ipsets. "host.com " or "1.2.3.4 " are ok now * init.d: 99-lan-filter custom script +* mdig: --eagain, --eagain-delay diff --git a/docs/manual.md b/docs/manual.md index 675cbb6..5cd5d07 100644 --- a/docs/manual.md +++ b/docs/manual.md @@ -4324,8 +4324,10 @@ ip2net фильтрует входные данные, выкидывая неп Она берет из stdin список доменов и выводит в stdout результат ресолвинга. Ошибки выводятся в stderr. ``` ---threads= ; количество потоков. по умолчанию 1. --family=<4|6|46> ; выбор семейства IP адресов : ipv4, ipv6, ipv4+ipv6 +--threads= ; количество потоков. по умолчанию 1. +--eagain= ; количество попыток повтора после EAGAIN. по умолчанию 10 +--eagain-delay= ; время ожидания в мсек между повторами по EAGAIN. по умолчанию 500. --verbose ; дебаг-лог на консоль --stats=N ; выводить статистику каждые N доменов --log-resolved= ; сохранять успешно отресолвленные домены в файл diff --git a/mdig/mdig.c b/mdig/mdig.c index 7873e08..d5f327a 100644 --- a/mdig/mdig.c +++ b/mdig/mdig.c @@ -30,7 +30,8 @@ #endif #include -#define RESOLVER_EAGAIN_ATTEMPTS 3 +#define RESOLVER_EAGAIN_ATTEMPTS 10 +#define RESOLVER_EAGAIN_DELAY 500 static void trimstr(char *s) { @@ -97,7 +98,7 @@ static struct { char verbose; char family; - int threads; + int threads, eagain, eagain_delay; time_t start_time; pthread_mutex_t flock; pthread_mutex_t slock; // stats lock @@ -193,11 +194,12 @@ static void *t_resolver(void *arg) int i, r; char dom[256]; bool is_ok; - struct addrinfo hints; - struct addrinfo *result; + struct addrinfo hints, *result; + struct timespec ts_eagain = { .tv_sec = glob.eagain_delay/1000, .tv_nsec=glob.eagain_delay%1000*1000000 }; VLOG("started"); + memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = (glob.family == FAMILY4) ? AF_INET : (glob.family == FAMILY6) ? AF_INET6 : AF_UNSPEC; hints.ai_socktype = SOCK_DGRAM; @@ -244,12 +246,16 @@ static void *t_resolver(void *arg) else if (dom_valid(dom)) { VLOG("resolving %s", dom); - for (i = 0; i < RESOLVER_EAGAIN_ATTEMPTS; i++) + for (i = 0; i < glob.eagain; i++) { if ((r = getaddrinfo(dom, NULL, &hints, &result))) { VLOG("failed to resolve %s : result %d (%s)", dom, r, eai_str(r)); - if (r == EAI_AGAIN) continue; // temporary failure. should retry + if (r == EAI_AGAIN) + { + nanosleep(&ts_eagain, NULL); + continue; // temporary failure. should retry + } } else { @@ -447,14 +453,18 @@ int dns_parse_query() static void exithelp(void) { printf( - " --threads=\n" " --family=<4|6|46>\t\t; ipv4, ipv6, ipv4+ipv6\n" + " --threads=\n" + " --eagain=\t; how many times to retry if EAGAIN received. default %u\n" + " --eagain-delay=\t\t; time in msec to wait between EAGAIN attempts. default %u\n" " --verbose\t\t\t; print query progress to stderr\n" " --stats=N\t\t\t; print resolve stats to stderr every N domains\n" " --log-resolved=\t\t; log successfully resolved domains to a file\n" " --log-failed=\t\t; log failed domains to a file\n" " --dns-make-query=\t; output to stdout binary blob with DNS query. use --family to specify ip version.\n" - " --dns-parse-query\t\t; read from stdin binary DNS answer blob and parse it to ipv4/ipv6 addresses\n" + " --dns-parse-query\t\t; read from stdin binary DNS answer blob and parse it to ipv4/ipv6 addresses\n", + RESOLVER_EAGAIN_ATTEMPTS, + RESOLVER_EAGAIN_DELAY ); exit(1); } @@ -469,6 +479,8 @@ static void exithelp(void) enum opt_indices { IDX_HELP, + IDX_EAGAIN, + IDX_EAGAIN_DELAY, IDX_THREADS, IDX_FAMILY, IDX_VERBOSE, @@ -483,6 +495,8 @@ enum opt_indices { static const struct option long_options[] = { [IDX_HELP] = {"help", no_argument, 0, 0}, [IDX_THREADS] = {"threads", required_argument, 0, 0}, + [IDX_EAGAIN] = {"eagain", required_argument, 0, 0}, + [IDX_EAGAIN_DELAY] = {"eagain-delay", required_argument, 0, 0}, [IDX_FAMILY] = {"family", required_argument, 0, 0}, [IDX_VERBOSE] = {"verbose", no_argument, 0, 0}, [IDX_STATS] = {"stats", required_argument, 0, 0}, @@ -503,6 +517,8 @@ int main(int argc, char **argv) *fn1 = *fn2 = *dom = 0; glob.family = FAMILY4; glob.threads = 1; + glob.eagain = RESOLVER_EAGAIN_ATTEMPTS; + glob.eagain_delay = RESOLVER_EAGAIN_DELAY; while ((v = getopt_long_only(argc, argv, "", long_options, &option_index)) != -1) { if (v) exithelp(); @@ -513,13 +529,29 @@ int main(int argc, char **argv) exithelp(); break; case IDX_THREADS: - glob.threads = optarg ? atoi(optarg) : 0; + glob.threads = atoi(optarg); if (glob.threads <= 0 || glob.threads > 100) { fprintf(stderr, "thread number must be within 1..100\n"); return 1; } break; + case IDX_EAGAIN: + glob.eagain = atoi(optarg); + if (glob.eagain <= 0 || glob.eagain > 1000) + { + fprintf(stderr, "eagain must be within 1..1000\n"); + return 1; + } + break; + case IDX_EAGAIN_DELAY: + glob.eagain_delay = atoi(optarg); + if (glob.eagain_delay < 0 || glob.eagain_delay > 100000) + { + fprintf(stderr, "eagain-delay must be within 0..100000\n"); + return 1; + } + break; case IDX_FAMILY: if (!strcmp(optarg, "4")) glob.family = FAMILY4;