1 module dnslib.generator;
2 
3 
4 import dnslib.defs;
5 
6 import std.conv: to;
7 import std.random;
8 
9 ushort IDcounter = 0;
10 
11 // Very simple random generator used for creating dns request ID values
12 auto randomEngine = MinstdRand(1);	// Generator is reseeded in module constructor
13 
14 static this()
15 {
16 	randomEngine.seed(unpredictableSeed);
17 }
18 
19 // ---------------------------------------------------------------------
20 
21 ushort newDnsId()
22 {
23 	IDcounter = to!ushort((IDcounter + uniform(1, ushort.max-1, randomEngine)) % ushort.max);
24 	return IDcounter;
25 }
26 
27 // ---------------------------------------------------------------------
28 
29 bool generateRequest(string domainName, dnsType type, out ushort dnsId, out ubyte[] requestData, bool recursionDesired = true)
30 {
31 	import std.bitmanip: swapEndian;
32 
33 	static assert (ushort.sizeof == 2);
34 	dnsId = newDnsId();
35 	ushort[] requestHeader = [dnsId, recursionDesired ? 0x0100 : 0x0000, 1, 0, 0, 0];  // 0x0100 = standard query with recursion desired; Only one query section.
36 	foreach(i,v; requestHeader)
37 	{
38 		requestHeader[i] = requestHeader[i].swapEndian();
39 	}
40 	
41 	requestData = cast(ubyte[])requestHeader;
42 
43 	if (domainName.length == 0 || domainName.length > 253) { return false; }
44 	
45 	import std..string: split;
46 	string[] domainNameElements = domainName.split(".");
47 	if (domainNameElements.length > 127) { return false; }
48 
49 	foreach(element; domainNameElements)
50 	{
51 		assert(1 <= element.length && element.length <= 63);
52 		if (element.length == 0 || element.length > 63) { return false; }
53 		requestData ~= to!ubyte(element.length);
54 		requestData ~= cast(ubyte[])element;
55 	}
56 	requestData ~= 0;
57 
58 	ushort requestClass = dnsClass.INET;
59 	ushort[] typeAndClass = [(cast(ushort)type).swapEndian(), requestClass.swapEndian()];
60 	requestData ~= cast(ubyte[])typeAndClass;
61 	
62 	return true;
63 }  // generateRequest
64 
65 // ---------------------------------------------------------------------
66 
67 bool generateReverseRequest(string ipstring, out ushort dnsId, out ubyte[] requestData)
68 {
69 	if (ipstring.length < 7 || ipstring.length > 15) { return false; }
70 	
71 	import std..string: split, join;
72 	string[] ipstringElements = ipstring.split(".");
73 	assert(ipstringElements.length == 4);
74 	foreach(element; ipstringElements)
75 	{
76 		if (element.length == 0 || element.length > 3) { return false; }
77 		foreach (c; element)
78 		{
79 			import std.ascii: isDigit;
80 			if (!c.isDigit()) { return false; }
81 		}
82 	}
83 	
84 	import std.algorithm.mutation: reverse;
85 	string domainName = ipstringElements.reverse.join(".") ~ ".in-addr.arpa";
86 	
87 	dnsType reverseDnsType = dnsType.PTR;
88 	generateRequest(domainName, reverseDnsType, dnsId, requestData, true);
89 	
90 	return true;
91 }  // generateReverseRequest
92