From 74d30b60767dfcbb35a7ecb39472c4ce521bfc25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anton=20Luka=20=C5=A0ijanec?= Date: Wed, 9 Feb 2022 17:38:46 +0100 Subject: =?UTF-8?q?nepreizku=C5=A1eno?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 68 insertions(+), 26 deletions(-) (limited to 'main.c') diff --git a/main.c b/main.c index a64b008..62cb30e 100644 --- a/main.c +++ b/main.c @@ -21,20 +21,23 @@ #include "domain2name.c" #include "host.c" #define HELP "find recursive DNS resolvers on IPv4 networks\n" \ -"%s [-a ip] [-b ip] [-e file [-f]] [h] [-k] [-p port] [-t μs] [-w μs] domain netwo1 [netwo2 ...]\n" \ +"%s [-a ip] [-b ip] [-e file [-f]] [h] [-k] [-m] [-n num] [-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" \ +" -m Scans increasingly larger networks. Input networks are treated as /32. Useful with -n.\n" \ +" -n Stops scanning after provided number of working servers is found and reported.\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" +"It would take a day to scan the entire address space (0.0.0.0/0) with the default timings.\n" \ +"If network has host bits set, scanning starts at that address. 10.0.0.100/24 scans 156 hosts.\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 @@ -350,6 +353,9 @@ int main (int argc, char ** argv) { int i = 0; /* 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 targetnum = 0; + int workingnum = 0; + int increasinglylarger = 0; int t = 1000; int w = 1000000; int e = 0; /* whether to exclude sent packets in PCAP - they're all the same */ @@ -357,7 +363,7 @@ int main (int argc, char ** argv) { signal(SIGINT, handler); signal(SIGTERM, handler); while (1) { - switch (getopt(argc, argv, ":a:b:e:fhkp:t:w:")) { + switch (getopt(argc, argv, ":a:b:e:fhkmn:p:t:w:")) { case 'a': inet_aton(optarg, &a); break; @@ -395,6 +401,12 @@ int main (int argc, char ** argv) { case 'k': k++; break; + case 'm': + increasinglylarger++; + break; + case 'n': + targetnum = atoi(optarg); + break; case 'p': b.sin_port = htons(atoi(optarg)); break; @@ -417,22 +429,29 @@ int main (int argc, char ** argv) { r = 4; goto r; } + if (increasinglylarger && l != 1) { + fprintf(stderr, "-m option is set, max one network. :: " HELP, argv[0]); + r = 5; + goto r; + } n = alloca(l*sizeof *n); for (int i = e; i < argc; i++) { int w = i-e; n[w] = str2net(argv[i]); + if (increasinglylarger) + n[w].mask.s_addr = INADDR_BROADCAST; } goto o; case '?': fprintf(stderr, "unknown option :: " HELP, argv[0]); - r = 5; + r = 6; goto r; case ':': fprintf(stderr, "missing option argument :: " HELP, argv[0]); - r = 6; + r = 7; goto r; default: - r = 7; + r = 8; goto r; } } @@ -442,31 +461,32 @@ o: fprintf(stderr, "resolving %s ... ", d); if ((e = resolve(d, &a.s_addr))) { fprintf(stderr, "failed: %s\n", gai_strerror(e)); - r = 8; + r = 9; 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 = 9; + r = 10; goto r; } int ž = 1; if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &ž, sizeof(ž)) == -1) { perror("setsockopt(s, SOL_SOCKET, SO_BROADCAST, &ž, sizeof(ž))"); - r = 10; + r = 11; 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 = 11; + r = 12; goto r; } struct timespec lp = { /* last packet */ .tv_sec = 0 }; int notfirst = 0; + j = localnumber(n[0]); while (!finish) { if (notfirst) { if (k) { @@ -476,19 +496,35 @@ o: j++; } else notfirst++; - if ((h = host(n[i], j)).mask.s_addr != INADDR_BROADCAST) { + if ((h = host(n[i], j)).mask.s_addr != INADDR_BROADCAST + || (increasinglylarger && scanuntilhost != -1 && j >= scanuntilhost)) { k: - if (++i >= l) { + if (increasinglylarger ? (n[0].mask.s_addr == INADDR_ANY) : (++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 = 12; + r = 13; goto r; } goto i; + } else { + if (increasinglylarger) + for (int ž = 0; ž < 31; ž++) + if (n[i].mask.s_addr & 1 << ž) { + n[i].mask.s_addr &= ~(1 << ž); + if (n[i].addr.s_addr & 1 << ž) { + n[i].addr.s_addr &= 1 << ž; /* but here we scan */ + scanuntilhost = localnumber(n[i]); /* UNTIL host */ + n[i].addr.s_addr &= n[i].mask.s_addr; /* from 0 */ + } else { + n[i].addr.s_addr |= (1 << (ž+1))-1; /* nisem prepr */ + scanuntilhost = -1; /* scan FROM localnum till end */ + } + break; + } + j = localnumber(n[i]); + h = host(n[i], j); } - else - h = host(n[i], (j = 0)); } 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 */ @@ -506,11 +542,11 @@ k: int v = domain2name_len(d, strlen(d)); #define L (sizeof h + v + 2*2) if (v < 0) { - r = 13; + r = 14; goto r; } if (L > 65535) { /* pebkac, there'll be no error message here */ - r = 14; + r = 15; goto r; } char u[65535]; /* max udp packet, alloca in a loop would be bad (not scope based) */ @@ -524,19 +560,19 @@ k: int ž; if (!e && o != -1 && (ž = logudp(o, b, m, u, L)) < -1) { fprintf(stderr, "logudp(o, b, m, u, L) == %d\n", ž); - r = 15; + r = 16; 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 = 16; + r = 17; goto r; } struct timespec z; i: if (clock_gettime(CLOCK_MONOTONIC, &z) == -1) { perror("clock_gettime(CLOCK_MONOTONIC, &z)"); - r = 17; + r = 18; goto r; } if ((z.tv_sec*1000000 + z.tv_nsec/1000) - (lp.tv_sec*1000000 + lp.tv_nsec/1000) > w @@ -552,7 +588,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 = 18; + r = 19; goto r; } if (!p) { @@ -562,7 +598,7 @@ i: continue; } if (q.revents & POLLERR || q.revents & POLLHUP || q.revents & POLLNVAL) { - r = 19; + r = 20; goto r; } struct sockaddr_in f; @@ -573,7 +609,7 @@ i: == -1) { if (errno != EWOULDBLOCK) { perror("recvfrom(s, u, 65535, MSG_DONTWAIT, (struct soc..."); - r = 20; + r = 21; goto r; } break; @@ -582,18 +618,24 @@ 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", ž); - r = 21; + r = 22; goto r; } fprintf(stderr, "RESPONSE\t%s", inet_ntoa(f.sin_addr)); ž = 0; struct in_addr i = parse_a(u, 65535, d, strlen(d), ž++); while (parse_a(u, 65535, d, strlen(d), ž++).s_addr); - if (i.s_addr == a.s_addr) /* if multithread, change printf to write. */ + if (i.s_addr == a.s_addr) { /* if multithread, change printf to write. */ printf("\tWORKING"); + if (--ž == 1) + if (++workingnum >= targetnum) { + fprintf(stderr, "discovered %d working servers.\n", workingnum); + goto r; /* r should be 0 here */ + } + } if (i.s_addr && i.s_addr != a.s_addr) printf("\tLYINGWITH\t%s", inet_ntoa(i)); - if (--ž > 1) + if (ž > 1) printf("\tMORETHANONE\t%d", ž); if (!i.s_addr) printf("\tNOA"); -- cgit v1.2.3