diff --git a/binaries/aarch64/mdig b/binaries/aarch64/mdig index 7114607..42382ae 100755 Binary files a/binaries/aarch64/mdig and b/binaries/aarch64/mdig differ diff --git a/binaries/arm/mdig b/binaries/arm/mdig index c862932..beff0d1 100755 Binary files a/binaries/arm/mdig and b/binaries/arm/mdig differ diff --git a/binaries/freebsd-x64/mdig b/binaries/freebsd-x64/mdig index 0b67ab7..df27435 100755 Binary files a/binaries/freebsd-x64/mdig and b/binaries/freebsd-x64/mdig differ diff --git a/binaries/mac64/mdig b/binaries/mac64/mdig index d466430..fc35eaa 100755 Binary files a/binaries/mac64/mdig and b/binaries/mac64/mdig differ diff --git a/binaries/mips32r1-lsb/mdig b/binaries/mips32r1-lsb/mdig index c7bebc9..187ecea 100755 Binary files a/binaries/mips32r1-lsb/mdig and b/binaries/mips32r1-lsb/mdig differ diff --git a/binaries/mips32r1-msb/mdig b/binaries/mips32r1-msb/mdig index 482096a..4fa97bf 100755 Binary files a/binaries/mips32r1-msb/mdig and b/binaries/mips32r1-msb/mdig differ diff --git a/binaries/mips64r2-msb/mdig b/binaries/mips64r2-msb/mdig index 05e95f3..314e3bd 100755 Binary files a/binaries/mips64r2-msb/mdig and b/binaries/mips64r2-msb/mdig differ diff --git a/binaries/ppc/mdig b/binaries/ppc/mdig index 8a12238..3d966ef 100755 Binary files a/binaries/ppc/mdig and b/binaries/ppc/mdig differ diff --git a/binaries/win64/mdig.exe b/binaries/win64/mdig.exe index 8006737..00b50ac 100644 Binary files a/binaries/win64/mdig.exe and b/binaries/win64/mdig.exe differ diff --git a/binaries/x86/mdig b/binaries/x86/mdig index 0f1f801..cca353a 100755 Binary files a/binaries/x86/mdig and b/binaries/x86/mdig differ diff --git a/binaries/x86_64/mdig b/binaries/x86_64/mdig index 382e4db..d34af6b 100755 Binary files a/binaries/x86_64/mdig and b/binaries/x86_64/mdig differ diff --git a/docs/changes.txt b/docs/changes.txt index 226ed9e..17815f2 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -341,3 +341,7 @@ v66: init.d: rewrite traffic interception and daemon launch parameters in config file. this break compatibility with old versions. init.d: openwrt-minimal : tpws launch for low storage openwrt devices + +v67: + +mdig: --dns-make-query, --dns-parse-query for side-channel resolving (DoH) diff --git a/docs/readme.txt b/docs/readme.txt index e99041b..e623e2b 100644 --- a/docs/readme.txt +++ b/docs/readme.txt @@ -1098,6 +1098,26 @@ ip2net фильтрует входные данные, выкидывая неп Не надо делать такое : 5000000/10000000. 1/2 - гораздо лучше. +mdig +---- + +Программа предназначена для многопоточного ресолвинга больших листов через системный DNS. +Она берет из stdin список доменов и выводит в stdout результат ресолвинга. Ошибки выводятся в stderr. + + --threads= ; количество потоков. по умолчанию 1. + --family=<4|6|46> ; выбор семейства IP адресов : ipv4, ipv6, ipv4+ipv6 + --verbose ; дебаг-лог на консоль + --stats=N ; выводить статистику каждые N доменов + --log-resolved= ; сохранять успешно отресолвленные домены в файл + --log-failed= ; сохранять неудачно отресолвленные домены в файл + --dns-make-query= ; вывести в stdout бинарный DNS запрос по домену. если --family=6, запрос будет AAAA, иначе A. + --dns-parse-query ; распарсить бинарный DNS ответ и выдать все ivp4 и ipv6 адреса из него в stdout + +Параметры --dns-make-query и --dns-parse-query позволяют провести ресолвинг одного домена через произвольный канал. +Например, следующим образом можно выполнить DoH запрос, используя лишь mdig и curl : +mdig --family=6 --dns-make-query=rutracker.org | curl --data-binary @- -H "Content-Type: application/dns-message" https://cloudflare-dns.com/dns-query | mdig --dns-parse-query + + Фильтрация по именам доменов ---------------------------- diff --git a/mdig/mdig.c b/mdig/mdig.c index 047e7b6..d50c1cc 100644 --- a/mdig/mdig.c +++ b/mdig/mdig.c @@ -319,15 +319,135 @@ static int run_threads(void) return thread ? 0 : 12; } +// slightly patched musl code +size_t dns_mk_query_blob(uint8_t op, const char *dname, uint8_t class, uint8_t type, uint8_t *buf, size_t buflen) +{ + int i, j; + uint16_t id; + struct timespec ts; + size_t l = strnlen(dname, 255); + size_t n; + + if (l && dname[l-1]=='.') l--; + if (l && dname[l-1]=='.') return 0; + n = 17+l+!!l; + if (l>253 || buflen15u) return 0; + + /* Construct query template - ID will be filled later */ + memset(buf, 0, n); + buf[2] = (op<<3) | 1; + buf[5] = 1; + memcpy((char *)buf+13, dname, l); + for (i=13; buf[i]; i=j+1) + { + for (j=i; buf[j] && buf[j] != '.'; j++); + if (j-i-1u > 62u) return 0; + buf[i-1] = j-i; + } + buf[i+1] = type; + buf[i+3] = class; + + /* Make a reasonably unpredictable id */ + clock_gettime(CLOCK_REALTIME, &ts); + id = (uint16_t)ts.tv_nsec + (uint16_t)(ts.tv_nsec>>16); + buf[0] = id>>8; + buf[1] = id; + + return n; +} +int dns_make_query(const char *dom, char family) +{ + uint8_t q[280]; + size_t l = dns_mk_query_blob(0, dom, 1, family == FAMILY6 ? 28 : 1, q, sizeof(q)); + if (!l) + { + fprintf(stderr, "could not make DNS query\n"); + return 1; + } + if (fwrite(q,l,1,stdout)!=1) + { + fprintf(stderr, "could not write DNS query blob to stdout\n"); + return 10; + } + return 0; +} + +bool dns_parse_print(const uint8_t *a, size_t len) +{ + // check of minimum header length and response flag + uint16_t k, dlen, qcount = a[4]<<8 | a[5], acount = a[6]<<8 | a[7]; + char s_ip[40]; + + if (len<12 || !(a[2]&0x80)) return false; + a+=12; len-=12; + for(k=0;klen) return false; + // skip to next label + len -= *a+1; a += *a+1; + } + if (len<5) return false; + // skip zero length label, type, class + a+=5; len-=5; + } + for(k=0;k\n" - " --family=<4|6|46>\t; ipv4, ipv6, ipv4+ipv6\n" - " --verbose\t\t; print query progress to stderr\n" - " --stats=N\t\t; print resolve stats to stderr every N domains\n" - " --log-resolved=\t; log successfully resolved domains to a file\n" - " --log-failed=\t; log failed domains to a file\n" + " --family=<4|6|46>\t\t; ipv4, ipv6, ipv4+ipv6\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" ); exit(1); } @@ -335,20 +455,23 @@ int main(int argc, char **argv) { int r, v, option_index = 0; char fn1[256],fn2[256]; + char dom[256]; static const struct option long_options[] = { - {"help",no_argument,0,0}, // optidx=0 - {"threads",required_argument,0,0}, // optidx=1 - {"family",required_argument,0,0}, // optidx=2 - {"verbose",no_argument,0,0}, // optidx=3 - {"stats",required_argument,0,0}, // optidx=4 - {"log-resolved",required_argument,0,0}, // optidx=5 - {"log-failed",required_argument,0,0}, // optidx=6 + {"help",no_argument,0,0}, // optidx=0 + {"threads",required_argument,0,0}, // optidx=1 + {"family",required_argument,0,0}, // optidx=2 + {"verbose",no_argument,0,0}, // optidx=3 + {"stats",required_argument,0,0}, // optidx=4 + {"log-resolved",required_argument,0,0}, // optidx=5 + {"log-failed",required_argument,0,0}, // optidx=6 + {"dns-make-query",required_argument,0,0}, // optidx=7 + {"dns-parse-query",no_argument,0,0}, // optidx=8 {NULL,0,NULL,0} }; memset(&glob, 0, sizeof(glob)); - *fn1 = *fn2 = 0; + *fn1 = *fn2 = *dom = 0; glob.family = FAMILY4; glob.threads = 1; while ((v = getopt_long_only(argc, argv, "", long_options, &option_index)) != -1) @@ -394,6 +517,12 @@ int main(int argc, char **argv) strncpy(fn2,optarg,sizeof(fn2)); fn2[sizeof(fn2)-1] = 0; break; + case 7: /* dns-make-query */ + strncpy(dom,optarg,sizeof(dom)); + dom[sizeof(dom)-1] = 0; + break; + case 8: /* dns-parse-query */ + return dns_parse_query(); } } @@ -406,6 +535,8 @@ int main(int argc, char **argv) } #endif + if (*dom) return dns_make_query(dom, glob.family); + if (*fn1) { glob.F_log_resolved = fopen(fn1,"wt");