From f475a1d18d746ae917cf29e90677e0fd8c1a7eae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anton=20Luka=20=C5=A0ijanec?= Date: Wed, 9 Feb 2022 21:54:09 +0100 Subject: just commiting this monstrosity in case I ever need it before rewriting --- Makefile | 2 +- README | 2 +- host.c | 2 +- main.c | 122 +++++++++++++++++++++++++++++++++++---------------------------- 4 files changed, 70 insertions(+), 58 deletions(-) diff --git a/Makefile b/Makefile index f58b98f..2e36074 100644 --- a/Makefile +++ b/Makefile @@ -29,7 +29,7 @@ clean: prepare: apt install build-essential -y -# developing is to be done on i386. for example the default suppression file is hardcoded for i386 here: +# developing is to be done on i386. # developing is to be done on bullseye. valgrind: diff --git a/README b/README index 08df66e..66e0094 100644 --- a/README +++ b/README @@ -26,7 +26,7 @@ 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, ... + -m Podan je en naslov računalnika namesto omrežij, išče strežnike okoli njega /32, /31, ... -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) diff --git a/host.c b/host.c index c4e4284..9fc2cad 100644 --- a/host.c +++ b/host.c @@ -106,7 +106,7 @@ unsigned long long int ri (unsigned long long int v, int s) { /* 000 100 010 110 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) + if (!(ntohl(n.mask.s_addr) & 1 << i) && ntohl(n.addr.s_addr) & 1 << i) r |= 1 << i; return r; } diff --git a/main.c b/main.c index 62cb30e..2546712 100644 --- a/main.c +++ b/main.c @@ -28,7 +28,7 @@ " -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" \ +" -m Scans increasingly larger networks. Input networks are treated as /31. Use 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" \ @@ -263,6 +263,7 @@ int logudp (int o /* fd */, struct sockaddr_in s, struct sockaddr_in d, char * u c = (char *) memcpy(c, &v, 2) + 2; c = (char *) memcpy(c, &n, 2) + 2; c = (char *) memcpy(c, u, l) + l; + c++; c--; /* to make scan-build happy that c is never read */ if (write(o, b, LOGUDP_L) == -1) { /* atomic and thread safe, as per posix */ perror("write(o, b, LOGUDP_L)"); return -3; @@ -270,7 +271,7 @@ int logudp (int o /* fd */, struct sockaddr_in s, struct sockaddr_in d, char * u return LOGUDP_L; } struct in_addr parse_a (const char * u, int s /* buffer size of u */, const char * d, int l, int n) { - struct in_addr r = { /* this uses heap and does not fix heap if realloc failed. */ + struct in_addr r = { .s_addr = 0 /* returns 0.0.0.0 in case of error or if no more results for n. */ }; int y = normalizedomain_len(d, l); @@ -283,16 +284,19 @@ struct in_addr parse_a (const char * u, int s /* buffer size of u */, const char int q = ntohs(h->qdcount); int a = ntohs(h->ancount+h->nscount+h->arcount); char * o = NULL; + char * fuckc = NULL; const char * c = u+sizeof(struct header); while (q--) { int č = name2domain_len(u, s, c); if (č < 0) goto r; - if (!(o = realloc(o, č))) + if (!(fuckc = realloc(o, č))) goto r; + o = fuckc; if (!(c = name2domain(o, u, s, c))) goto r; - struct question * ć = (struct question *) (c+1); + struct question * ć = (struct question *) (c+1); /* scan-build ACK: ć is not read */ + ć++; ć--; /* to make scan-build happy that ć is never read */ if ((c += sizeof(*ć)+1) >= u+512) goto r; } /* we skip over any questions */ @@ -300,8 +304,9 @@ struct in_addr parse_a (const char * u, int s /* buffer size of u */, const char int č = name2domain_len(u, s, c); if (č < 0) goto r; - if (!(o = realloc(o, č))) + if (!(fuckc = realloc(o, č))) goto r; + o = fuckc; if (!(c = name2domain(o, u, s, c))) goto r; struct rr * ć = (struct rr *) (c+1); @@ -334,7 +339,7 @@ void handler () { exit(1); } int main (int argc, char ** argv) { - int r = 2; + int r = 1; struct in_addr a = { .s_addr = 0 }; @@ -360,6 +365,7 @@ int main (int argc, char ** argv) { int w = 1000000; int e = 0; /* whether to exclude sent packets in PCAP - they're all the same */ struct in_net h; /* host to scan is .addr, h as struct in_net is returned from host() */ + int notfirst = 0; signal(SIGINT, handler); signal(SIGTERM, handler); while (1) { @@ -373,7 +379,7 @@ int main (int argc, char ** argv) { case 'e': if ((o = open(optarg, O_CREAT | O_TRUNC | O_WRONLY, 00664)) == -1) { perror("open(optarg, O_CREAT | O_TRUNC | O_WRONLY)"); - r = 1; + r = 2; goto r; } struct pcap_global g = { @@ -387,7 +393,7 @@ int main (int argc, char ** argv) { }; if (write(o, &g, sizeof g) == -1) { perror("write(o, &g, sizeof g)"); - r = 2; + r = 3; goto r; } break; @@ -419,19 +425,19 @@ int main (int argc, char ** argv) { case -1: if (!(argc-optind)) { fprintf(stderr, "specify domain name :: " HELP, argv[0]); - r = 3; + r = 4; goto r; } d = argv[optind]; int e = optind+1; if (!(l = argc-e)) { fprintf(stderr, "specify targets to scan :: " HELP, argv[0]); - r = 4; + r = 5; goto r; } if (increasinglylarger && l != 1) { fprintf(stderr, "-m option is set, max one network. :: " HELP, argv[0]); - r = 5; + r = 6; goto r; } n = alloca(l*sizeof *n); @@ -439,19 +445,19 @@ int main (int argc, char ** argv) { int w = i-e; n[w] = str2net(argv[i]); if (increasinglylarger) - n[w].mask.s_addr = INADDR_BROADCAST; + n[w].mask.s_addr = htonl(ntohl(INADDR_BROADCAST)&~1); } goto o; case '?': fprintf(stderr, "unknown option :: " HELP, argv[0]); - r = 6; + r = 7; goto r; case ':': fprintf(stderr, "missing option argument :: " HELP, argv[0]); - r = 7; + r = 8; goto r; default: - r = 8; + r = 9; goto r; } } @@ -461,32 +467,32 @@ o: fprintf(stderr, "resolving %s ... ", d); if ((e = resolve(d, &a.s_addr))) { fprintf(stderr, "failed: %s\n", gai_strerror(e)); - r = 9; + r = 10; 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 = 10; + r = 11; goto r; } int ž = 1; if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &ž, sizeof(ž)) == -1) { perror("setsockopt(s, SOL_SOCKET, SO_BROADCAST, &ž, sizeof(ž))"); - r = 11; + r = 12; 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 = 12; + r = 13; goto r; } struct timespec lp = { /* last packet */ .tv_sec = 0 }; - int notfirst = 0; - j = localnumber(n[0]); + fprintf(stderr, "starting at host number %lld\n", (j = localnumber(n[i]))); + long int scanuntilhost = -1; /* no limit */ while (!finish) { if (notfirst) { if (k) { @@ -496,32 +502,34 @@ o: j++; } else notfirst++; - if ((h = host(n[i], j)).mask.s_addr != INADDR_BROADCAST - || (increasinglylarger && scanuntilhost != -1 && j >= scanuntilhost)) { + if (getenv("DF_DEBUG")) + fprintf(stderr, "j = %lld, scanuntilhost = %ld\n", j, scanuntilhost); + if ((h = host(n[i], j)).mask.s_addr != INADDR_BROADCAST || + (increasinglylarger && scanuntilhost != -1 && j >= scanuntilhost)) { k: 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 = 13; + r = 14; 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; + for (int ž = 0; increasinglylarger && ž < 31; ž++) + if (ntohl(n[i].mask.s_addr) & 1 << ž) { + n[i].mask.s_addr &= htonl(~(1 << ž)); + if (ntohl(n[i].addr.s_addr) & 1 << (ž)) { + scanuntilhost = 1 << ž; + n[i].addr.s_addr &= n[i].mask.s_addr; /* 0 */ + } else { + n[i].addr.s_addr |= htonl((1 << (ž))-1); + scanuntilhost = -1; /* until end */ } + break; + } + fprintf(stderr, "increasing scanning net: %s", inet_ntoa(n[i].addr)); + fprintf(stderr, "/%s t: %ld\n", inet_ntoa(n[i].mask), scanuntilhost); j = localnumber(n[i]); h = host(n[i], j); } @@ -542,11 +550,11 @@ k: int v = domain2name_len(d, strlen(d)); #define L (sizeof h + v + 2*2) if (v < 0) { - r = 14; + r = 15; goto r; } if (L > 65535) { /* pebkac, there'll be no error message here */ - r = 15; + r = 16; goto r; } char u[65535]; /* max udp packet, alloca in a loop would be bad (not scope based) */ @@ -557,22 +565,23 @@ k: c += domain2name(c, d, strlen(d)); c = (char *) memcpy(c, &y, 2) + 2; c = (char *) memcpy(c, &k, 2) + 2; + c++; c--; /* to make scan-build happy that c is never read */ int ž; if (!e && o != -1 && (ž = logudp(o, b, m, u, L)) < -1) { fprintf(stderr, "logudp(o, b, m, u, L) == %d\n", ž); - r = 16; + r = 17; 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 = 17; + r = 18; goto r; } struct timespec z; i: if (clock_gettime(CLOCK_MONOTONIC, &z) == -1) { perror("clock_gettime(CLOCK_MONOTONIC, &z)"); - r = 18; + r = 19; goto r; } if ((z.tv_sec*1000000 + z.tv_nsec/1000) - (lp.tv_sec*1000000 + lp.tv_nsec/1000) > w @@ -588,7 +597,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 = 19; + r = 20; goto r; } if (!p) { @@ -598,7 +607,7 @@ i: continue; } if (q.revents & POLLERR || q.revents & POLLHUP || q.revents & POLLNVAL) { - r = 20; + r = 21; goto r; } struct sockaddr_in f; @@ -609,7 +618,7 @@ i: == -1) { if (errno != EWOULDBLOCK) { perror("recvfrom(s, u, 65535, MSG_DONTWAIT, (struct soc..."); - r = 21; + r = 22; goto r; } break; @@ -618,7 +627,7 @@ 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 = 22; + r = 23; goto r; } fprintf(stderr, "RESPONSE\t%s", inet_ntoa(f.sin_addr)); @@ -627,15 +636,18 @@ i: while (parse_a(u, 65535, d, strlen(d), ž++).s_addr); 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 (ž-1 == 1 && i.s_addr) + if (++workingnum >= targetnum && targetnum) { + printf("\n"); + fprintf(stderr, "discovered %d working server%s.\n", + workingnum, workingnum==1 ? "": "s"); + r = 0; /* r is 1 by default */ + goto r; } } 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"); @@ -646,16 +658,16 @@ i: goto i; } r: - if (!r && j != -1) { /* TODO: tell EXACT packets that were sent before termination. */ - char * x = alloca(l*31+strlen("SCANNED \n0")); /* currently, if scan was */ - strcpy(x, "SCANNED "); /* terminated, only networks before */ + if (!r && notfirst) { /* TODO: tell EXACT packets that were sent before termination. */ + char * x = alloca(l*31+strlen("SCANNED \n0")+strlen("WORKINGNUM aaaaaaaaaaaaaaaa")); + strcpy(x, "SCANNED "); /* if scan term, only networks be4 */ for (int m = 0; m < (finish ? i : l); m++) { /* network at which scan was */ strcat(x, inet_ntoa(n[m].addr)); /* terminated are reported to be */ strcat(x, "/"); /* scanned, not mentioning the */ strcat(x, inet_ntoa(n[m].mask)); /* part of the last not mentioned */ strcat(x, " "); /* network that was scanned. */ } /* this may lead to statistical */ - strcat(x, "\n"); /* issues because it would appear */ + sprintf(x+strlen(x), "\nWORKINGNUM %d\n", workingnum); /* issues cause it'd appear */ write(STDIN_FILENO, x, strlen(x)); /* as if we received packets from */ } /* hosts we haven't queried yet. */ if (s != -1) -- cgit v1.2.3