summaryrefslogblamecommitdiffstats
path: root/main.c
blob: a7b2ba46387c8547c21eff873319d483bede64ee (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
                                    









                                      
                                     


                                       
                                        
                                   


                                            
                        
                 
                                                                
                                                                                                                     





                                                                                                     
                                                                                          
                                                                                              





                                                                                                     

                                                                                                 
                                                                                                     

                                                                                            
                                                                                             



                                                                                                     
                        
                                                                                           

                                                                                             

















                                                                                                   
                                                                                          




                                                                                                    
  



                                                                                                     





                                                                                                   

                                       
                                                                                                   























                                                                                                     
                                                                                                   

                       
                                                                   

                                                                                                    

                              

                 

                     





                                                                
                                                                                                     
                          





                                                                

                                









                                                                                                   
                      
                    
                    


              
           

                                                                                                     
                                                                                                   
                                                                
                                                                                                 


                                                                 
                                                                
                                                                                           
                                                                
                          



              
                                                                                                    










              
  





                 
  













                                                                                                    
                                           

                                                                
                                                                



                                                                
                                                                
                          










                                                                             
                                                                                                     


                                                            
                          



                                        

                                                              

                       

                                         
                                              
                                     

                             
                                
                                                                                           

                                  
          
                                                

                                                                                 
                                

                                                        


                                                   
                                          
                                         
                                                                     
                                                                                     
                                                
                          
         

                        
                                                                                                     
                            







                                                                                                   


                                                            
                        
                            
                                                 



                                                  
                                              
                               
                          
                                                   
                               

                                                                                                      
                                                  
                               




                                                  
                                              
                               
                          





                                                                 

                               
                                 
                                     






                                                                                                          
                        

                                                     
                       
                                                                                                



                                                                                                   
               
                 
                          
                        

                                   
                  









                                            
                        

                                     

                                         
                                      

                                                                                                     

                           


                                           

                        

                                                                                                
                         

                                 
                   
                                                                    





                                                               
                                 
                                                                                                    
                                                                                             
                                              

                                               






                                                                
                                                      


                                                                         
                                              

                                               
                                      









                                                      
                                 
                                               



                                                         


                                                                 





                                                 
                                

                                                                                                 
                                              

                                               



                                                                                                     
                                              

                                               

                                                                                                            
                                              

                                               
                                                        

                                                                
                                                                



                                                                                    

                                       

                                                                                    
                                      


                                                                                             
                                      
                                       
                                
                                      
                                       

                 





                                                                         
                               





                                                                   
                       

                       


                                                                                   
                       

                                                                                                     

                                                                                  
                       

                       


                                                

                                                                                   
                         







                                                                                

                                                                                             
                                                                                          
  






















                                                                                             
                                                                                                

                                                                                     
                                               

                                               
                                       
                                

                                                      
                         
                 
                                                                                                 

                                                                                                    
                                                                                                     

                                                                                                   







                                                                                     
                              
                            
                               

                               
                                                                                
                               


                                                                                                    






                                                                
                                                                             
                       

                                                                             
                               

                               

                                                                                                     
                               
                               
                                                                                                   



                                                                     
                               

                               

                                                                                                   
                                                                                             









                                                                        
                               
                               
                 






                                                                                         
                               








                                                                                                   
                                                                                                     
                                               





                                                                                 
                                                                            
                                                                                      
                                       
                                       
                         
                                                                               

                                                                                 
                                                                             
                                                                                                 
                                                    






                                                                                                     

                                         
                                                             
                                                                        
                                     



                                                                



                               
         
  

                                                                                                     















                                                                      


                                           


                                           

                 
#include <sys/socket.h> /* udp(7) */
#include <netinet/in.h>
#include <netinet/udp.h>
#include <poll.h> /* poll(2) */
#include <sys/types.h> /* socket(2) */
#include <sys/socket.h>
#include <unistd.h> /* close(2) */
#include <stdio.h> /* perror(3) */
#include <sys/stat.h> /* open(2) */
#include <fcntl.h>
#include <errno.h> /* errno(3) */
#include <arpa/inet.h> /* htons(3) */
#include <netdb.h> /* getaddrinfo(3) */
#include <stdlib.h> /* atoi(3) */
#include <string.h> /* strchr(3) */
#include <time.h> /* clock_gettime(2) */
#include <signal.h> /* signal(2) */
/* #include <sys/prctl.h> */ /* prctl(2) */
/* #include <sys/wait.h> */ /* waitpid(2) */
#include <poll.h> /* poll(2) */
#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] [-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 Spiral-search around a single host given instead of networks. 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" \
"	-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" \
"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
	POINTER	16 bits: first two bits one, then 14 bits as offset from first byte of packet
	STRING	a single byte for defining length (0-256 - all eight bits) and then string of chars
	DOMAIN	 i.) one or more LABLEN followed by ASCII label (no dots) end with either LABLEN 0
		or a POINTER that points to some LABLEN somewhere else in the packet		-OR-:
		ii.) a POINTER that points to some LABLEN somewhere else in the packet
