#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) {
}