]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - include/modules/dns.h
Merge pull request #677 from Robby-/master-dnsblzline
[user/henk/code/inspircd.git] / include / modules / dns.h
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2013 Adam <Adam@anope.org>
5  *   Copyright (C) 2003-2013 Anope Team <team@anope.org>
6  *
7  * This file is part of InspIRCd.  InspIRCd is free software: you can
8  * redistribute it and/or modify it under the terms of the GNU General Public
9  * License as published by the Free Software Foundation, version 2.
10  *
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
14  * details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #pragma once
21
22 namespace DNS
23 {
24         /** Valid query types
25          */
26         enum QueryType
27         {
28                 /* Nothing */
29                 QUERY_NONE,
30                 /* A simple A lookup */
31                 QUERY_A = 1,
32                 /* A CNAME lookup */
33                 QUERY_CNAME = 5,
34                 /* Reverse DNS lookup */
35                 QUERY_PTR = 12,
36                 /* TXT */
37                 QUERY_TXT = 16,
38                 /* IPv6 AAAA lookup */
39                 QUERY_AAAA = 28
40         };
41
42         /** Flags that can be AND'd into DNSPacket::flags to receive certain values
43          */
44         enum
45         {
46                 QUERYFLAGS_QR = 0x8000,
47                 QUERYFLAGS_OPCODE = 0x7800,
48                 QUERYFLAGS_AA = 0x400,
49                 QUERYFLAGS_TC = 0x200,
50                 QUERYFLAGS_RD = 0x100,
51                 QUERYFLAGS_RA = 0x80,
52                 QUERYFLAGS_Z = 0x70,
53                 QUERYFLAGS_RCODE = 0xF
54         };
55
56         enum Error
57         {
58                 ERROR_NONE,
59                 ERROR_UNKNOWN,
60                 ERROR_UNLOADED,
61                 ERROR_TIMEDOUT,
62                 ERROR_MALFORMED,
63                 ERROR_NOT_AN_ANSWER,
64                 ERROR_NONSTANDARD_QUERY,
65                 ERROR_FORMAT_ERROR,
66                 ERROR_SERVER_FAILURE,
67                 ERROR_DOMAIN_NOT_FOUND,
68                 ERROR_NOT_IMPLEMENTED,
69                 ERROR_REFUSED,
70                 ERROR_NO_RECORDS,
71                 ERROR_INVALIDTYPE
72         };
73
74         typedef uint16_t RequestId;
75
76         const int PORT = 53;
77
78         class Exception : public ModuleException
79         {
80          public:
81                 Exception(const std::string& message) : ModuleException(message) { }
82         };
83
84         struct Question
85         {
86                 std::string name;
87                 QueryType type;
88
89                 Question() : type(QUERY_NONE) { }
90                 Question(const std::string& n, QueryType t) : name(n), type(t) { }
91                 bool operator==(const Question& other) const { return ((name == other.name) && (type == other.type)); }
92                 bool operator!=(const Question& other) const { return (!(*this == other)); }
93
94                 struct hash
95                 {
96                         size_t operator()(const Question& question) const
97                         {
98                                 return irc::insensitive()(question.name);
99                         }
100                 };
101         };
102
103         struct ResourceRecord : Question
104         {
105                 unsigned int ttl;
106                 std::string rdata;
107                 time_t created;
108
109                 ResourceRecord(const std::string& n, QueryType t) : Question(n, t), ttl(0), created(ServerInstance->Time()) { }
110                 ResourceRecord(const Question& question) : Question(question), ttl(0), created(ServerInstance->Time()) { }
111         };
112
113         struct Query
114         {
115                 Question question;
116                 std::vector<ResourceRecord> answers;
117                 Error error;
118                 bool cached;
119
120                 Query() : error(ERROR_NONE), cached(false) { }
121                 Query(const Question& q) : question(q), error(ERROR_NONE), cached(false) { }
122
123                 const ResourceRecord* FindAnswerOfType(QueryType qtype) const
124                 {
125                         for (std::vector<DNS::ResourceRecord>::const_iterator i = answers.begin(); i != answers.end(); ++i)
126                         {
127                                 const DNS::ResourceRecord& rr = *i;
128                                 if (rr.type == qtype)
129                                         return &rr;
130                         }
131
132                         return NULL;
133                 }
134         };
135
136         class ReplySocket;
137         class Request;
138
139         /** DNS manager
140          */
141         class Manager : public DataProvider
142         {
143          public:
144                 Manager(Module* mod) : DataProvider(mod, "DNS") { }
145
146                 virtual void Process(Request* req) = 0;
147                 virtual void RemoveRequest(Request* req) = 0;
148                 virtual std::string GetErrorStr(Error) = 0;
149         };
150
151         /** A DNS query.
152          */
153         class Request : public Timer
154         {
155          protected:
156                 Manager* const manager;
157          public:
158                 Question question;
159                 /* Use result cache if available */
160                 bool use_cache;
161                 /* Request id */
162                 RequestId id;
163                 /* Creator of this request */
164                 Module* const creator;
165
166                 Request(Manager* mgr, Module* mod, const std::string& addr, QueryType qt, bool usecache = true)
167                         : Timer((ServerInstance->Config->dns_timeout ? ServerInstance->Config->dns_timeout : 5))
168                         , manager(mgr)
169                         , question(addr, qt)
170                         , use_cache(usecache)
171                         , id(0)
172                         , creator(mod)
173                 {
174                 }
175
176                 virtual ~Request()
177                 {
178                         manager->RemoveRequest(this);
179                 }
180
181                 /** Called when this request succeeds
182                  * @param r The query sent back from the nameserver
183                  */
184                 virtual void OnLookupComplete(const Query* req) = 0;
185
186                 /** Called when this request fails or times out.
187                  * @param r The query sent back from the nameserver, check the error code.
188                  */
189                 virtual void OnError(const Query* req) { }
190
191                 /** Used to time out the query, calls OnError and asks the TimerManager
192                  * to delete this request
193                  */
194                 bool Tick(time_t now)
195                 {
196                         Query rr(this->question);
197                         rr.error = ERROR_TIMEDOUT;
198                         this->OnError(&rr);
199                         delete this;
200                         return false;
201                 }
202         };
203
204 } // namespace DNS