HEADER:		12 bytes
	XID	16 bits: random string to be matched in response to prevent cache poisoning
     /	QR	 1 bit : what type is this packet?	0 quest	1 response
    |	OPCODE   4 bits: type of query			0 query	1 iquer	2 sstat	3-15 reserved
1 byte	AA	 1 bit : is response authoritative?	0 no	1 yes
    |	TC	 1 bit : was response truncated?	0 no	1 yes
     \	RD       1 bit : does query desire recursion?	0 no	1 yes
     /	RA	 1 bit : does response server recurse?	0 no	1 yes
1 byte	Z	 3 bits: reserved for future		0 only option
     \	RCODE	 4 bits: error condition	0 ok	1 fmter	2 srvfa	3 nxdom	4 N/I	5 forbidden
    	QDCOUNT	16 bits: number of questions
	ANCOUNT 16 bits: number of answers
	NSCOUNT 16 bits: authority section (where to ask for actual response - NS RECORDS)
	ARCOUNT 16 bits: additional section (glue records)
QUESTION:
	QNAME	DOMAIN
	QTYPE	16 bits: 1 A 	2 NS	5 CNAME	6 SOA	10 NULL	12 PTR 13 HINFO	15 MX	16 TXT ...
	QCLASS	16 bits: 1 INTERNET	2 CSNET	(obsolete)	3 CHAOS	4 HESIOD	255 ANY ...
ANSWER:
	NAME	DOMAIN
	TYPE	same as QTYPE
	CLASS	same description as QCLASS, except class 255 ANY is not allowed here
	TTL	32 bits: unsigned intager of seconds. for this period the record is valid.
	RDLEN	16 bits: length of RDATA field - this is a number 0-65536, no two zero bits
	RDATA	A: 4 bytes IP address		NS: DOMAIN	CNAME: DOMAIN
		SOA: NAME-ns1 NAME-email 32b-serial 32b-refresh 32b-retry 32b-expire 32b-nxdomainttl
		NULL: any data up to RDLEN 	PTR: DOMAIN	HINFO: STRING-CPU, STRING-OS
		MX: 16 bit preference, NAME-like domain		TXT: one or more STRING
