1 /*
2  *
3  * (C) 2003-2020 Anope Team
4  * Contact us at team@anope.org
5  *
6  * Please read COPYING and README for further details.
7  *
8  * Based on the original code of Epona by Lara.
9  * Based on the original code of Services by Andy Church.
10  */
11 
12 #ifndef DNS_H
13 #define DNS_H
14 
15 namespace DNS
16 {
17 	/** Valid query types
18 	 */
19 	enum QueryType
20 	{
21 		/* Nothing */
22 		QUERY_NONE,
23 		/* A simple A lookup */
24 		QUERY_A = 1,
25 		/* An authoritative name server */
26 		QUERY_NS = 2,
27 		/* A CNAME lookup */
28 		QUERY_CNAME = 5,
29 		/* Start of a zone of authority */
30 		QUERY_SOA = 6,
31 		/* Reverse DNS lookup */
32 		QUERY_PTR = 12,
33 		/* IPv6 AAAA lookup */
34 		QUERY_AAAA = 28,
35 		/* Zone transfer */
36 		QUERY_AXFR = 252,
37 		/* A lookup for any record */
38 		QUERY_ANY = 255
39 	};
40 
41 	/** Flags that can be AND'd into DNSPacket::flags to receive certain values
42 	 */
43 	enum
44 	{
45 		QUERYFLAGS_QR = 0x8000,
46 		QUERYFLAGS_OPCODE = 0x7800,
47 		QUERYFLAGS_OPCODE_NOTIFY = 0x2000,
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_NOT_AN_ANSWER,
63 		ERROR_NONSTANDARD_QUERY,
64 		ERROR_FORMAT_ERROR,
65 		ERROR_SERVER_FAILURE,
66 		ERROR_DOMAIN_NOT_FOUND,
67 		ERROR_NOT_IMPLEMENTED,
68 		ERROR_REFUSED,
69 		ERROR_NO_RECORDS,
70 		ERROR_INVALIDTYPE
71 	};
72 
73 	struct Question
74 	{
75 		Anope::string name;
76 		QueryType type;
77 		unsigned short qclass;
78 
QuestionQuestion79 		Question() : type(QUERY_NONE), qclass(0) { }
nameQuestion80 		Question(const Anope::string &n, QueryType t, unsigned short c = 1) : name(n), type(t), qclass(c) { }
81 		inline bool operator==(const Question & other) const { return name == other.name && type == other.type && qclass == other.qclass; }
82 
83 		struct hash
84 		{
operatorQuestion::hash85 			size_t operator()(const Question &q) const
86 			{
87 				return Anope::hash_ci()(q.name);
88 			}
89 		};
90 	};
91 
92 	struct ResourceRecord : Question
93 	{
94 		unsigned int ttl;
95 		Anope::string rdata;
96 		time_t created;
97 
QuestionResourceRecord98 		ResourceRecord(const Anope::string &n, QueryType t, unsigned short c = 1) : Question(n, t, c), ttl(0), created(Anope::CurTime) { }
ResourceRecordResourceRecord99 		ResourceRecord(const Question &q) : Question(q), ttl(0), created(Anope::CurTime) { }
100 	};
101 
102 	struct Query
103 	{
104 		std::vector<Question> questions;
105 		std::vector<ResourceRecord> answers, authorities, additional;
106 		Error error;
107 
QueryQuery108 		Query() : error(ERROR_NONE) { }
QueryQuery109 		Query(const Question &q) : error(ERROR_NONE) { questions.push_back(q); }
110 	};
111 
112 	class ReplySocket;
113 	class Request;
114 
115 	/** DNS manager
116 	 */
117 	class Manager : public Service
118 	{
119 	 public:
Manager(Module * creator)120 		Manager(Module *creator) : Service(creator, "DNS::Manager", "dns/manager") { }
~Manager()121 		virtual ~Manager() { }
122 
123 		virtual void Process(Request *req) = 0;
124 		virtual void RemoveRequest(Request *req) = 0;
125 
126 		virtual bool HandlePacket(ReplySocket *s, const unsigned char *const data, int len, sockaddrs *from) = 0;
127 
128 		virtual void UpdateSerial() = 0;
129 		virtual void Notify(const Anope::string &zone) = 0;
130 		virtual uint32_t GetSerial() const = 0;
131 	};
132 
133 	/** A DNS query.
134 	 */
135 	class Request : public Timer, public Question
136 	{
137 		Manager *manager;
138 	 public:
139 		/* Use result cache if available */
140 		bool use_cache;
141 		/* Request id */
142 		unsigned short id;
143 		/* Creator of this request */
144 		Module *creator;
145 
146 		Request(Manager *mgr, Module *c, const Anope::string &addr, QueryType qt, bool cache = false) : Timer(0), Question(addr, qt), manager(mgr),
147 			use_cache(cache), id(0), creator(c) { }
148 
~Request()149 		virtual ~Request()
150 		{
151 			manager->RemoveRequest(this);
152 		}
153 
154 		/** Called when this request succeeds
155 		 * @param r The query sent back from the nameserver
156 		 */
157 		virtual void OnLookupComplete(const Query *r) = 0;
158 
159 		/** Called when this request fails or times out.
160 		 * @param r The query sent back from the nameserver, check the error code.
161 		 */
OnError(const Query * r)162 		virtual void OnError(const Query *r) { }
163 
164 		/** Used to time out the query, xalls OnError and lets the TimerManager
165 		 * delete this request.
166 		 */
Tick(time_t)167 		void Tick(time_t) anope_override
168 		{
169 			Log(LOG_DEBUG_2) << "Resolver: timeout for query " << this->name;
170 			Query rr(*this);
171 			rr.error = ERROR_TIMEDOUT;
172 			this->OnError(&rr);
173 		}
174 	};
175 
176 } // namespace DNS
177 
178 #endif // DNS_H
179