summaryrefslogtreecommitdiff
path: root/include/dns.h
blob: 8a84bdd47f7c6414394b31a04a378d7808448d06 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
#ifndef DNS_H
#define DNS_H

/** Valid query types
 */
enum QueryType
{
	/* Nothing */
	DNS_QUERY_NONE,
	/* A simple A lookup */
	DNS_QUERY_A = 1,
	/* A CNAME lookup */
	DNS_QUERY_CNAME = 5,
	/* Reverse DNS lookup */
	DNS_QUERY_PTR = 12,
	/* IPv6 AAAA lookup */
	DNS_QUERY_AAAA = 28
};

/** Flags that can be AND'd into DNSPacket::flags to receive certain values
 */
enum QueryFlags
{
	DNS_QUERYFLAGS_QR = 0x8000,
	DNS_QUERYFLAGS_OPCODE = 0x7800,
	DNS_QUERYFLAGS_AA = 0x400,
	DBS_QUERYFLAGS_TC = 0x200,
	DNS_QUERYFLAGS_RD = 0x100,
	DNS_QUERYFLAGS_RA = 0x80,
	DNS_QUERYFLAGS_Z = 0x70,
	DNS_QUERYFLAGS_RCODE = 0xF
};

enum DNSError
{
	DNS_ERROR_NONE,
	DNS_ERROR_UNKNOWN,
	DNS_ERROR_UNLOADED,
	DNS_ERROR_TIMEOUT,
	DNS_ERROR_NOT_AN_ANSWER,
	DNS_ERROR_NONSTANDARD_QUERY,
	DNS_ERROR_FORMAT_ERROR,
	DNS_ERROR_SERVER_FAILURE,
	DNS_ERROR_DOMAIN_NOT_FOUND,
	DNS_ERROR_NOT_IMPLEMENTED,
	DNS_ERROR_REFUSED,
	DNS_ERROR_NO_RECORDS,
	DNS_ERROR_INVALIDTYPE
};

class DNSRequestTimeout; // Forward declarations
struct DNSRecord;
class Module;

/** The request
 */
class CoreExport DNSRequest
{
	/* Timeout timer for this request */
	DNSRequestTimeout *timeout;
	/* Use result cache if available */
	bool use_cache;

 public:
	/* Request id */
 	unsigned short id;
 	/* Creator of this request */
	Module *creator;

	/* Address we're looking up */
	Anope::string address;
	/* QueryType, A, AAAA, PTR etc */
	QueryType QT;

	DNSRequest(const Anope::string &addr, QueryType qt, bool cache = false, Module *c = NULL);

	virtual ~DNSRequest();

	void Process();

	virtual void OnLookupComplete(const DNSRecord *r) = 0;

	virtual void OnError(const DNSRecord *r);
};

/** A full packet sent to the nameserver, may contain multiple queries
 */
struct DNSPacket
{
	/* Our 16-bit id for this header */
	unsigned short id;
	/* Flags on the query */
	unsigned short flags;
	/* Number of queries */
	unsigned short qdcount;
	/* Number of resource records in answer */
	unsigned short ancount;
	/* Number of NS resource records in authority records section */
	unsigned short nscount;
	/* Number of resource records in the additional records section */
	unsigned short arcount;
	/* How many of the bytes of the payload are in use */
	unsigned short payload_count;
	/* The queries, at most can be 512 bytes */
	unsigned char payload[512];

	inline DNSPacket();

	bool AddQuestion(const Anope::string &address, QueryType qt);

	inline void FillPacket(const unsigned char *input, const size_t length);

	inline void FillBuffer(unsigned char *buffer);
};

struct CoreExport DNSRecord
{
	/* Name of the initial lookup */
	Anope::string name;
	/* Result of the lookup */
	Anope::string result;
	/* Type of query this was */
	QueryType type;
	/* Error, if there was one */
	DNSError error;
	/* Record class, should always be 1 */
	unsigned short record_class;
	/* Time to live */
	time_t ttl;
	/* Record length */
	unsigned short rdlength;

	/* When this record was created in our cache */
	time_t created;

	inline DNSRecord(const Anope::string &n);
	operator bool() const;
};

/** DNS manager, manages the connection and all requests
 */
class CoreExport DNSManager : public Timer, public Socket
{
	std::multimap<Anope::string, DNSRecord *> cache;
	sockaddrs addrs;
 public:
	std::deque<DNSPacket *> packets;
	std::map<short, DNSRequest *> requests;

	static const int DNSPort = 53;

	DNSManager(const Anope::string &nameserver, int port);

	~DNSManager();

	bool ProcessRead();

	bool ProcessWrite();

	void AddCache(DNSRecord *rr);
	bool CheckCache(DNSRequest *request);
	void Tick(time_t now);

	void Cleanup(Module *mod);

	/** Does a BLOCKING DNS query and returns the first IP.
	 * Only use this if you know what you are doing. Unless you specifically
	 * need a blocking query use the DNSRequest system
	 */
	static DNSRecord BlockingQuery(const Anope::string &mask, QueryType qt);
};

/** A DNS timeout, one is made for every DNS request to detect timeouts
 */
class DNSRequestTimeout : public Timer
{
	DNSRequest *request;
 public:
 	bool done;

	DNSRequestTimeout(DNSRequest *r, time_t timeout);

	~DNSRequestTimeout();

	void Tick(time_t);
};

extern DNSManager *DNSEngine;

#endif // DNS_H