*/
/* PCAP file format: GLOBALHEADER PACKETHEADER PACKETDATA PACKETHEADER2 PACKETDATA2 ...
GLOBAL HEADER:	24 bytes
	MAGIC	32 bits: 0xA1B2C3D4 timestamp is s and micros	0xA1B23C4D timestamp is s and nanos
	MAJOR	16 bits: version	2 https://tools.ietf.org/id/draft-gharris-opsawg-pcap-00.html
	MINOR	16 bits: version	4 	/-----------------------------------------------\
	RESERV1	32 bits: unused and set to 0	| //en.wikipedia.org/wiki/Frame_check_sequence	|
	RESERV2 32 bits: unused and set to 0	\--------------------------------------------\	|
	SNAPLEN	32 bits: larger or equal to size of largest capture of a single packet		|
	FCS	 4 bits: if last bit is 1, first 3 tell nr of bytes of FCS appended to every packet
	LINKTYP	28 bits: pkt type //tcpdump.org/linktypes.html	101 IPv4/v6	1 ether
PACKET HEADER:	16 bytes
	SECONDS	32 bits: UNIX timestamp
	SUBSECS 32 bits: nanoseconds elapsed since the second, can also be microseconds - see MAGIC
	CAPTURE	32 bits: number of bytes captured from the packet following the header
	ORIGLEN	32 bits: number of bytes of the original packet size (can be more than CAPTURE)
*/
/* IPv4 PACKET: HEADER DATA				https://datatracker.ietf.org/doc/html/rfc791
HEADER:
 /--	VERSION	 4 bits:	4 IPv4	6 IPv6
| T	HEADLEN	 4 bits: >= 5.	Header size 32 bit words (header is padded), so it points to data.
|w	SRVTYPE	 8 bits:	3bPrecedence 1bLowDelay 1bHighThroughput 1bHighReliability 2bReserved
|e		Prec.: 0routine 1prio 2immediate 3flash 4flashoverride 5critic 110inetctrl 111netctrl
|n	LENGTH	16 bits: length including header and data. every host must accept at least 576.
|t	IDENTIF	16 bits: not so unique ID per src-dest persisted across fragmentations for reassembly
|y	FLAGS	 3 bits: bit 0 (1. bit): evil bit, bit 1: don't fragment, bit 2: more fragments
| B	FOFFSET	13 bits: where in complete datagram this fragment belongs in 64 bit words-first has 0
|y	TTL	 8 bits: every router decreases by one, when zero, packet is destroyed
|t	PROTO	 8 bits: datatracker.ietf.org/doc/html/rfc790#page-6	1 ICMP	6 TCP	17 UDP
|e	CHCKSUM	16 bits: 16 bit one's complement of the one's complement sum of 16b words in header
|s	SRCADDR	32 bits:
 \--	DSTADDR 32 bits:
	OPTIONS variable: depending on type, it may be single byte-type or byte-type, byte-len, data.
		Option type byte: 1b-copy to fragmented headers 2b-option class 5b-option number
		Option classes:  0 control	1 reserved	2 debugging	3 reserved
		Option byte zero denotes an end of options, NOOP is option number 1
	PADDING variable: zero bytes ensuring header is aligned into 32 bit words
*/
/* UDP PACKET: HEADER (8 bytes) DATA				https://www.ietf.org/rfc/rfc768.txt
	SRCPORT	16 bits
	DSTPORT	16 bits
	LENGTH	16 bits: size of packet including header in bytes+8
	CHCKSUM	16 bits: same algo as IP, data: pseudoheader (srcip dstip 0x0011 LENGTH) header data
*/
#define MICROSECOND 0xA1B2C3D4
#define NANOSECOND 0xA1B23C4D
#define PCAPMAJ 2
#define PCAPMIN 4
#define ETHERNET = 1,
#define IP 101
struct pcap_global {
	uint32_t subsecond		__attribute__((packed));
	uint16_t major			__attribute__((packed));
	uint16_t minor			__attribute__((packed));
	uint32_t reserved[2]		__attribute__((packed));
	uint32_t snaplen		__attribute__((packed));
	uint32_t linktype		__attribute__((packed)); /* FCS in included here for order */
} __attribute__((packed));
struct pcap_packet {
	uint32_t seconds		__attribute__((packed));
	uint32_t subseconds		__attribute__((packed));
	uint32_t capture_length		__attribute__((packed));
	uint32_t original_length	__attribute__((packed));
} __attribute__((packed));
#define LOW_DELAY (1 << 4)
#define HIGH_THROUGHPUT (1 << 3)
#define HIGH_RELIABILITY (1 << 2)
#define ROUTINE (0 << 5)
#define PRIORITY (1 << 5)
#define IMMEDIATE (1 << 6)
#define FLASH (PRIORITY | IMMEDIATE)
#define FLASH_OVERRIDE (1 << 7)
#define CRITICAL (FLASH_OVERRIDE | PRIORITY)
#define INETCTRL (FLASH_OVERRIDE | IMMEDIATE)
#define NETCTRL (FLASH_OVERRIDE | FLASH)
#define HEADLENOR (1 << 6) /* always bitwiseOR the headlen with this to apply the version number */
#define EVIL (1 << 15)
#define DF (1 << 14)
#define MF (1 << 13)
#define ICMP 1
#define TCP 6
#define UDP 17
struct ip {
	uint8_t headlen; /* length of header in 32 bit words (min 5, max 15 = 60B). see HEADLENOR. */
	uint8_t srvtype; /* OR here: LOW_DELAY, HIGH_THROUGHPUT, HIGH_RELIABILITY, ROUTINE, ... */
	uint16_t length			__attribute__((packed)); /* header + data in 8 bit words */
	uint16_t identifier		__attribute__((packed));
	uint16_t foffset /* 64b wrds */ __attribute__((packed)); /* or any flags: EVIL, DF, MF */
	uint8_t ttl;			/* ignored for uint8_t */
	uint8_t protocol;		/* ignored for uint8_t */
	uint16_t checksum;		/* ignoref for uint8_t */
	struct in_addr src		__attribute__((packed));
	struct in_addr dst		__attribute__((packed)); /* ----------- 20 bytes */
	char options[];			/* ignored for char[] */
} __attribute__((packed));
enum type {
	A = 1,
	Ns,
	Md,
	Cname = 5, /* we skip the quite obsolete Mf record, luckily Mf (more fragments) is also 4 */
	Soa,
	Mb,
	Mg,
	Mr,
	Null,
	Wks,
	Ptr,
	Hinfo,
	Minfo,
	Mx,
	Txt
};
enum class {
	In = 1,
	Cs,
	Ch,
	He,
	Any = 255
};
#define RESPONSE (1 << 15)								/* :FLAGS */
#define QUESTION (0 << 15)
#define QUERY (0 << 11)
#define IQUERY (1 << 11)
#define STATUS (1 << 12)
#define AA (1 << 10)
#define TC (1 << 9)
#define RD (1 << 8)
#define RA (1 << 7)
#define SUCCESS (0 << 0)
#define FORMAT_ERROR (1 << 0)
#define SERVFAIL (1 << 1)
#define NXDOMAIN (FORMAT_ERROR | SERVFAIL)
#define NI (1 << 2)
#define FORBIDDEN (NXDOMAIN | FORMAT_ERROR)
struct header {
	uint16_t xid			__attribute__((packed));
	uint16_t flags			__attribute__((packed));
	uint16_t qdcount		__attribute__((packed));
	uint16_t ancount		__attribute__((packed));
	uint16_t nscount		__attribute__((packed));
	uint16_t arcount		__attribute__((packed));
	char data[];			/* ignored for char[] */
} __attribute__((packed));
struct rr { /* name is omitted, first byte of struct is first byte of type */
	uint16_t type			__attribute__((packed));
	uint16_t class			__attribute__((packed));
	uint32_t ttl			__attribute__((packed));
	uint16_t len			__attribute__((packed));
	char data[];			/* ignored for char[] */
} __attribute__((packed));
struct question {
	uint16_t type			__attribute__((packed));
	uint16_t class			__attribute__((packed));
} __attribute__((packed));
int logudp (int o /* fd */, struct sockaddr_in s, struct sockaddr_in d, char * u, size_t l /* d */) {
	struct timespec t;
	if (clock_gettime(CLOCK_REALTIME, &t) == -1) {
		perror("clock_gettime(CLOCK_REALTIME, &t)");
		return -2;
	}
	struct pcap_packet p = {
		.seconds = t.tv_sec,
		.subseconds = t.tv_nsec,
		.capture_length = sizeof(struct ip) + l + 4*2,
		.original_length = sizeof(struct ip) + l + 4*2
	};
	struct ip i = {
		.headlen = 5 | HEADLENOR,
		.srvtype = ROUTINE,
		.length = htons(8+l+sizeof i),
		.identifier = 0x6969,
		.foffset = 0,
		.ttl = 69,
		.protocol = UDP,
		.checksum = 0, /* wireshark does not validate, at least not on debian 11 */
		.src = s.sin_addr,
		.dst = d.sin_addr
	};
#define LOGUDP_L (sizeof p + sizeof i + 4*2 + l)
	char * c, * b = alloca(LOGUDP_L); /* to do in one write (thread safe) */
	char * n = "\0"; /* as per udp rfc when no checksum was calculated (-: */
	uint16_t v = htons(l+8);
	c = (char *) memcpy(b, &p, sizeof p) + sizeof p;
	c = (char *) memcpy(c, &i, sizeof i) + sizeof i;
	c = (char *) memcpy(c, &s.sin_port, 2) + 2;
	c = (char *) memcpy(c, &d.sin_port, 2) + 2;
	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;
	}
	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 = {
		.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);
	if (y < 0)
		return r;
	char * ž = alloca(y);
	if (normalizedomain(ž, d, l) < 0)
		return r;
	const struct header * h = (const struct header *) u;
	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 (!(fuckc = realloc(o, č)))
			goto r;
		o = fuckc;
		if (!(c = name2domain(o, u, s, c)))
			goto r;
		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 */
	while (a--) {
		int č = name2domain_len(u, s, c);
		if (č < 0)
			goto r;
		if (!(fuckc = realloc(o, č)))
			goto r;
		o = fuckc;
		if (!(c = name2domain(o, u, s, c)))
			goto r;
		struct rr * ć = (struct rr *) (c+1);
		if (c+sizeof(*ć) >= u+512)
			goto r;
		if ((c += ntohs(ć->len)+sizeof(*ć)+1) >= u+512)
			goto r;
		if (y != č)
			continue;
		if (memcmp(o, ž, y))
			continue;
		if (ntohs(ć->type) != A)
			continue;
		if (ntohs(ć->class) != In)
			continue;
		if (ntohs(ć->len) != 4)			/* this is actually a malformed packet, */
			continue;			/* A resource record must be four bytes */
		if (n--)
			continue;
		r.s_addr = *(in_addr_t *) (ć->data);
		goto r;
	} /* we scroll over answers now and treat all three types the same, waiting for our A */
