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