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