r:
	free(o);
	return r;
} /* returns nth IP of A record for domain d of length l in response packet u or 0.0.0.0 for err */
int finish = 0;
void handler () {
	if (++finish >= 3)
		exit(1);
}
int main (int argc, char ** argv) {
	int r = 1;
	struct in_addr a = {
		.s_addr = 0
	};
	struct sockaddr_in b = {
		.sin_family = AF_INET,
		.sin_port = 0,
		.sin_addr = {
			.s_addr = INADDR_ANY
		}
	};
	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 */
	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;
	unsigned int spiralsearch = 0;
	unsigned int spiralsearch_up = 0;
	unsigned int spiralsearch_down = 0;
	int t = 1000;
	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) {
		switch (getopt(argc, argv, ":a:b:e:fhkmn:p:t:w:")) {
			case 'a':
				inet_aton(optarg, &a);
				break;
			case 'b':
				inet_aton(optarg, &b.sin_addr);
				break;
			case 'e':
				if ((o = open(optarg, O_CREAT | O_TRUNC | O_WRONLY, 00664)) == -1) {
					perror("open(optarg, O_CREAT | O_TRUNC | O_WRONLY)");
					r = 2;
					goto r;
				}
				struct pcap_global g = {
					.subsecond = NANOSECOND,
					.major = PCAPMAJ,
					.minor = PCAPMIN,
					.reserved[0] = 0,
					.reserved[1] = 0,
					.snaplen = 65535,
					.linktype = IP
				};
				if (write(o, &g, sizeof g) == -1) {
					perror("write(o, &g, sizeof g)");
					r = 3;
					goto r;
				}
				break;
			case 'f':
				e++;
				break;
			case 'h':
				printf(HELP, argv[0]);
				r = 0;
				goto r;
			case 'k':
				k++;
				break;
			case 'm':
				spiralsearch++;
				break;
			case 'n':
				targetnum = atoi(optarg);
				break;
			case 'p':
				b.sin_port = htons(atoi(optarg));
				break;
			case 't':
				t = atoi(optarg);
				break;
			case 'w':
				w = atoi(optarg);
				break;
			case -1:
				if (!(argc-optind)) {
					fprintf(stderr, "specify domain name :: " HELP, argv[0]);
					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 = 5;
					goto r;
				}
				if (spiralsearch && l != 1) {
					fprintf(stderr, "-m option is set, max one host :: " HELP, argv[0]);
					r = 6;
					goto r;
				}
				n = alloca(l*sizeof *n);
				for (int i = e; i < argc; i++) {
					int w = i-e;
					n[w] = str2net(argv[i]);
					if (spiralsearch) {
						n[w].mask.s_addr = INADDR_BROADCAST;
						h = n[w];
					}
				}
				goto o;
			case '?':
				fprintf(stderr, "unknown option :: " HELP, argv[0]);
				r = 7;
				goto r;
			case ':':
				fprintf(stderr, "missing option argument :: " HELP, argv[0]);
				r = 8;
				goto r;
			default:
				r = 9;
				goto r;
		}
	}
