anope

- supernets anope source code & configuration
git clone git://git.acid.vegas/anope.git
Log | Files | Refs | Archive | README

m_dns.cpp (27353B)

      1 /*
      2  *
      3  * (C) 2003-2022 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 #include "module.h"
     13 #include "modules/dns.h"
     14 
     15 using namespace DNS;
     16 
     17 namespace
     18 {
     19 	Anope::string admin, nameservers;
     20 	int refresh;
     21 	time_t timeout;
     22 }
     23 
     24 /** A full packet sent or received to/from the nameserver
     25  */
     26 class Packet : public Query
     27 {
     28 	static bool IsValidName(const Anope::string &name)
     29 	{
     30 		return name.find_first_not_of("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-") == Anope::string::npos;
     31 	}
     32 
     33 	void PackName(unsigned char *output, unsigned short output_size, unsigned short &pos, const Anope::string &name)
     34 	{
     35 		if (pos + name.length() + 2 > output_size)
     36 			throw SocketException("Unable to pack name");
     37 
     38 		Log(LOG_DEBUG_2) << "Resolver: PackName packing " << name;
     39 
     40 		sepstream sep(name, '.');
     41 		Anope::string token;
     42 
     43 		while (sep.GetToken(token))
     44 		{
     45 			output[pos++] = token.length();
     46 			memcpy(&output[pos], token.c_str(), token.length());
     47 			pos += token.length();
     48 		}
     49 
     50 		output[pos++] = 0;
     51 	}
     52 
     53 	Anope::string UnpackName(const unsigned char *input, unsigned short input_size, unsigned short &pos)
     54 	{
     55 		Anope::string name;
     56 		unsigned short pos_ptr = pos, lowest_ptr = input_size;
     57 		bool compressed = false;
     58 
     59 		if (pos_ptr >= input_size)
     60 			throw SocketException("Unable to unpack name - no input");
     61 
     62 		while (input[pos_ptr] > 0)
     63 		{
     64 			unsigned short offset = input[pos_ptr];
     65 
     66 			if (offset & POINTER)
     67 			{
     68 				if ((offset & POINTER) != POINTER)
     69 					throw SocketException("Unable to unpack name - bogus compression header");
     70 				if (pos_ptr + 1 >= input_size)
     71 					throw SocketException("Unable to unpack name - bogus compression header");
     72 
     73 				/* Place pos at the second byte of the first (farthest) compression pointer */
     74 				if (compressed == false)
     75 				{
     76 					++pos;
     77 					compressed = true;
     78 				}
     79 
     80 				pos_ptr = (offset & LABEL) << 8 | input[pos_ptr + 1];
     81 
     82 				/* Pointers can only go back */
     83 				if (pos_ptr >= lowest_ptr)
     84 					throw SocketException("Unable to unpack name - bogus compression pointer");
     85 				lowest_ptr = pos_ptr;
     86 			}
     87 			else
     88 			{
     89 				if (pos_ptr + offset + 1 >= input_size)
     90 					throw SocketException("Unable to unpack name - offset too large");
     91 				if (!name.empty())
     92 					name += ".";
     93 				for (unsigned i = 1; i <= offset; ++i)
     94 					name += input[pos_ptr + i];
     95 
     96 				pos_ptr += offset + 1;
     97 				if (compressed == false)
     98 					/* Move up pos */
     99 					pos = pos_ptr;
    100 			}
    101 		}
    102 
    103 		/* +1 pos either to one byte after the compression pointer or one byte after the ending \0 */
    104 		++pos;
    105 
    106 		/* Empty names are valid (root domain) */
    107 
    108 		Log(LOG_DEBUG_2) << "Resolver: UnpackName successfully unpacked " << name;
    109 
    110 		return name;
    111 	}
    112 
    113 	Question UnpackQuestion(const unsigned char *input, unsigned short input_size, unsigned short &pos)
    114 	{
    115 		Question question;
    116 
    117 		question.name = this->UnpackName(input, input_size, pos);
    118 
    119 		if (pos + 4 > input_size)
    120 			throw SocketException("Unable to unpack question");
    121 
    122 		if (!IsValidName(question.name))
    123 			throw SocketException("Invalid question name");
    124 
    125 		question.type = static_cast<QueryType>(input[pos] << 8 | input[pos + 1]);
    126 		pos += 2;
    127 
    128 		question.qclass = input[pos] << 8 | input[pos + 1];
    129 		pos += 2;
    130 
    131 		return question;
    132 	}
    133 
    134 	ResourceRecord UnpackResourceRecord(const unsigned char *input, unsigned short input_size, unsigned short &pos)
    135 	{
    136 		ResourceRecord record = static_cast<ResourceRecord>(this->UnpackQuestion(input, input_size, pos));
    137 
    138 		if (pos + 6 > input_size)
    139 			throw SocketException("Unable to unpack resource record");
    140 
    141 		record.ttl = (input[pos] << 24) | (input[pos + 1] << 16) | (input[pos + 2] << 8) | input[pos + 3];
    142 		pos += 4;
    143 
    144 		//record.rdlength = input[pos] << 8 | input[pos + 1];
    145 		pos += 2;
    146 
    147 		switch (record.type)
    148 		{
    149 			case QUERY_A:
    150 			{
    151 				if (pos + 4 > input_size)
    152 					throw SocketException("Unable to unpack resource record");
    153 
    154 				in_addr a;
    155 				a.s_addr = input[pos] | (input[pos + 1] << 8) | (input[pos + 2] << 16)  | (input[pos + 3] << 24);
    156 				pos += 4;
    157 
    158 				sockaddrs addrs;
    159 				addrs.ntop(AF_INET, &a);
    160 				if (!addrs.valid())
    161 					throw SocketException("Invalid IP");
    162 
    163 				record.rdata = addrs.addr();
    164 				break;
    165 			}
    166 			case QUERY_AAAA:
    167 			{
    168 				if (pos + 16 > input_size)
    169 					throw SocketException("Unable to unpack resource record");
    170 
    171 				in6_addr a;
    172 				for (int j = 0; j < 16; ++j)
    173 					a.s6_addr[j] = input[pos + j];
    174 				pos += 16;
    175 
    176 				sockaddrs addrs;
    177 				addrs.ntop(AF_INET6, &a);
    178 				if (!addrs.valid())
    179 					throw SocketException("Invalid IP");
    180 
    181 				record.rdata = addrs.addr();
    182 				break;
    183 			}
    184 			case QUERY_CNAME:
    185 			case QUERY_PTR:
    186 			{
    187 				record.rdata = this->UnpackName(input, input_size, pos);
    188 
    189 				if (!IsValidName(record.rdata))
    190 					throw SocketException("Invalid cname/ptr record data");
    191 
    192 				break;
    193 			}
    194 			default:
    195 				break;
    196 		}
    197 
    198 		Log(LOG_DEBUG_2) << "Resolver: " << record.name << " -> " << record.rdata;
    199 
    200 		return record;
    201 	}
    202 
    203  public:
    204 	static const int POINTER = 0xC0;
    205 	static const int LABEL = 0x3F;
    206 	static const int HEADER_LENGTH = 12;
    207 
    208 	Manager *manager;
    209 	/* Source or destination of the packet */
    210 	sockaddrs addr;
    211 	/* ID for this packet */
    212 	unsigned short id;
    213 	/* Flags on the packet */
    214 	unsigned short flags;
    215 
    216 	Packet(Manager *m, sockaddrs *a) : manager(m), id(0), flags(0)
    217 	{
    218 		if (a)
    219 			addr = *a;
    220 	}
    221 
    222 	void Fill(const unsigned char *input, const unsigned short len)
    223 	{
    224 		if (len < HEADER_LENGTH)
    225 			throw SocketException("Unable to fill packet");
    226 
    227 		unsigned short packet_pos = 0;
    228 
    229 		this->id = (input[packet_pos] << 8) | input[packet_pos + 1];
    230 		packet_pos += 2;
    231 
    232 		this->flags = (input[packet_pos] << 8) | input[packet_pos + 1];
    233 		packet_pos += 2;
    234 
    235 		unsigned short qdcount = (input[packet_pos] << 8) | input[packet_pos + 1];
    236 		packet_pos += 2;
    237 
    238 		unsigned short ancount = (input[packet_pos] << 8) | input[packet_pos + 1];
    239 		packet_pos += 2;
    240 
    241 		unsigned short nscount = (input[packet_pos] << 8) | input[packet_pos + 1];
    242 		packet_pos += 2;
    243 
    244 		unsigned short arcount = (input[packet_pos] << 8) | input[packet_pos + 1];
    245 		packet_pos += 2;
    246 
    247 		Log(LOG_DEBUG_2) << "Resolver: qdcount: " << qdcount << " ancount: " << ancount << " nscount: " << nscount << " arcount: " << arcount;
    248 
    249 		for (unsigned i = 0; i < qdcount; ++i)
    250 			this->questions.push_back(this->UnpackQuestion(input, len, packet_pos));
    251 
    252 		for (unsigned i = 0; i < ancount; ++i)
    253 			this->answers.push_back(this->UnpackResourceRecord(input, len, packet_pos));
    254 
    255 		try
    256 		{
    257 			for (unsigned i = 0; i < nscount; ++i)
    258 				this->authorities.push_back(this->UnpackResourceRecord(input, len, packet_pos));
    259 
    260 			for (unsigned i = 0; i < arcount; ++i)
    261 				this->additional.push_back(this->UnpackResourceRecord(input, len, packet_pos));
    262 		}
    263 		catch (const SocketException &ex)
    264 		{
    265 			Log(LOG_DEBUG_2) << "Unable to parse ns/ar records: " << ex.GetReason();
    266 		}
    267 	}
    268 
    269 	unsigned short Pack(unsigned char *output, unsigned short output_size)
    270 	{
    271 		if (output_size < HEADER_LENGTH)
    272 			throw SocketException("Unable to pack packet");
    273 
    274 		unsigned short pos = 0;
    275 
    276 		output[pos++] = this->id >> 8;
    277 		output[pos++] = this->id & 0xFF;
    278 		output[pos++] = this->flags >> 8;
    279 		output[pos++] = this->flags & 0xFF;
    280 		output[pos++] = this->questions.size() >> 8;
    281 		output[pos++] = this->questions.size() & 0xFF;
    282 		output[pos++] = this->answers.size() >> 8;
    283 		output[pos++] = this->answers.size() & 0xFF;
    284 		output[pos++] = this->authorities.size() >> 8;
    285 		output[pos++] = this->authorities.size() & 0xFF;
    286 		output[pos++] = this->additional.size() >> 8;
    287 		output[pos++] = this->additional.size() & 0xFF;
    288 
    289 		for (unsigned i = 0; i < this->questions.size(); ++i)
    290 		{
    291 			Question &q = this->questions[i];
    292 
    293 			if (q.type == QUERY_PTR)
    294 			{
    295 				sockaddrs ip(q.name);
    296 				if (!ip.valid())
    297 					throw SocketException("Invalid IP");
    298 
    299 				switch (ip.family())
    300 				{
    301 					case AF_INET6:
    302 						q.name = ip.reverse() + ".ip6.arpa";
    303 						break;
    304 					case AF_INET:
    305 						q.name = ip.reverse() + ".in-addr.arpa";
    306 						break;
    307 					default:
    308 						throw SocketException("Unsupported IP Family");
    309 				}
    310 			}
    311 
    312 			this->PackName(output, output_size, pos, q.name);
    313 
    314 			if (pos + 4 >= output_size)
    315 				throw SocketException("Unable to pack packet");
    316 
    317 			short s = htons(q.type);
    318 			memcpy(&output[pos], &s, 2);
    319 			pos += 2;
    320 
    321 			s = htons(q.qclass);
    322 			memcpy(&output[pos], &s, 2);
    323 			pos += 2;
    324 		}
    325 
    326 		std::vector<ResourceRecord> types[] = { this->answers, this->authorities, this->additional };
    327 		for (int i = 0; i < 3; ++i)
    328 			for (unsigned j = 0; j < types[i].size(); ++j)
    329 			{
    330 				ResourceRecord &rr = types[i][j];
    331 
    332 				this->PackName(output, output_size, pos, rr.name);
    333 
    334 				if (pos + 8 >= output_size)
    335 					throw SocketException("Unable to pack packet");
    336 
    337 				short s = htons(rr.type);
    338 				memcpy(&output[pos], &s, 2);
    339 				pos += 2;
    340 
    341 				s = htons(rr.qclass);
    342 				memcpy(&output[pos], &s, 2);
    343 				pos += 2;
    344 
    345 				long l = htonl(rr.ttl);
    346 				memcpy(&output[pos], &l, 4);
    347 				pos += 4;
    348 
    349 				switch (rr.type)
    350 				{
    351 					case QUERY_A:
    352 					{
    353 						if (pos + 6 > output_size)
    354 							throw SocketException("Unable to pack packet");
    355 
    356 						sockaddrs a(rr.rdata);
    357 						if (!a.valid())
    358 							throw SocketException("Invalid IP");
    359 
    360 						s = htons(4);
    361 						memcpy(&output[pos], &s, 2);
    362 						pos += 2;
    363 
    364 						memcpy(&output[pos], &a.sa4.sin_addr, 4);
    365 						pos += 4;
    366 						break;
    367 					}
    368 					case QUERY_AAAA:
    369 					{
    370 						if (pos + 18 > output_size)
    371 							throw SocketException("Unable to pack packet");
    372 
    373 						sockaddrs a(rr.rdata);
    374 						if (!a.valid())
    375 							throw SocketException("Invalid IP");
    376 
    377 						s = htons(16);
    378 						memcpy(&output[pos], &s, 2);
    379 						pos += 2;
    380 
    381 						memcpy(&output[pos], &a.sa6.sin6_addr, 16);
    382 						pos += 16;
    383 						break;
    384 					}
    385 					case QUERY_NS:
    386 					case QUERY_CNAME:
    387 					case QUERY_PTR:
    388 					{
    389 						if (pos + 2 >= output_size)
    390 							throw SocketException("Unable to pack packet");
    391 
    392 						unsigned short packet_pos_save = pos;
    393 						pos += 2;
    394 
    395 						this->PackName(output, output_size, pos, rr.rdata);
    396 
    397 						s = htons(pos - packet_pos_save - 2);
    398 						memcpy(&output[packet_pos_save], &s, 2);
    399 						break;
    400 					}
    401 					case QUERY_SOA:
    402 					{
    403 						if (pos + 2 >= output_size)
    404 							throw SocketException("Unable to pack packet");
    405 
    406 						unsigned short packet_pos_save = pos;
    407 						pos += 2;
    408 
    409 						std::vector<Anope::string> ns;
    410 						spacesepstream(nameservers).GetTokens(ns);
    411 						this->PackName(output, output_size, pos, !ns.empty() ? ns[0] : "");
    412 						this->PackName(output, output_size, pos, admin.replace_all_cs('@', '.'));
    413 
    414 						if (pos + 20 >= output_size)
    415 							throw SocketException("Unable to pack SOA");
    416 
    417 						l = htonl(manager->GetSerial());
    418 						memcpy(&output[pos], &l, 4);
    419 						pos += 4;
    420 
    421 						l = htonl(refresh); // Refresh
    422 						memcpy(&output[pos], &l, 4);
    423 						pos += 4;
    424 
    425 						l = htonl(refresh); // Retry
    426 						memcpy(&output[pos], &l, 4);
    427 						pos += 4;
    428 
    429 						l = htonl(604800); // Expire
    430 						memcpy(&output[pos], &l, 4);
    431 						pos += 4;
    432 
    433 						l = htonl(0); // Minimum
    434 						memcpy(&output[pos], &l, 4);
    435 						pos += 4;
    436 
    437 						s = htons(pos - packet_pos_save - 2);
    438 						memcpy(&output[packet_pos_save], &s, 2);
    439 
    440 						break;
    441 					}
    442 					default:
    443 						break;
    444 				}
    445 			}
    446 
    447 		return pos;
    448 	}
    449 };
    450 
    451 namespace DNS
    452 {
    453 	class ReplySocket : public virtual Socket
    454 	{
    455 	 public:
    456 		virtual ~ReplySocket() { }
    457 		virtual void Reply(Packet *p) = 0;
    458 	};
    459 }
    460 
    461 /* Listens for TCP requests */
    462 class TCPSocket : public ListenSocket
    463 {
    464 	Manager *manager;
    465 
    466  public:
    467 	/* A TCP client */
    468 	class Client : public ClientSocket, public Timer, public ReplySocket
    469 	{
    470 		Manager *manager;
    471 		Packet *packet;
    472 		unsigned char packet_buffer[524];
    473 		int length;
    474 
    475 	 public:
    476 		Client(Manager *m, TCPSocket *l, int fd, const sockaddrs &addr) : Socket(fd, l->IsIPv6()), ClientSocket(l, addr), Timer(5),
    477 			manager(m), packet(NULL), length(0)
    478 		{
    479 			Log(LOG_DEBUG_2) << "Resolver: New client from " << addr.addr();
    480 		}
    481 
    482 		~Client()
    483 		{
    484 			Log(LOG_DEBUG_2) << "Resolver: Exiting client from " << clientaddr.addr();
    485 			delete packet;
    486 		}
    487 
    488 		/* Times out after a few seconds */
    489 		void Tick(time_t) anope_override { }
    490 
    491 		void Reply(Packet *p) anope_override
    492 		{
    493 			delete packet;
    494 			packet = p;
    495 			SocketEngine::Change(this, true, SF_WRITABLE);
    496 		}
    497 
    498 		bool ProcessRead() anope_override
    499 		{
    500 			Log(LOG_DEBUG_2) << "Resolver: Reading from DNS TCP socket";
    501 
    502 			int i = recv(this->GetFD(), reinterpret_cast<char *>(packet_buffer) + length, sizeof(packet_buffer) - length, 0);
    503 			if (i <= 0)
    504 				return false;
    505 
    506 			length += i;
    507 
    508 			unsigned short want_len = packet_buffer[0] << 8 | packet_buffer[1];
    509 			if (length >= want_len + 2)
    510 			{
    511 				int len = length - 2;
    512 				length -= want_len + 2;
    513 				return this->manager->HandlePacket(this, packet_buffer + 2, len, NULL);
    514 			}
    515 			return true;
    516 		}
    517 
    518 		bool ProcessWrite() anope_override
    519 		{
    520 			Log(LOG_DEBUG_2) << "Resolver: Writing to DNS TCP socket";
    521 
    522 			if (packet != NULL)
    523 			{
    524 				try
    525 				{
    526 					unsigned char buffer[65535];
    527 					unsigned short len = packet->Pack(buffer + 2, sizeof(buffer) - 2);
    528 
    529 					short s = htons(len);
    530 					memcpy(buffer, &s, 2);
    531 					len += 2;
    532 
    533 					send(this->GetFD(), reinterpret_cast<char *>(buffer), len, 0);
    534 				}
    535 				catch (const SocketException &) { }
    536 
    537 				delete packet;
    538 				packet = NULL;
    539 			}
    540 
    541 			SocketEngine::Change(this, false, SF_WRITABLE);
    542 			return true; /* Do not return false here, bind is unhappy we close the connection so soon after sending */
    543 		}
    544 	};
    545 
    546 	TCPSocket(Manager *m, const Anope::string &ip, int port) : Socket(-1, ip.find(':') != Anope::string::npos), ListenSocket(ip, port, ip.find(':') != Anope::string::npos), manager(m) { }
    547 
    548 	ClientSocket *OnAccept(int fd, const sockaddrs &addr) anope_override
    549 	{
    550 		return new Client(this->manager, this, fd, addr);
    551 	}
    552 };
    553 
    554 /* Listens for UDP requests */
    555 class UDPSocket : public ReplySocket
    556 {
    557 	Manager *manager;
    558 	std::deque<Packet *> packets;
    559 
    560  public:
    561 	UDPSocket(Manager *m, const Anope::string &ip, int port) : Socket(-1, ip.find(':') != Anope::string::npos, SOCK_DGRAM), manager(m) { }
    562 
    563 	~UDPSocket()
    564 	{
    565 		for (unsigned i = 0; i < packets.size(); ++i)
    566 			delete packets[i];
    567 	}
    568 
    569 	void Reply(Packet *p) anope_override
    570 	{
    571 		packets.push_back(p);
    572 		SocketEngine::Change(this, true, SF_WRITABLE);
    573 	}
    574 
    575 	std::deque<Packet *>& GetPackets() { return packets; }
    576 
    577 	bool ProcessRead() anope_override
    578 	{
    579 		Log(LOG_DEBUG_2) << "Resolver: Reading from DNS UDP socket";
    580 
    581 		unsigned char packet_buffer[524];
    582 		sockaddrs from_server;
    583 		socklen_t x = sizeof(from_server);
    584 		int length = recvfrom(this->GetFD(), reinterpret_cast<char *>(&packet_buffer), sizeof(packet_buffer), 0, &from_server.sa, &x);
    585 		return this->manager->HandlePacket(this, packet_buffer, length, &from_server);
    586 	}
    587 
    588 	bool ProcessWrite() anope_override
    589 	{
    590 		Log(LOG_DEBUG_2) << "Resolver: Writing to DNS UDP socket";
    591 
    592 		Packet *r = !packets.empty() ? packets.front() : NULL;
    593 		if (r != NULL)
    594 		{
    595 			try
    596 			{
    597 				unsigned char buffer[524];
    598 				unsigned short len = r->Pack(buffer, sizeof(buffer));
    599 
    600 				sendto(this->GetFD(), reinterpret_cast<char *>(buffer), len, 0, &r->addr.sa, r->addr.size());
    601 			}
    602 			catch (const SocketException &) { }
    603 
    604 			delete r;
    605 			packets.pop_front();
    606 		}
    607 
    608 		if (packets.empty())
    609 			SocketEngine::Change(this, false, SF_WRITABLE);
    610 
    611 		return true;
    612 	}
    613 };
    614 
    615 class NotifySocket : public Socket
    616 {
    617 	Packet *packet;
    618  public:
    619 	NotifySocket(bool v6, Packet *p) : Socket(-1, v6, SOCK_DGRAM), packet(p)
    620 	{
    621 		SocketEngine::Change(this, false, SF_READABLE);
    622 		SocketEngine::Change(this, true, SF_WRITABLE);
    623 	}
    624 
    625 	bool ProcessWrite() anope_override
    626 	{
    627 		if (!packet)
    628 			return false;
    629 
    630 		Log(LOG_DEBUG_2) << "Resolver: Notifying slave " << packet->addr.addr();
    631 
    632 		try
    633 		{
    634 			unsigned char buffer[524];
    635 			unsigned short len = packet->Pack(buffer, sizeof(buffer));
    636 
    637 			sendto(this->GetFD(), reinterpret_cast<char *>(buffer), len, 0, &packet->addr.sa, packet->addr.size());
    638 		}
    639 		catch (const SocketException &) { }
    640 
    641 		delete packet;
    642 		packet = NULL;
    643 
    644 		return false;
    645 	}
    646 };
    647 
    648 class MyManager : public Manager, public Timer
    649 {
    650 	uint32_t serial;
    651 
    652 	typedef TR1NS::unordered_map<Question, Query, Question::hash> cache_map;
    653 	cache_map cache;
    654 
    655 	TCPSocket *tcpsock;
    656 	UDPSocket *udpsock;
    657 
    658 	bool listen;
    659 	sockaddrs addrs;
    660 
    661 	std::vector<std::pair<Anope::string, short> > notify;
    662  public:
    663 	std::map<unsigned short, Request *> requests;
    664 
    665 	MyManager(Module *creator) : Manager(creator), Timer(300, Anope::CurTime, true), serial(Anope::CurTime), tcpsock(NULL), udpsock(NULL),
    666 		listen(false), cur_id(rand())
    667 	{
    668 	}
    669 
    670 	~MyManager()
    671 	{
    672 		delete udpsock;
    673 		delete tcpsock;
    674 
    675 		for (std::map<unsigned short, Request *>::iterator it = this->requests.begin(), it_end = this->requests.end(); it != it_end;)
    676 		{
    677 			Request *request = it->second;
    678 			++it;
    679 
    680 			Query rr(*request);
    681 			rr.error = ERROR_UNKNOWN;
    682 			request->OnError(&rr);
    683 
    684 			delete request;
    685 		}
    686 		this->requests.clear();
    687 
    688 		this->cache.clear();
    689 	}
    690 
    691 	void SetIPPort(const Anope::string &nameserver, const Anope::string &ip, unsigned short port, std::vector<std::pair<Anope::string, short> > n)
    692 	{
    693 		delete udpsock;
    694 		delete tcpsock;
    695 
    696 		udpsock = NULL;
    697 		tcpsock = NULL;
    698 
    699 		try
    700 		{
    701 			this->addrs.pton(nameserver.find(':') != Anope::string::npos ? AF_INET6 : AF_INET, nameserver, 53);
    702 
    703 			udpsock = new UDPSocket(this, ip, port);
    704 
    705 			if (!ip.empty())
    706 			{
    707 				udpsock->Bind(ip, port);
    708 				tcpsock = new TCPSocket(this, ip, port);
    709 				listen = true;
    710 			}
    711 		}
    712 		catch (const SocketException &ex)
    713 		{
    714 			Log() << "Unable to bind dns to " << ip << ":" << port << ": " << ex.GetReason();
    715 		}
    716 
    717 		notify = n;
    718 	}
    719 
    720  private:
    721 	unsigned short cur_id;
    722 
    723 	unsigned short GetID()
    724 	{
    725 		if (this->udpsock->GetPackets().size() == 65535)
    726 			throw SocketException("DNS queue full");
    727 
    728 		do
    729 			cur_id = (cur_id + 1) & 0xFFFF;
    730 		while (!cur_id || this->requests.count(cur_id));
    731 
    732 		return cur_id;
    733 	}
    734 
    735  public:
    736 	void Process(Request *req) anope_override
    737 	{
    738 		Log(LOG_DEBUG_2) << "Resolver: Processing request to lookup " << req->name << ", of type " << req->type;
    739 
    740 		if (req->use_cache && this->CheckCache(req))
    741 		{
    742 			Log(LOG_DEBUG_2) << "Resolver: Using cached result";
    743 			delete req;
    744 			return;
    745 		}
    746 
    747 		if (!this->udpsock)
    748 			throw SocketException("No dns socket");
    749 
    750 		req->id = GetID();
    751 		this->requests[req->id] = req;
    752 
    753 		req->SetSecs(timeout);
    754 
    755 		Packet *p = new Packet(this, &this->addrs);
    756 		p->flags = QUERYFLAGS_RD;
    757 		p->id = req->id;
    758 		p->questions.push_back(*req);
    759 
    760 		this->udpsock->Reply(p);
    761 	}
    762 
    763 	void RemoveRequest(Request *req) anope_override
    764 	{
    765 		this->requests.erase(req->id);
    766 	}
    767 
    768 	bool HandlePacket(ReplySocket *s, const unsigned char *const packet_buffer, int length, sockaddrs *from) anope_override
    769 	{
    770 		if (length < Packet::HEADER_LENGTH)
    771 			return true;
    772 
    773 		Packet recv_packet(this, from);
    774 
    775 		try
    776 		{
    777 			recv_packet.Fill(packet_buffer, length);
    778 		}
    779 		catch (const SocketException &ex)
    780 		{
    781 			Log(LOG_DEBUG_2) << ex.GetReason();
    782 			return true;
    783 		}
    784 
    785 		if (!(recv_packet.flags & QUERYFLAGS_QR))
    786 		{
    787 			if (!listen)
    788 				return true;
    789 			else if (recv_packet.questions.empty())
    790 			{
    791 				Log(LOG_DEBUG_2) << "Resolver: Received a question with no questions?";
    792 				return true;
    793 			}
    794 
    795 			Packet *packet = new Packet(recv_packet);
    796 			packet->flags |= QUERYFLAGS_QR; /* This is a response */
    797 			packet->flags |= QUERYFLAGS_AA; /* And we are authoritative */
    798 
    799 			packet->answers.clear();
    800 			packet->authorities.clear();
    801 			packet->additional.clear();
    802 
    803 			for (unsigned i = 0; i < recv_packet.questions.size(); ++i)
    804 			{
    805 				const Question& q = recv_packet.questions[i];
    806 
    807 				if (q.type == QUERY_AXFR || q.type == QUERY_SOA)
    808 				{
    809 					ResourceRecord rr(q.name, QUERY_SOA);
    810 					packet->answers.push_back(rr);
    811 
    812 					if (q.type == QUERY_AXFR)
    813 					{
    814 						Anope::string token;
    815 						spacesepstream sep(nameservers);
    816 						while (sep.GetToken(token))
    817 						{
    818 							ResourceRecord rr2(q.name, QUERY_NS);
    819 							rr2.rdata = token;
    820 							packet->answers.push_back(rr2);
    821 						}
    822 					}
    823 					break;
    824 				}
    825 			}
    826 
    827 			FOREACH_MOD(OnDnsRequest, (recv_packet, packet));
    828 
    829 			for (unsigned i = 0; i < recv_packet.questions.size(); ++i)
    830 			{
    831 				const Question& q = recv_packet.questions[i];
    832 
    833 				if (q.type == QUERY_AXFR)
    834 				{
    835 					ResourceRecord rr(q.name, QUERY_SOA);
    836 					packet->answers.push_back(rr);
    837 					break;
    838 				}
    839 			}
    840 
    841 			if (packet->answers.empty() && packet->authorities.empty() && packet->additional.empty() && packet->error == ERROR_NONE)
    842 				packet->error = ERROR_REFUSED; // usually safe, won't cause an NXDOMAIN to get cached
    843 
    844 			s->Reply(packet);
    845 			return true;
    846 		}
    847 
    848 		if (from == NULL)
    849 		{
    850 			Log(LOG_DEBUG_2) << "Resolver: Received an answer over TCP. This is not supported.";
    851 			return true;
    852 		}
    853 		else if (this->addrs != *from)
    854 		{
    855 			Log(LOG_DEBUG_2) << "Resolver: Received an answer from the wrong nameserver, Bad NAT or DNS forging attempt? '" << this->addrs.addr() << "' != '" << from->addr() << "'";
    856 			return true;
    857 		}
    858 
    859 		std::map<unsigned short, Request *>::iterator it = this->requests.find(recv_packet.id);
    860 		if (it == this->requests.end())
    861 		{
    862 			Log(LOG_DEBUG_2) << "Resolver: Received an answer for something we didn't request";
    863 			return true;
    864 		}
    865 		Request *request = it->second;
    866 
    867 		if (recv_packet.flags & QUERYFLAGS_OPCODE)
    868 		{
    869 			Log(LOG_DEBUG_2) << "Resolver: Received a nonstandard query";
    870 			recv_packet.error = ERROR_NONSTANDARD_QUERY;
    871 			request->OnError(&recv_packet);
    872 		}
    873 		else if (recv_packet.flags & QUERYFLAGS_RCODE)
    874 		{
    875 			Error error = ERROR_UNKNOWN;
    876 
    877 			switch (recv_packet.flags & QUERYFLAGS_RCODE)
    878 			{
    879 				case 1:
    880 					Log(LOG_DEBUG_2) << "Resolver: format error";
    881 					error = ERROR_FORMAT_ERROR;
    882 					break;
    883 				case 2:
    884 					Log(LOG_DEBUG_2) << "Resolver: server error";
    885 					error = ERROR_SERVER_FAILURE;
    886 					break;
    887 				case 3:
    888 					Log(LOG_DEBUG_2) << "Resolver: domain not found";
    889 					error = ERROR_DOMAIN_NOT_FOUND;
    890 					break;
    891 				case 4:
    892 					Log(LOG_DEBUG_2) << "Resolver: not implemented";
    893 					error = ERROR_NOT_IMPLEMENTED;
    894 					break;
    895 				case 5:
    896 					Log(LOG_DEBUG_2) << "Resolver: refused";
    897 					error = ERROR_REFUSED;
    898 					break;
    899 				default:
    900 					break;
    901 			}
    902 
    903 			recv_packet.error = error;
    904 			request->OnError(&recv_packet);
    905 		}
    906 		else if (recv_packet.questions.empty() || recv_packet.answers.empty())
    907 		{
    908 			Log(LOG_DEBUG_2) << "Resolver: No resource records returned";
    909 			recv_packet.error = ERROR_NO_RECORDS;
    910 			request->OnError(&recv_packet);
    911 		}
    912 		else
    913 		{
    914 			Log(LOG_DEBUG_2) << "Resolver: Lookup complete for " << request->name;
    915 			request->OnLookupComplete(&recv_packet);
    916 			this->AddCache(recv_packet);
    917 		}
    918 
    919 		delete request;
    920 		return true;
    921 	}
    922 
    923 	void UpdateSerial() anope_override
    924 	{
    925 		serial = Anope::CurTime;
    926 	}
    927 
    928 	void Notify(const Anope::string &zone) anope_override
    929 	{
    930 		/* notify slaves of the update */
    931 		for (unsigned i = 0; i < notify.size(); ++i)
    932 		{
    933 			const Anope::string &ip = notify[i].first;
    934 			short port = notify[i].second;
    935 
    936 			sockaddrs addr;
    937 			addr.pton(ip.find(':') != Anope::string::npos ? AF_INET6 : AF_INET, ip, port);
    938 			if (!addr.valid())
    939 				return;
    940 
    941 			Packet *packet = new Packet(this, &addr);
    942 			packet->flags = QUERYFLAGS_AA | QUERYFLAGS_OPCODE_NOTIFY;
    943 			try
    944 			{
    945 				packet->id = GetID();
    946 			}
    947 			catch (const SocketException &)
    948 			{
    949 				delete packet;
    950 				continue;
    951 			}
    952 
    953 			packet->questions.push_back(Question(zone, QUERY_SOA));
    954 
    955 			new NotifySocket(ip.find(':') != Anope::string::npos, packet);
    956 		}
    957 	}
    958 
    959 	uint32_t GetSerial() const anope_override
    960 	{
    961 		return serial;
    962 	}
    963 
    964 	void Tick(time_t now) anope_override
    965 	{
    966 		Log(LOG_DEBUG_2) << "Resolver: Purging DNS cache";
    967 
    968 		for (cache_map::iterator it = this->cache.begin(), it_next; it != this->cache.end(); it = it_next)
    969 		{
    970 			const Query &q = it->second;
    971 			const ResourceRecord &req = q.answers[0];
    972 			it_next = it;
    973 			++it_next;
    974 
    975 			if (req.created + static_cast<time_t>(req.ttl) < now)
    976 				this->cache.erase(it);
    977 		}
    978 	}
    979 
    980  private:
    981 	/** Add a record to the dns cache
    982 	 * @param r The record
    983 	 */
    984 	void AddCache(Query &r)
    985 	{
    986 		const ResourceRecord &rr = r.answers[0];
    987 		Log(LOG_DEBUG_3) << "Resolver cache: added cache for " << rr.name << " -> " << rr.rdata << ", ttl: " << rr.ttl;
    988 		this->cache[r.questions[0]] = r;
    989 	}
    990 
    991 	/** Check the DNS cache to see if request can be handled by a cached result
    992 	 * @return true if a cached result was found.
    993 	 */
    994 	bool CheckCache(Request *request)
    995 	{
    996 		cache_map::iterator it = this->cache.find(*request);
    997 		if (it != this->cache.end())
    998 		{
    999 			Query &record = it->second;
   1000 			Log(LOG_DEBUG_3) << "Resolver: Using cached result for " << request->name;
   1001 			request->OnLookupComplete(&record);
   1002 			return true;
   1003 		}
   1004 
   1005 		return false;
   1006 	}
   1007 
   1008 };
   1009 
   1010 class ModuleDNS : public Module
   1011 {
   1012 	MyManager manager;
   1013 
   1014 	Anope::string nameserver;
   1015 	Anope::string ip;
   1016 	int port;
   1017 
   1018 	std::vector<std::pair<Anope::string, short> > notify;
   1019 
   1020  public:
   1021 	ModuleDNS(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, EXTRA | VENDOR), manager(this)
   1022 	{
   1023 
   1024 	}
   1025 
   1026 	~ModuleDNS()
   1027 	{
   1028 		for (std::map<int, Socket *>::const_iterator it = SocketEngine::Sockets.begin(), it_end = SocketEngine::Sockets.end(); it != it_end;)
   1029 		{
   1030 			Socket *s = it->second;
   1031 			++it;
   1032 
   1033 			if (dynamic_cast<NotifySocket *>(s) || dynamic_cast<TCPSocket::Client *>(s))
   1034 				delete s;
   1035 		}
   1036 	}
   1037 
   1038 	void OnReload(Configuration::Conf *conf) anope_override
   1039 	{
   1040 		Configuration::Block *block = conf->GetModule(this);
   1041 
   1042 		nameserver = block->Get<const Anope::string>("nameserver", "127.0.0.1");
   1043 		timeout =  block->Get<time_t>("timeout", "5");
   1044 		ip = block->Get<const Anope::string>("ip", "0.0.0.0");
   1045 		port = block->Get<int>("port", "53");
   1046 		admin = block->Get<const Anope::string>("admin", "admin@example.com");
   1047 		nameservers = block->Get<const Anope::string>("nameservers", "ns1.example.com");
   1048 		refresh = block->Get<int>("refresh", "3600");
   1049 
   1050 		for (int i = 0; i < block->CountBlock("notify"); ++i)
   1051 		{
   1052 			Configuration::Block *n = block->GetBlock("notify", i);
   1053 			Anope::string nip = n->Get<Anope::string>("ip");
   1054 			short nport = n->Get<short>("port");
   1055 
   1056 			notify.push_back(std::make_pair(nip, nport));
   1057 		}
   1058 
   1059 		if (Anope::IsFile(nameserver))
   1060 		{
   1061 			std::ifstream f(nameserver.c_str());
   1062 			bool success = false;
   1063 
   1064 			if (f.is_open())
   1065 			{
   1066 				for (Anope::string server; std::getline(f, server.str());)
   1067 				{
   1068 					if (server.find("nameserver") == 0)
   1069 					{
   1070 						size_t i = server.find_first_of("123456789");
   1071 						if (i != Anope::string::npos)
   1072 						{
   1073 							if (server.substr(i).is_pos_number_only())
   1074 							{
   1075 								nameserver = server.substr(i);
   1076 								Log(LOG_DEBUG) << "Nameserver set to " << nameserver;
   1077 								success = true;
   1078 								break;
   1079 							}
   1080 						}
   1081 					}
   1082 				}
   1083 
   1084 				f.close();
   1085 			}
   1086 
   1087 			if (!success)
   1088 			{
   1089 				Log() << "Unable to find nameserver, defaulting to 127.0.0.1";
   1090 				nameserver = "127.0.0.1";
   1091 			}
   1092 		}
   1093 
   1094 		try
   1095 		{
   1096 			this->manager.SetIPPort(nameserver, ip, port, notify);
   1097 		}
   1098 		catch (const SocketException &ex)
   1099 		{
   1100 			throw ModuleException(ex.GetReason());
   1101 		}
   1102 	}
   1103 
   1104 	void OnModuleUnload(User *u, Module *m) anope_override
   1105 	{
   1106 		for (std::map<unsigned short, Request *>::iterator it = this->manager.requests.begin(), it_end = this->manager.requests.end(); it != it_end;)
   1107 		{
   1108 			unsigned short id = it->first;
   1109 			Request *req = it->second;
   1110 			++it;
   1111 
   1112 			if (req->creator == m)
   1113 			{
   1114 				Query rr(*req);
   1115 				rr.error = ERROR_UNLOADED;
   1116 				req->OnError(&rr);
   1117 
   1118 				delete req;
   1119 				this->manager.requests.erase(id);
   1120 			}
   1121 		}
   1122 	}
   1123 };
   1124 
   1125 MODULE_INIT(ModuleDNS)