summaryrefslogblamecommitdiffstats
path: root/main.c
blob: ec94e3f3385058b4e50743e56614d5a377d49f1e (plain) (tree)





























































































































































































                                                                                                     
#include <sys/socket.h> /* udp(7) */	/* TODO: random XID */
#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> /* byteorder(3) */
#include <string.h> /* strlen(3) */
#include "domain2name.c"
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#define MAX(a,b) ((a) > (b) ? (a) : (b))
#define MAXDOMAIN 255
#define QUERYDOMAIN "http://sijanec.eu/link?r=.sijanec.eu."
#define	EXPECTEDA 93.103.235.126
#define HELP "find recursive DNS resolvers on IPv4 networks\n" \
	"%s [-h] [-d domain] [-a ipv4] network1 [network2 [network3 ...]]\n" \
	"	-a Specify the IPv4 of the -d domain to be used instead of getaddrinfo(3).\n" \
	"	-d Specify the domain name to be used in queries that has a single A record.\n" \
	"	-h Show this help and exit.\n" \
	"Networks are specified as domain names or IPv4 addresses followed by a forward slash\n" \
	"and the netmask in decimal (0-32) or dot notation. For example: example.com/32. \n" \
	"When scanning the Internet please make sure that you specify your own domain instead\n" \
	"of the default one (f@sijanec.eu-http://sijanec.eu/link?r=.sijanec.eu). Make sure it\n" \
	"somehow contains your contact information so the network/server administrator when\n" \
	"looking at the logs will be able to contact you.\n"
/* DNS PACKET: HEADER (12 bytes) QUESTION ANSWER AUTHORITY ADDITIONAL

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	 8 bits: first two bits one, then 6 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:
	XID	16 bits: random string to be matched in response to prevent cache poisoning
     /	QR	 1 bit : what type is this packet?	0 query	1 response
    |	OPCODE   4 bits: type of query			0 std	1 invrs	2 srvst	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
	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


*/
enum qr {
	Query,
	Response
};
enum opcode {
	Query,
	Iquery,
	Stauts
};
enum rcode {
	Success,
	Format_error,
	Servfail,
	Nxdomain,
	Ni,
	Forbidden
};
enum type {
	A = 1,
	Ns,
	Md,
	Mf,
	Cname,
	Soa,
	Mb,
	Mg,
	Mr,
	Null,
	Wks,
	Ptr,
	Hinfo,
	Minfo,
	Mx,
	Txt
}
enum class {
	In = 1,
	Cs,
	Ch,
	He,
	Any = 255
}
struct header {
	uint16_t xid;
	enum qr qr : 1;
	enum opcode opcode : 4;
	unsigned int aa : 1;
	unsigned int tc : 1;
	unsigned int rd : 1;
	unsigned int ra : 1;
	unsigned int z : 3;
	enum rcode rcode : 4;
	uint16_t qdcount;
	uint16_t ancount;
	uint16_t nscount;
	uint16_t arcount;
};
struct question {
	char * qname;
	enum qtype qtype : 16;
	enum qclass qclass : 16;
};
struct answer {
	char * name;
	enum class class : 16;
	uint16_t rdlen;
	char * rdata;
}
int main (int argc, char ** argv) {
	int r = 0;
	while (t) {
		switch (getopt(argc, argv, ":a:d:h")) {
			/* TODO */
			case 'h':
				printf(HELP, argv[0]);
				r = 0;
				goto r;
			case -1:
				d = optarg;
				if (!d || !*d) {
					fprintf(stderr, "specify the domain :: " HELP, argv[0]);
					r = 4;
					goto r;
				}
				if (strlen(d) > MAXDOMAIN) {
					fprintf(stderr, "domain is too long - max "#MAXDOMAIN".\n");
					r = 5;
					goto r;
				}
				t = 0;
				break;
			case '?':
				fprintf(stderr, "unknown option :: " HELP, argv[0]);
				if (db != -1)
					close(db);
				r = 6;
				goto r;
			case ':':
				fprintf(stderr, "missing option argument :: " HELP, argv[0]);
				r = 7;
				goto r;
		}
	}
r:
	if (s != -1)
		if (close(s))
			perror("close(s)");
	}
	return r;
}
int handle () {
	char buf[512]; /* we don't support EDNS0 here, so max DNS packet is 512 bytes */
	recvfrom();
}
int query () {
	sendto();
}
int erase (char * dbfn, int dbfd, char * db) {
	
}