summaryrefslogtreecommitdiffstats
path: root/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'main.c')
-rw-r--r--main.c133
1 files changed, 78 insertions, 55 deletions
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;