summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnton Luka Šijanec <anton@sijanec.eu>2022-02-09 17:38:46 +0100
committerAnton Luka Šijanec <anton@sijanec.eu>2022-02-09 17:38:46 +0100
commit74d30b60767dfcbb35a7ecb39472c4ce521bfc25 (patch)
tree6f4888e250e3b0ce8dc301433494ff44406a7424
parentsicer testirano, ampak sem utrujen, grem spat (diff)
downloaddnsfind-74d30b60767dfcbb35a7ecb39472c4ce521bfc25.tar
dnsfind-74d30b60767dfcbb35a7ecb39472c4ce521bfc25.tar.gz
dnsfind-74d30b60767dfcbb35a7ecb39472c4ce521bfc25.tar.bz2
dnsfind-74d30b60767dfcbb35a7ecb39472c4ce521bfc25.tar.lz
dnsfind-74d30b60767dfcbb35a7ecb39472c4ce521bfc25.tar.xz
dnsfind-74d30b60767dfcbb35a7ecb39472c4ce521bfc25.tar.zst
dnsfind-74d30b60767dfcbb35a7ecb39472c4ce521bfc25.zip
-rw-r--r--README3
-rw-r--r--host.c7
-rw-r--r--main.c94
3 files changed, 78 insertions, 26 deletions
diff --git a/README b/README
index dd75cb3..08df66e 100644
--- a/README
+++ b/README
@@ -26,6 +26,8 @@ stikala za razne opcije je treba navesti pred domeno in omrežji in so sledeča:
-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)
+ -m Podan je en naslov računalnika namesto omrežij, išče strežnike okoli njega /32, /31, /30, ...
+ -n Ko je najdenih toliko delujočih strežnikov, kot je podana številka kot argument, prenehajmo
-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 mikrosek. po prejemu zadnjega paketa po koncu pošiljanja (privzeto 1000000)
@@ -36,6 +38,7 @@ domeni sledijo omrežja, ki so podana kot naslov omrežja, poševnica in omrežn
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.
+ skeniranje omrežja se začne na podanem naslovu in ne na 0. računalniku (10.0.0.100/24 skenira 156 naslovov).
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.
diff --git a/host.c b/host.c
index 89a8524..c4e4284 100644
--- a/host.c
+++ b/host.c
@@ -103,3 +103,10 @@ unsigned long long int ri (unsigned long long int v, int s) { /* 000 100 010 110
v &= ~(1 << i--);
}
}
+unsigned long long int localnumber (struct in_net n) {
+ unsigned long long int r = 0;
+ for (int i = 31; i >= 0; i--)
+ if (n.mask.s_addr & 1 << i && n.addr.s_addr & 1 << i)
+ r |= 1 << i;
+ return r;
+}
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");