]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - include/modules/dns.h
8ac90f7deb12a24cab248ba710101039416b1588
[user/henk/code/inspircd.git] / include / modules / dns.h
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2017, 2019 Sadie Powell <sadie@witchery.services>
5  *   Copyright (C) 2014-2015 Attila Molnar <attilamolnar@hush.com>
6  *   Copyright (C) 2013, 2015-2016 Adam <Adam@anope.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 #pragma once
22
23 namespace DNS
24 {
25         /** Valid query types
26          */
27         enum QueryType
28         {
29                 /* Nothing */
30                 QUERY_NONE,
31                 /* A simple A lookup */
32                 QUERY_A = 1,
33                 /* A CNAME lookup */
34                 QUERY_CNAME = 5,
35                 /* Reverse DNS lookup */
36                 QUERY_PTR = 12,
37                 /* TXT */
38                 QUERY_TXT = 16,
39                 /* IPv6 AAAA lookup */
40                 QUERY_AAAA = 28
41         };
42
43         /** Flags that can be AND'd into DNSPacket::flags to receive certain values
44          */
45         enum
46         {
47                 QUERYFLAGS_QR = 0x8000,
48                 QUERYFLAGS_OPCODE = 0x7800,
49                 QUERYFLAGS_AA = 0x400,
50                 QUERYFLAGS_TC = 0x200,
51                 QUERYFLAGS_RD = 0x100,
52                 QUERYFLAGS_RA = 0x80,
53                 QUERYFLAGS_Z = 0x70,
54                 QUERYFLAGS_RCODE = 0xF
55         };
56
57         enum Error
58         {
59                 ERROR_NONE,
60                 ERROR_UNKNOWN,
61                 ERROR_UNLOADED,
62                 ERROR_TIMEDOUT,
63                 ERROR_MALFORMED,
64                 ERROR_NOT_AN_ANSWER,
65                 ERROR_NONSTANDARD_QUERY,
66                 ERROR_FORMAT_ERROR,
67                 ERROR_SERVER_FAILURE,
68                 ERROR_DOMAIN_NOT_FOUND,
69                 ERROR_NOT_IMPLEMENTED,
70                 ERROR_REFUSED,
71                 ERROR_NO_RECORDS,
72                 ERROR_INVALIDTYPE
73         };
74
75         typedef uint16_t RequestId;
76
77         const int PORT = 53;
78
79         class Exception : public ModuleException
80         {
81          public:
82                 Exception(const std::string& message) : ModuleException(message) { }
83         };
84
85         struct Question
86         {
87                 std::string name;
88                 QueryType type;
89
90                 Question() : type(QUERY_NONE) { }
91                 Question(const std::string& n, QueryType t) : name(n), type(t) { }
92                 bool operator==(const Question& other) const { return ((name == other.name) && (type == other.type)); }
93                 bool operator!=(const Question& other) const { return (!(*this == other)); }
94
95                 struct hash
96                 {
97                         size_t operator()(const Question& question) const
98                         {
99                                 return irc::insensitive()(question.name);
100                         }
101                 };
102         };
103
104         struct ResourceRecord : Question
105         {
106                 unsigned int ttl;
107                 std::string rdata;
108                 time_t created;
109
110                 ResourceRecord(const std::string& n, QueryType t) : Question(n, t), ttl(0), created(ServerInstance->Time()) { }
111                 ResourceRecord(const Question& question) : Question(question), ttl(0), created(ServerInstance->Time()) { }
112         };
113
114         struct Query
115         {
116                 Question question;
117                 std::vector<ResourceRecord> answers;
118                 Error error;
119                 bool cached;
120
121                 Query() : error(ERROR_NONE), cached(false) { }
122                 Query(const Question& q) : question(q), error(ERROR_NONE), cached(false) { }
123
124                 const ResourceRecord* FindAnswerOfType(QueryType qtype) const
125                 {
126                         for (std::vector<DNS::ResourceRecord>::const_iterator i = answers.begin(); i != answers.end(); ++i)
127                         {
128                                 const DNS::ResourceRecord& rr = *i;
129                                 if (rr.type == qtype)
130                                         return &rr;
131                         }
132
133                         return NULL;
134                 }
135         };
136
137         class ReplySocket;
138         class Request;
139
140         /** DNS manager
141          */
142         class Manager : public DataProvider
143         {
144          public:
145                 Manager(Module* mod) : DataProvider(mod, "DNS") { }
146
147                 virtual void Process(Request* req) = 0;
148                 virtual void RemoveRequest(Request* req) = 0;
149                 virtual std::string GetErrorStr(Error) = 0;
150                 virtual std::string GetTypeStr(QueryType) = 0;
151         };
152
153         /** A DNS query.
154          */
155         class Request : public Timer
156         {
157          protected:
158                 Manager* const manager;
159          public:
160                 Question question;
161                 /* Use result cache if available */
162                 bool use_cache;
163                 /* Request id */
164                 RequestId id;
165                 /* Creator of this request */
166                 Module* const creator;
167
168                 Request(Manager* mgr, Module* mod, const std::string& addr, QueryType qt, bool usecache = true)
169                         : Timer(ServerInstance->Config->ConfValue("dns")->getDuration("timeout", 5, 1))
170                         , manager(mgr)
171                         , question(addr, qt)
172                         , use_cache(usecache)
173                         , id(0)
174                         , creator(mod)
175                 {
176                 }
177
178                 virtual ~Request()
179                 {
180                         manager->RemoveRequest(this);
181                 }
182
183                 /** Called when this request succeeds
184                  * @param r The query sent back from the nameserver
185                  */
186                 virtual void OnLookupComplete(const Query* req) = 0;
187
188                 /** Called when this request fails or times out.
189                  * @param r The query sent back from the nameserver, check the error code.
190                  */
191                 virtual void OnError(const Query* req) { }
192
193                 /** Used to time out the query, calls OnError and asks the TimerManager
194                  * to delete this request
195                  */
196                 bool Tick(time_t now) CXX11_OVERRIDE
197                 {
198                         Query rr(this->question);
199                         rr.error = ERROR_TIMEDOUT;
200                         this->OnError(&rr);
201                         delete this;
202                         return false;
203                 }
204         };
205
206 } // namespace DNS