o:
	if (!a.s_addr) {
		int e;
		fprintf(stderr, "resolving %s ... ", d);
		if ((e = resolve(d, &a.s_addr))) {
			fprintf(stderr, "failed: %s\n", gai_strerror(e));
			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 = 11;
		goto r;
	}
	int ž = 1;
	if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &ž, sizeof(ž)) == -1) {
		perror("setsockopt(s, SOL_SOCKET, SO_BROADCAST, &ž, sizeof(ž))");
		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 = 13;
		goto r;
	}
	struct timespec lp = { /* last packet */
		.tv_sec = 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) {
				if (!(j = ri(j, 32-popcnt32(n[i].mask.s_addr))))
					goto k;
			} else
				j++;
		} else
			notfirst++;
		if (getenv("DF_DEBUG"))
			fprintf(stderr, "j = %lld, scanuntilhost = %ld\n", j, scanuntilhost);
		if (spiralsearch || (h = host(n[i], j)).mask.s_addr != INADDR_BROADCAST) {
k:
			if (spiralsearch) {
				if (spiralsearch < 10) /* this indicates we haven't yet */
					spiralsearch = 10; /* scanned given ip itself */
				else {
					if (spiralsearch_down == UINT32_MAX
							&& spiralsearch_up == UINT32_MAX)
						goto finished_sending;
					if ((spiralsearch_up <= spiralsearch_down
							&& spiralsearch_up != UINT32_MAX)
							|| spiralsearch_down == UINT32_MAX) {
						h.addr.s_addr = htonl(ntohl(n[i].addr.s_addr)
								+ ++spiralsearch_up);
						if (h.addr.s_addr == INADDR_BROADCAST)
							spiralsearch_up = UINT32_MAX;
					} else {
						h.addr.s_addr = htonl(ntohl(n[i].addr.s_addr)
								- ++spiralsearch_down);
						if (!h.addr.s_addr)
							spiralsearch_down = UINT32_MAX;
					}
				}
			} else if (++i >= l) {
finished_sending:
				fprintf(stderr, "finished sending, waiting for last replies\n");
				if (clock_gettime(CLOCK_MONOTONIC, &lp) == -1) {
					perror("clock_gettime(CLOCK_MONOTONIC, &z)");
					r = 14;
					goto r;
				}
				goto i;
			} else {
				j = localnumber(n[i]);
				h = host(n[i], j);
			}
		}
		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 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 */
			.flags = htons(QUESTION | QUERY | RD),
			.qdcount = htons(1),
			.ancount = 0,
			.nscount = 0,
			.arcount = 0
		};
		int v = domain2name_len(d, strlen(d));
