diff options
Diffstat (limited to 'main.c')
-rw-r--r-- | main.c | 133 |
1 files changed, 78 insertions, 55 deletions
@@ -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; |