From 1a22d36e7a08e9ed06ff1e8f825159e3658fe8cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anton=20Luka=20=C5=A0ijanec?= Date: Wed, 2 Feb 2022 22:35:13 +0100 Subject: sicer testirano, ampak sem utrujen, grem spat --- .gitignore | 2 + Makefile | 2 +- README | 32 ++++++------- debian/changelog | 8 ++++ host.c | 17 +++++-- host_test.c | 6 ++- main.c | 133 ++++++++++++++++++++++++++++++++----------------------- 7 files changed, 124 insertions(+), 76 deletions(-) diff --git a/.gitignore b/.gitignore index e473d8b..f641316 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ a.out dnsfind +.gdb_history +out.pcap diff --git a/Makefile b/Makefile index 13eba26..f58b98f 100644 --- a/Makefile +++ b/Makefile @@ -27,7 +27,7 @@ clean: rm dnsfind -f prepare: - apt install build-essential-y + apt install build-essential -y # developing is to be done on i386. for example the default suppression file is hardcoded for i386 here: # developing is to be done on bullseye. diff --git a/README b/README index 2c56d8a..dd75cb3 100644 --- a/README +++ b/README @@ -19,29 +19,31 @@ ob vsakem prejetem paketu se izpiše vrstica na standarni izhod v slednji obliki prvima dvema zapisoma (WORKING in LYINGWITH) lahko sledi še en tabulator in MORETHANONE presledek številka, ki pove, da je odgovor vseboval več kot en A zapis in pove koliko jih je. -stikala za razne opcije je treba navesti pred omrežji in so sledeča: - -a Nastavi IP naslov A RR domene, podane v -d, ki naj se uporabi namesto klica getaddrinfo(3) +stikala za razne opcije je treba navesti pred domeno in omrežji in so sledeča: + -a IP naslov (A RR) navedene domene za pošiljanje, ki naj se uporabi namesto getaddrinfo(3) -b Uporabi mrežno kartico, katere IP naslov je podan, za pošiljanje in prejemanje paketov - -d Nastavi domeno z enim A zapisom, ki bo poslana kot vprašanje (privzeto: dnsfind.sijanec.eu) - -e Ne vključi poslanih paketov, ki so itak vedno isti, v PCAP datoteko, nastavljeno z -o - -h Pokaže besedilo pomoči - -o Sproti naj se v navedeno datoteko piše vsak poslan/prejet (glej -e) paket v PCAP obliki + -e Navedi ime datoteke, v katero naj piše vsak poslan/prejet (glej -f) paket v PCAP obliki + -f Ne vključi poslanih paketov, ki so itak vedno isti, v PCAP datoteko, nastavljeno z -e + -h Pokaže vgrajeno besedilo pomoči + -k Večaj IP naslov v "obratnem" vrstnem redu (b000, b100, b010, b110, b001, b101, b011, b111) -p Nastavi številko izvornih UDP vrat. Če ni navedena, jedro izbere eno prosto. -t Zamik pred pošiljanjem naslednjega paketa v mikrosekundah (privzeto in minimalno 1000) - -w Končaj toliko mikrosekund po prejemu zadnjega paketa po koncu pošiljanja (privzeto 1000000) -stikalom sledijo omrežja, ki so podana kot naslov omrežja, poševnica in omrežna maska. + -w Končaj toliko mikrosek. po prejemu zadnjega paketa po koncu pošiljanja (privzeto 1000000) +morebitnim stikalom sledi domena z *ENIM* DNS A zapisom, ki bo poslana kot vprašanje v DNS zahtevah. +domeni sledijo omrežja, ki so podana kot naslov omrežja, poševnica in omrežna maska. omrežja so ločena s presledki, z drugimi besedami mora biti vsako svoj argument. naslov omrežja in omrežja maska sta lahko tudi domeni, ki sta na začetku prevedeni v IPv4. omrežne maske so lahko tudi število začetnih nastavljenih bitov (24 za 255.255.255.0). omrežne maske, ki niso CIDR, so dovoljene, recimo 255.0.255.255. na primer za skeniranje celotnega Interneta se lahko uporabi kakršen koli naslov in maska 0. -opozorilo: pred skeniranjem velikih omrežij se posvetujte s ponudnikom omrežne povezljivosti in -vsekakor zamenjajte domeno iz dnsfind.sijanec.eu na nekaj svojega s stikalom -d. +teoretično bi trajalo en dan za skeniranje celotnega naslovnega prostora IPv4 (2^32 računalnikov), a je ta številka lahko veliko večja, recimo tudi zato, ker jedro skoraj vedno malo zamudi zamik med pošiljanjem dveh paketov, ki je uveljavljen s sistemskim klicem poll(2). prav tako se čas porablja tudi ob pisanju na standardni izhod, standardno napako, vtičnice in PCAP datoteko. -teoretično bi trajalo en dan za skeniranje celotnega naslovnega prostora IPv4 (2^32 računalnikov), a -je ta številka lahko veliko večja, recimo tudi zato, ker jedro skoraj vedno malo zamudi zamik med -pošiljanjem dveh paketov, ki je uveljavljen s sistemskim klicem poll(2). prav tako se -čas porablja tudi ob pisanju na standardni izhod, standardno napako, vtičnice in PCAP datoteko. +avtomatska gradnja izvršilnih datotek in programskih paketov za štiri arhitekture: + gospodar sužnjev: https://jenkins.sijanec.eu/job/dnsfind + sužnji: http://amd64.sijanec.eu/prog/dnsfind + http://arm64.sijanec.eu/prog/dnsfind + http://armel.sijanec.eu/prog/dnsfind + i386 pa gradi moj osebni prenosni računalnik, ki ni vedno povezan v Internet. - -- Anton Luka Šijanec Tue, 18 Jan 2022 14:30:00 +0200 + -- Anton Luka Šijanec Tue, 19 Jan 2022 14:30:00 +0200 diff --git a/debian/changelog b/debian/changelog index aae5c73..b032805 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +dnsfind (0.0.2-1) stable; urgency=low + + * removed default domain. domain must be now provided before networks + without option -d, which was also removed. + * added option -k for bit endianness reverse incrementing host address + + -- Anton Luka Šijanec Wed, 02 Feb 2022 18:00:00 +0100 + dnsfind (0.0.1-1) stable; urgency=low * removed test.c. debian building ran make test, make has automatic rules diff --git a/host.c b/host.c index 2087761..89a8524 100644 --- a/host.c +++ b/host.c @@ -10,8 +10,7 @@ struct in_net { struct in_addr addr; struct in_addr mask; }; -/* not needed begin */ -#define POPCNT(y) int popcnt##x (uint##y##_t x) { \ +#define POPCNT(y) int popcnt##y (uint##y##_t x) { \ int c = 0; \ for (int i = 0; i < y; i++) \ if (1 << i & x) \ @@ -19,8 +18,6 @@ struct in_net { return c; \ } POPCNT(32) -unsigned int power2[] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608, 16777216, 33554432, 67108864, 134217728, 268435456, 536870912, 1073741824, 2147483648 }; /* ah yes, libmath */ -/* not needed end */ struct in_net host (struct in_net n, unsigned long long int h /* number of host in the network */) { n.addr.s_addr = ntohl(n.addr.s_addr & n.mask.s_addr); n.mask.s_addr = ntohl(n.mask.s_addr); @@ -94,3 +91,15 @@ r: *--m = o; return r; } +unsigned long long int ri (unsigned long long int v, int s) { /* 000 100 010 110 001 101 011 111 */ + int i = s-1; + if (!(v & 1 << (s-1))) + return v | 1 << (s-1); + while (1) { + if (!(v & 1 << i)) + return v | 1 << i; + if (!i) /* rollover */ + return 0; + v &= ~(1 << i--); + } +} diff --git a/host_test.c b/host_test.c index b0d95c5..b30ca22 100644 --- a/host_test.c +++ b/host_test.c @@ -1,7 +1,11 @@ #include "host.c" int main (int argc, char ** argv) { if (argc != 3) { - fprintf(stderr, "%s network hostnumber\n", argv[0]); + uint32_t v = 0; + unsigned long long int i = 0; + while ((v = ri(v, 4))) + fprintf(stderr, "(debug) %llu\t%u\n", i++, v); + fprintf(stderr, "%s network hostnumber\t\t(debug: %llu)\n", argv[0], i); return 1; } struct in_net h = host(str2net(argv[1]), strtoll(argv[2], NULL, 10)); diff --git a/main.c b/main.c index aa37c89..a64b008 100644 --- a/main.c +++ b/main.c @@ -21,22 +21,20 @@ #include "domain2name.c" #include "host.c" #define HELP "find recursive DNS resolvers on IPv4 networks\n" \ - "%s [-a ip] [-b ip] [-d domain] [-eh] [-o file] [-p port] [-t μs] [-w μs] net1 [net2 ...]\n" \ - " -a Specify the IPv4 of the -d domain to be used instead of getaddrinfo(3).\n" \ - " -b Bind on a specific interface, defined by IPv4. Default is any interface.\n" \ - " -d Specify the domain name to be used in queries that has a single A record.\n" \ - " -e Exclude sent packets from -o PCAP output (they're all the same).\n" \ - " -h Show this help and exit.\n" \ - " -o Output PCAP to filename. Any existing file is truncated. No IP/UDP checksums.\n" \ - " -p Set the source port number to use instead of a dynamically asigned one.\n" \ - " -t Number of microseconds to wait between sent packets. (default 1000 - 64 KB/s)\n" \ - " -w Finish after μs after recv'd last packet when done sending. (default 1000000)\n" \ - "Network addresses are optionally followed by slash and netmask, otherwise networks are\n" \ - "understood as single host addresses. Both network names and netmasks can be domains to\n" \ - "be looked up or IP dot-notation addresses. Mask can also be a bit prefix (/32 default).\n" \ - "When scanning the Internet please make sure that you specify your own domain instead\n" \ - "of the default one (dnsfind.sijanec.eu).\n" \ - "It would take a day to scan the entire address space with the default timings.\n" +"%s [-a ip] [-b ip] [-e file [-f]] [h] [-k] [-p port] [-t μs] [-w μs] domain netwo1 [netwo2 ...]\n" \ +" -a Specify the A RR IPv4 address of the domain to be used instead of getaddrinfo(3).\n" \ +" -b Bind on a specific interface, defined by IPv4. Default is to use any interface.\n" \ +" -e Output PCAP to filename. Any existing file is truncated. No IP/UDP checksums. See -f.\n" \ +" -f Exclude sent packets from -e PCAP output They're all the same with different dst IPs.\n" \ +" -h Show this help and exit.\n" \ +" -k Increment IP addresses in reverse bit endianness (000 100 010 110 001 101 011 111).\n" \ +" -p Set the source port number to use instead of a dynamically asigned one.\n" \ +" -t Number of microseconds to wait between sent packets. (default & min. 1000 - 64 KB/s)\n" \ +" -w Finish after μs after last received packet when done with sending. (default 1000000)\n" \ +"Network addresses are optionally followed by slash and netmask, otherwise networks are\n" \ +"understood as single host addresses. Both network names and netmasks can be domains to be\n" \ +"looked up or IP dot-notation addresses. Mask can also be a bit prefix (default /32).\n" \ +"It would take a day to scan the entire address space (0.0.0.0/0) with the default timings.\n" /* DNS PACKET: HEADER QUESTION ANSWER AUTHORITY ADDITIONAL datatracker.ietf.org/doc/html/rfc1035 DEFINITIONS: (those appear somewhere in the packet, packet does not start with definitions!) LABLEN 8 bits: first two bits zero, then 6 bits length of label @@ -344,13 +342,14 @@ int main (int argc, char ** argv) { .s_addr = INADDR_ANY } }; - char * d = "dnsfind.sijanec.eu"; + char * d = NULL; int s = -1; /* socket */ int o = -1; /* output file */ struct in_net * n; /* networks */ int l; /* count of networks */ int i = 0; /* network index */ - int j = -1; /* host in network index */ + long long int j = 0; /* host in network index */ + int k = 0; /* little bitendian IP address inc: 10.0.0.0, 10.128.0.0, 10.64.0.0, 10.192.0.0 */ int t = 1000; int w = 1000000; int e = 0; /* whether to exclude sent packets in PCAP - they're all the same */ @@ -358,24 +357,14 @@ int main (int argc, char ** argv) { signal(SIGINT, handler); signal(SIGTERM, handler); while (1) { - switch (getopt(argc, argv, ":a:b:d:eho:p:t:w:")) { + switch (getopt(argc, argv, ":a:b:e:fhkp:t:w:")) { case 'a': inet_aton(optarg, &a); break; case 'b': inet_aton(optarg, &b.sin_addr); break; - case 'd': - d = optarg; - break; case 'e': - e++; - break; - case 'h': - printf(HELP, argv[0]); - r = 0; - goto r; - case 'o': if ((o = open(optarg, O_CREAT | O_TRUNC | O_WRONLY, 00664)) == -1) { perror("open(optarg, O_CREAT | O_TRUNC | O_WRONLY)"); r = 1; @@ -396,6 +385,16 @@ int main (int argc, char ** argv) { goto r; } break; + case 'f': + e++; + break; + case 'h': + printf(HELP, argv[0]); + r = 0; + goto r; + case 'k': + k++; + break; case 'p': b.sin_port = htons(atoi(optarg)); break; @@ -406,27 +405,34 @@ int main (int argc, char ** argv) { w = atoi(optarg); break; case -1: - if (!(l = argc-optind)) { - fprintf(stderr, "specify targets to scan :: " HELP, argv[0]); + if (!(argc-optind)) { + fprintf(stderr, "specify domain name :: " HELP, argv[0]); r = 3; goto r; } + d = argv[optind]; + int e = optind+1; + if (!(l = argc-e)) { + fprintf(stderr, "specify targets to scan :: " HELP, argv[0]); + r = 4; + goto r; + } n = alloca(l*sizeof *n); - for (int i = optind; i < argc; i++) { - int w = i-optind; + for (int i = e; i < argc; i++) { + int w = i-e; n[w] = str2net(argv[i]); } goto o; case '?': fprintf(stderr, "unknown option :: " HELP, argv[0]); - r = 4; + r = 5; goto r; case ':': fprintf(stderr, "missing option argument :: " HELP, argv[0]); - r = 5; + r = 6; goto r; default: - r = 6; + r = 7; goto r; } } @@ -436,31 +442,47 @@ o: fprintf(stderr, "resolving %s ... ", d); if ((e = resolve(d, &a.s_addr))) { fprintf(stderr, "failed: %s\n", gai_strerror(e)); - r = 7; + r = 8; goto r; } fprintf(stderr, " %s\n", inet_ntoa(a)); } if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) { perror("socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)"); - r = 8; + r = 9; goto r; } + int ž = 1; + if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &ž, sizeof(ž)) == -1) { + perror("setsockopt(s, SOL_SOCKET, SO_BROADCAST, &ž, sizeof(ž))"); + r = 10; + goto r; + } /* setting this so that sending packets to a broadcast address does not fail with noperm */ if (bind(s, (struct sockaddr *) &b, sizeof(struct sockaddr))) { perror("bind(s, (struct sokaddr *) &b, sizeof(struct sockaddr))"); - r = 9; + r = 11; goto r; } struct timespec lp = { /* last packet */ .tv_sec = 0 }; + int notfirst = 0; while (!finish) { - if ((h = host(n[i], ++j)).mask.s_addr != INADDR_BROADCAST) { + if (notfirst) { + if (k) { + if (!(j = ri(j, 32-popcnt32(n[i].mask.s_addr)))) + goto k; + } else + j++; + } else + notfirst++; + if ((h = host(n[i], j)).mask.s_addr != INADDR_BROADCAST) { +k: if (++i >= l) { fprintf(stderr, "finished sending, waiting for last replies\n"); if (clock_gettime(CLOCK_MONOTONIC, &lp) == -1) { perror("clock_gettime(CLOCK_MONOTONIC, &z)"); - r = 10; + r = 12; goto r; } goto i; @@ -468,10 +490,10 @@ o: else h = host(n[i], (j = 0)); } - struct sockaddr_in m = { /* see, I don't know much about scopes in C and I'm */ + struct sockaddr_in m = { /* I don't know much about scopes in C and I'm */ .sin_family = AF_INET, /* intentionally excercising them for the cost of */ .sin_port = htons(53), /* code unreadability. in this scope I defined h */ - .sin_addr = h.addr /* as struct header, in parent scope it was in_net, */ + .sin_addr = h.addr /* as struct header, in scope above it was in_net, */ }; /* and I used h as in_net in this scope as well, */ struct header h = { /* but h as header is declared after that use (; */ .xid = 0x6969, /* oh no, cache poisoning, whatever'll I do */ @@ -484,11 +506,11 @@ o: int v = domain2name_len(d, strlen(d)); #define L (sizeof h + v + 2*2) if (v < 0) { - r = 11; + r = 13; goto r; } if (L > 65535) { /* pebkac, there'll be no error message here */ - r = 12; + r = 14; goto r; } char u[65535]; /* max udp packet, alloca in a loop would be bad (not scope based) */ @@ -502,24 +524,24 @@ o: int ž; if (!e && o != -1 && (ž = logudp(o, b, m, u, L)) < -1) { fprintf(stderr, "logudp(o, b, m, u, L) == %d\n", ž); - r = 13; + r = 15; goto r; } if (sendto(s, u, L, 0, (struct sockaddr *) &m, sizeof(struct sockaddr)) == -1) { - perror("sendto(s, u, L, 0, (struct sockaddr *) &m, sizeof(struct sockaddr))"); - r = 14; + perror("sendto(s,u, L, 0, (struct sockaddr *) &m, sizeof(struct sockaddr))"); + r = 16; goto r; } struct timespec z; i: if (clock_gettime(CLOCK_MONOTONIC, &z) == -1) { perror("clock_gettime(CLOCK_MONOTONIC, &z)"); - r = 15; + r = 17; goto r; } if ((z.tv_sec*1000000 + z.tv_nsec/1000) - (lp.tv_sec*1000000 + lp.tv_nsec/1000) > w && lp.tv_sec) { - fprintf(stderr, "no more packets were received for -w microseconds. done.\n"); + fprintf(stderr, "no more packets were received for -w μs. done.\n"); r = 0; goto r; } @@ -530,7 +552,7 @@ i: int p; if ((p = poll(&q, 1, t/1000 == 0 ? 1 : t/1000)) == -1) { perror("poll(&q, 1, t/1000 == 0 ? 1 : t/1000)"); - r = 16; + r = 18; goto r; } if (!p) { @@ -540,7 +562,7 @@ i: continue; } if (q.revents & POLLERR || q.revents & POLLHUP || q.revents & POLLNVAL) { - r = 17; + r = 19; goto r; } struct sockaddr_in f; @@ -550,8 +572,8 @@ i: if ((š = recvfrom(s, u, 65535, MSG_DONTWAIT, (struct sockaddr *) &f, &č)) == -1) { if (errno != EWOULDBLOCK) { - perror("recvfrom(s, u, 65535, MSG_DONTWAIT, (struct sock..."); - r = 18; + perror("recvfrom(s, u, 65535, MSG_DONTWAIT, (struct soc..."); + r = 20; goto r; } break; @@ -560,7 +582,8 @@ i: lp = z; /* this loop ends nearly in an instant */ if (o != -1 && (ž = logudp(o, f, b, u, š)) < -1) { fprintf(stderr, "logudp(o, f, b, u, š) == %d\n", ž); - return 3; + r = 21; + goto r; } fprintf(stderr, "RESPONSE\t%s", inet_ntoa(f.sin_addr)); ž = 0; -- cgit v1.2.3