#define L (sizeof h + v + 2*2)
		if (v < 0) {
			r = 15;
			goto r;
		}
		if (L > 65535) { /* pebkac, there'll be no error message here */
			r = 16;
			goto r;
		}
		char u[65535]; /* max udp packet, alloca in a loop would be bad (not scope based) */
		char * c;
		uint16_t y = htons(A);
		uint16_t k = htons(In);
		c = (char *) memcpy(u, &h, sizeof h) + sizeof h;
		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 = 17;
			goto r;
		}
		if (sendto(s, u, L, 0, (struct sockaddr *) &m, sizeof(struct sockaddr_in)) == -1) {
			perror("sendto(s, u, L, 0, (struct sockaddr *) &m, sizeof(struct sockad...");
			r = 18;
			goto r;
		} /* https://stevecao.wordpress.com/2018/09/28/diagnosing-invalid-argument-error */
		struct timespec z;
i:
		if (clock_gettime(CLOCK_MONOTONIC, &z) == -1) {
			perror("clock_gettime(CLOCK_MONOTONIC, &z)");
			r = 19;
			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 μs. done.\n");
			r = 0;
			goto r;
		}
		struct pollfd q = {
			.fd = s,
			.events = POLLIN
		};
		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 = 20;
			goto r;
		}
		if (!p) {
			if (lp.tv_sec)
				goto i;
			else
				continue;
		}
		if (q.revents & POLLERR || q.revents & POLLHUP || q.revents & POLLNVAL) {
			r = 21;
			goto r;
		}
		struct sockaddr_in f;
		socklen_t č = sizeof f;
		while (1) {
			int š;
			if ((š = recvfrom(s, u, 65535, MSG_DONTWAIT, (struct sockaddr *) &f, &č))
				       == -1) {
				if (errno != EWOULDBLOCK) {
					perror("recvfrom(s, u, 65535, MSG_DONTWAIT, (struct soc...");
					r = 22;
					goto r;
				}
				break;
			}
			if (lp.tv_sec)
				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 = 23;
				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. */
				printf("\tWORKING");
				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)
				printf("\tMORETHANONE\t%d", ž);
			if (!i.s_addr)
				printf("\tNOA");
			printf("\n");

		}
		if (z.tv_sec)
			goto i;
	}
r:
	if (!r && notfirst) { /* TODO: tell EXACT packets that were sent before termination. */
		char * x = alloca(l*31+strlen("SCANNED  \n0")+strlen("WORKINGNUM aaaaaaaaaaaaaaaa"));
		if (spiralsearch) {
			strcpy(x, "SPIRALSEARCH ");
			strcat(x, inet_ntoa(n[0].addr));
			strcat(x, " ");
		} else {
			strcpy(x, "SCANNED ");
			for (int m = 0; m < (finish ? i : l); m++) {
				strcat(x, inet_ntoa(n[m].addr));
				strcat(x, "/");
				strcat(x, inet_ntoa(n[m].mask));
				strcat(x, " ");
			}
		}
		sprintf(x+strlen(x), "\nWORKINGNUM %d\n", workingnum);
		write(STDIN_FILENO, x, strlen(x));
	}
	if (s != -1)
		if (close(s))
			perror("close(s)");
	if (o != -1)
		if (close(o))
			perror("close(o)");
	return r;
}