]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - include/dns.h
Do not use the result of the dns cache when the query type of the result is different...
[user/henk/code/inspircd.git] / include / dns.h
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
5  *   Copyright (C) 2005-2008 Craig Edwards <craigedwards@brainbox.cc>
6  *   Copyright (C) 2007 Dennis Friis <peavey@inspircd.org>
7  *
8  * This file is part of InspIRCd.  InspIRCd is free software: you can
9  * redistribute it and/or modify it under the terms of the GNU General Public
10  * License as published by the Free Software Foundation, version 2.
11  *
12  * This program is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
15  * details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21
22 /*
23 dns.h - dns library very very loosely based on
24 firedns, Copyright (C) 2002 Ian Gulliver
25
26 This program is free software; you can redistribute it and/or modify
27 it under the terms of version 2 of the GNU General Public License as
28 published by the Free Software Foundation.
29
30 This program is distributed in the hope that it will be useful,
31 but WITHOUT ANY WARRANTY; without even the implied warranty of
32 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
33 GNU General Public License for more details.
34
35 You should have received a copy of the GNU General Public License
36 along with this program; if not, write to the Free Software
37 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
38 */
39
40 #ifndef DNS_H
41 #define DNS_H
42
43 #include "socket.h"
44 #include "hashcomp.h"
45
46 /**
47  * Query and resource record types
48  */
49 enum QueryType
50 {
51         /** Uninitialized Query */
52         DNS_QUERY_NONE  = 0,
53         /** 'A' record: an ipv4 address */
54         DNS_QUERY_A     = 1,
55         /** 'CNAME' record: An alias */
56         DNS_QUERY_CNAME = 5,
57         /** 'PTR' record: a hostname */
58         DNS_QUERY_PTR   = 12,
59         /** 'AAAA' record: an ipv6 address */
60         DNS_QUERY_AAAA  = 28,
61
62         /** Force 'PTR' to use IPV4 scemantics */
63         DNS_QUERY_PTR4  = 0xFFFD,
64         /** Force 'PTR' to use IPV6 scemantics */
65         DNS_QUERY_PTR6  = 0xFFFE
66 };
67
68 /**
69  * Result status, used internally
70  */
71 class CoreExport DNSResult
72 {
73  public:
74         /** Result ID
75          */
76         int id;
77         /** Result body, a hostname or IP address
78          */
79         std::string result;
80         /** Time-to-live value of the result
81          */
82         unsigned long ttl;
83         /** The original request, a hostname or IP address
84          */
85         std::string original;
86         /** The type of the request
87          */
88         QueryType type;
89
90         /** Build a DNS result.
91          * @param i The request ID
92          * @param res The request result, a hostname or IP
93          * @param timetolive The request time-to-live
94          * @param orig The original request, a hostname or IP
95          */
96         DNSResult(int i, const std::string &res, unsigned long timetolive, const std::string &orig, QueryType qt = DNS_QUERY_NONE) : id(i), result(res), ttl(timetolive), original(orig), type(qt) { }
97 };
98
99 /**
100  * Information on a completed lookup, used internally
101  */
102 typedef std::pair<unsigned char*, std::string> DNSInfo;
103
104 /** Cached item stored in the query cache.
105  */
106 class CoreExport CachedQuery
107 {
108  public:
109         /** The cached result data, an IP or hostname
110          */
111         std::string data;
112         /** The type of result this is
113          */
114         QueryType type;
115         /** The time when the item is due to expire
116          */
117         time_t expires;
118
119         /** Build a cached query
120          * @param res The result data, an IP or hostname
121          * @param ttl The time-to-live value of the query result
122          */
123         CachedQuery(const std::string &res, QueryType qt, unsigned int ttl);
124
125         /** Returns the number of seconds remaining before this
126          * cache item has expired and should be removed.
127          */
128         int CalcTTLRemaining();
129 };
130
131 /** DNS cache information. Holds IPs mapped to hostnames, and hostnames mapped to IPs.
132  */
133 typedef nspace::hash_map<irc::string, CachedQuery, irc::hash> dnscache;
134
135 /**
136  * Error types that class Resolver can emit to its error method.
137  */
138 enum ResolverError
139 {
140         RESOLVER_NOERROR        =       0,
141         RESOLVER_NSDOWN         =       1,
142         RESOLVER_NXDOMAIN       =       2,
143         RESOLVER_BADIP          =       3,
144         RESOLVER_TIMEOUT        =       4,
145         RESOLVER_FORCEUNLOAD    =       5
146 };
147
148 /**
149  * Used internally to force PTR lookups to use a certain protocol scemantics,
150  * e.g. x.x.x.x.in-addr.arpa for v4, and *.ip6.arpa for v6.
151  */
152 enum ForceProtocol
153 {
154         /** Forced to use ipv4 */
155         PROTOCOL_IPV4 = 0,
156         /** Forced to use ipv6 */
157         PROTOCOL_IPV6 = 1
158 };
159
160 /**
161  * The Resolver class is a high-level abstraction for resolving DNS entries.
162  * It can do forward and reverse IPv4 lookups, and where IPv6 is supported, will
163  * also be able to do those, transparent of protocols. Module developers must
164  * extend this class via inheritence, and then insert a pointer to their derived
165  * class into the core using Server::AddResolver(). Once you have done this,
166  * the class will be able to receive callbacks. There are two callbacks which
167  * can occur by calling virtual methods, one is a success situation, and the other
168  * an error situation.
169  */
170 class CoreExport Resolver
171 {
172  protected:
173         /**
174          * Pointer to creator module (if any, or NULL)
175          */
176         ModuleRef Creator;
177         /**
178          * The input data, either a host or an IP address
179          */
180         std::string input;
181         /**
182          * True if a forward lookup is being performed, false if otherwise
183          */
184         QueryType querytype;
185         /**
186          * The DNS erver being used for lookups. If this is an empty string,
187          * the value of ServerConfig::DNSServer is used instead.
188          */
189         std::string server;
190         /**
191          * The ID allocated to your lookup. This is a pseudo-random number
192          * between 0 and 65535, a value of -1 indicating a failure.
193          * The core uses this to route results to the correct objects.
194          */
195         int myid;
196
197         /**
198          * Cached result, if there is one
199          */
200         CachedQuery *CQ;
201
202         /**
203          * Time left before cache expiry
204          */
205         int time_left;
206
207  public:
208         /**
209          * Initiate DNS lookup. Your class should not attempt to delete or free these
210          * objects, as the core will do this for you. They must always be created upon
211          * the heap using new, as you cannot be sure at what time they will be deleted.
212          * Allocating them on the stack or attempting to delete them yourself could cause
213          * the object to go 'out of scope' and cause a segfault in the core if the result
214          * arrives at a later time.
215          * @param source The IP or hostname to resolve
216          * @param qt The query type to perform. Resolution of 'A', 'AAAA', 'PTR' and 'CNAME' records
217          * is supported. Use one of the QueryType enum values to initiate this type of
218          * lookup. Resolution of 'AAAA' ipv6 records is always supported, regardless of
219          * wether InspIRCd is built with ipv6 support.
220          * To look up reverse records, specify one of DNS_QUERY_PTR4 or DNS_QUERY_PTR6 depending
221          * on the type of address you are looking up.
222          * @param cached The constructor will set this boolean to true or false depending
223          * on whether the DNS lookup you are attempting is cached (and not expired) or not.
224          * If the value is cached, upon return this will be set to true, otherwise it will
225          * be set to false. You should pass this value to InspIRCd::AddResolver(), which
226          * will then influence the behaviour of the method and determine whether a cached
227          * or non-cached result is obtained. The value in this variable is always correct
228          * for the given request when the constructor exits.
229          * @param creator See the note below.
230          * @throw ModuleException This class may throw an instance of ModuleException, in the
231          * event a lookup could not be allocated, or a similar hard error occurs such as
232          * the network being down. This will also be thrown if an invalid IP address is
233          * passed when resolving a 'PTR' record.
234          *
235          * NOTE: If you are instantiating your DNS lookup from a module, you should set the
236          * value of creator to point at your Module class. This way if your module is unloaded
237          * whilst lookups are in progress, they can be safely removed and your module will not
238          * crash the server.
239          */
240         Resolver(const std::string &source, QueryType qt, bool &cached, Module* creator);
241
242         /**
243          * The default destructor does nothing.
244          */
245         virtual ~Resolver();
246
247         /**
248          * When your lookup completes, this method will be called.
249          * @param result The resulting DNS lookup, either an IP address or a hostname.
250          * @param ttl The time-to-live value of the result, in the instance of a cached
251          * result, this is the number of seconds remaining before refresh/expiry.
252          * @param cached True if the result is a cached result, false if it was requested
253          * from the DNS server.
254          */
255         virtual void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached) = 0;
256
257         /**
258          * If an error occurs (such as NXDOMAIN, no domain name found) then this method
259          * will be called.
260          * @param e A ResolverError enum containing the error type which has occured.
261          * @param errormessage The error text of the error that occured.
262          */
263         virtual void OnError(ResolverError e, const std::string &errormessage);
264
265         /**
266          * Returns the id value of this class. This is primarily used by the core
267          * to determine where in various tables to place a pointer to your class, but it
268          * is safe to call and use this method.
269          * As specified in RFC1035, each dns request has a 16 bit ID value, ranging
270          * from 0 to 65535. If there is an issue and the core cannot send your request,
271          * this method will return -1.
272          */
273         int GetId();
274
275         /**
276          * Returns the creator module, or NULL
277          */
278         Module* GetCreator();
279
280         /**
281          * If the result is a cached result, this triggers the objects
282          * OnLookupComplete. This is done because it is not safe to call
283          * the abstract virtual method from the constructor.
284          */
285         void TriggerCachedResult();
286 };
287
288 /** DNS is a singleton class used by the core to dispatch dns
289  * requests to the dns server, and route incoming dns replies
290  * back to Resolver objects, based upon the request ID. You
291  * should never use this class yourself.
292  */
293 class CoreExport DNS : public EventHandler
294 {
295  private:
296
297         /**
298          * The maximum value of a dns request id,
299          * 16 bits wide, 0xFFFF.
300          */
301         static const int MAX_REQUEST_ID = 0xFFFF;
302
303         /**
304          * Currently cached items
305          */
306         dnscache* cache;
307
308         /** A timer which ticks every hour to remove expired
309          * items from the DNS cache.
310          */
311         class CacheTimer* PruneTimer;
312
313         /**
314          * Build a dns packet payload
315          */
316         int MakePayload(const char* name, const QueryType rr, const unsigned short rr_class, unsigned char* payload);
317
318  public:
319
320         irc::sockets::sockaddrs myserver;
321
322         /**
323          * Currently active Resolver classes
324          */
325         Resolver* Classes[MAX_REQUEST_ID];
326
327         /**
328          * Requests that are currently 'in flight'
329          */
330         DNSRequest* requests[MAX_REQUEST_ID];
331
332         /**
333          * The port number DNS requests are made on,
334          * and replies have as a source-port number.
335          */
336         static const int QUERY_PORT = 53;
337
338         /**
339          * Fill an rr (resource record) with data from input
340          */
341         static void FillResourceRecord(ResourceRecord* rr, const unsigned char* input);
342
343         /**
344          * Fill a header with data from input limited by a length
345          */
346         static void FillHeader(DNSHeader *header, const unsigned char *input, const int length);
347
348         /**
349          * Empty out a header into a data stream ready for transmission "on the wire"
350          */
351         static void EmptyHeader(unsigned char *output, const DNSHeader *header, const int length);
352
353         /**
354          * Start the lookup of an ipv4 from a hostname
355          */
356         int GetIP(const char* name);
357
358         /**
359          * Start lookup of a hostname from an ip, but
360          * force a specific protocol to be used for the lookup
361          * for example to perform an ipv6 reverse lookup.
362          */
363         int GetNameForce(const char *ip, ForceProtocol fp);
364
365         /**
366          * Start lookup of an ipv6 from a hostname
367          */
368         int GetIP6(const char *name);
369
370         /**
371          * Start lookup of a CNAME from another hostname
372          */
373         int GetCName(const char* alias);
374
375         /**
376          * Fetch the result string (an ip or host)
377          * and/or an error message to go with it.
378          */
379         DNSResult GetResult();
380
381         /**
382          * Handle a SocketEngine read event
383          * Inherited from EventHandler
384          */
385         void HandleEvent(EventType et, int errornum = 0);
386
387         /**
388          * Add a Resolver* to the list of active classes
389          */
390         bool AddResolverClass(Resolver* r);
391
392         /**
393          * Add a query to the list to be sent
394          */
395         DNSRequest* AddQuery(DNSHeader *header, int &id, const char* original);
396
397         /**
398          * The constructor initialises the dns socket,
399          * and clears the request lists.
400          */
401         DNS();
402
403         /**
404          * Re-initialize the DNS subsystem.
405          */
406         void Rehash();
407
408         /**
409          * Destructor
410          */
411         ~DNS();
412
413         /**
414          * Turn an in6_addr into a .ip6.arpa domain
415          */
416         static void MakeIP6Int(char* query, const in6_addr *ip);
417
418         /**
419          * Clean out all dns resolvers owned by a particular
420          * module, to make unloading a module safe if there
421          * are dns requests currently in progress.
422          */
423         void CleanResolvers(Module* module);
424
425         /** Return the cached value of an IP or hostname
426          * @param source An IP or hostname to find in the cache.
427          * @return A pointer to a CachedQuery if the item exists,
428          * otherwise NULL.
429          */
430         CachedQuery* GetCache(const std::string &source);
431
432         /** Delete a cached item from the DNS cache.
433          * @param source An IP or hostname to remove
434          */
435         void DelCache(const std::string &source);
436
437         /** Clear all items from the DNS cache immediately.
438          */
439         int ClearCache();
440
441         /** Prune the DNS cache, e.g. remove all expired
442          * items and rehash the cache buckets, but leave
443          * items in the hash which are still valid.
444          */
445         int PruneCache();
446 };
447
448 #endif
449