diff options
author | Adam <Adam@anope.org> | 2012-12-15 01:33:31 -0500 |
---|---|---|
committer | Adam <Adam@anope.org> | 2012-12-15 01:33:31 -0500 |
commit | dcd34d37287adb6aa03d32edd17fc8015b52feb8 (patch) | |
tree | 4eb963bc60c8db543973456e7fce35aaae5a4ad4 /src | |
parent | cdec0a3f96bbfa6d5300b7a6d602fd170e7ccd56 (diff) |
Move DNS handling to a module
Diffstat (limited to 'src')
-rw-r--r-- | src/config.cpp | 44 | ||||
-rw-r--r-- | src/dns.cpp | 963 | ||||
-rw-r--r-- | src/misc.cpp | 31 | ||||
-rw-r--r-- | src/module.cpp | 4 | ||||
-rw-r--r-- | src/uplink.cpp | 8 |
5 files changed, 35 insertions, 1015 deletions
diff --git a/src/config.cpp b/src/config.cpp index 8969569fd..79ebce9f3 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -17,7 +17,6 @@ #include "opertype.h" #include "channels.h" #include "hashcomp.h" -#include "dns.h" #ifndef _WIN32 #include <errno.h> @@ -175,42 +174,6 @@ ServerConfig::ServerConfig() ModeManager::UpdateDefaultMLock(this); - if (IsFile(this->NameServer)) - { - std::ifstream f(this->NameServer.c_str()); - Anope::string server; - bool success = false; - - while (f.is_open() && getline(f, server.str())) - { - if (server.find("nameserver") == 0) - { - size_t ip = server.find_first_of("123456789"); - if (ip != Anope::string::npos) - { - if (server.substr(ip).is_pos_number_only()) - { - this->NameServer = server.substr(ip); - Log(LOG_DEBUG) << "Nameserver set to " << this->NameServer; - success = true; - break; - } - } - } - } - - if (f.is_open()) - f.close(); - - if (!success) - { - Log() << "Unable to find nameserver, defaulting to 127.0.0.1"; - this->NameServer = "127.0.0.1"; - } - } - delete DNS::Engine; - DNS::Engine = new DNS::Manager(this->NameServer, this->DNSIP, this->DNSPort); - if (this->CaseMap == "ascii") Anope::casemap = std::locale(std::locale(), new Anope::ascii_ctype<char>()); else if (this->CaseMap == "rfc1459") @@ -1262,13 +1225,6 @@ ConfigItems::ConfigItems(ServerConfig *conf) {"mail", "emailchange_message", "", new ValueContainerString(&conf->MailEmailchangeMessage), DT_STRING | DT_ALLOW_NEWLINE, ValidateMail}, {"mail", "memo_subject", "", new ValueContainerString(&conf->MailMemoSubject), DT_STRING, ValidateMail}, {"mail", "memo_message", "", new ValueContainerString(&conf->MailMemoMessage), DT_STRING | DT_ALLOW_NEWLINE, ValidateMail}, - {"dns", "nameserver", "127.0.0.1", new ValueContainerString(&conf->NameServer), DT_STRING, NoValidation}, - {"dns", "timeout", "5", new ValueContainerTime(&conf->DNSTimeout), DT_TIME, NoValidation}, - {"dns", "ip", "0.0.0.0", new ValueContainerString(&conf->DNSIP), DT_STRING, NoValidation}, - {"dns", "port", "53", new ValueContainerInt(&conf->DNSPort), DT_INTEGER, NoValidation}, - {"dns", "admin", "admin@example.com", new ValueContainerString(&conf->DNSSOAAdmin), DT_STRING, NoValidation}, - {"dns", "nameservers", "ns1.example.com", new ValueContainerString(&conf->DNSSOANS), DT_STRING, NoValidation}, - {"dns", "refresh", "3600", new ValueContainerUInt(&conf->DNSSOARefresh), DT_UINTEGER, NoValidation}, {"chanserv", "name", "", new ValueContainerString(&conf->ChanServ), DT_STRING, NoValidation}, {"chanserv", "defaults", "keeptopic secure securefounder signkick", new ValueContainerString(&CSDefaults), DT_STRING, ValidateChanServ}, {"chanserv", "maxregistered", "0", new ValueContainerUInt(&conf->CSMaxReg), DT_UINTEGER, ValidateChanServ}, diff --git a/src/dns.cpp b/src/dns.cpp deleted file mode 100644 index ccb919a31..000000000 --- a/src/dns.cpp +++ /dev/null @@ -1,963 +0,0 @@ -/* - * - * (C) 2003-2012 Anope Team - * Contact us at team@anope.org - * - * Please read COPYING and README for further details. - * - * Based on the original code of Epona by Lara. - * Based on the original code of Services by Andy Church. - * - */ - -#include "services.h" -#include "anope.h" -#include "dns.h" -#include "sockets.h" -#include "socketengine.h" - -#ifndef _WIN32 -#include <sys/types.h> -#include <sys/socket.h> -#include <netdb.h> -#endif - -using namespace DNS; - -Manager *DNS::Engine = NULL; - -Question::Question() -{ - this->type = QUERY_NONE; - this->qclass = 0; -} - -Question::Question(const Anope::string &n, QueryType t, unsigned short q) : name(n), type(t), qclass(q) -{ -} - -ResourceRecord::ResourceRecord(const Anope::string &n, QueryType t, unsigned short q) : Question(n, t, q) -{ - this->ttl = 0; - this->created = Anope::CurTime; -} - -ResourceRecord::ResourceRecord(const Question &q) : Question(q) -{ - this->ttl = 0; - this->created = Anope::CurTime; -} - -Query::Query() -{ - this->error = ERROR_NONE; -} - -Query::Query(const Question &q) -{ - this->questions.push_back(q); - this->error = ERROR_NONE; -} - -Request::Request(const Anope::string &addr, QueryType qt, bool cache, Module *c) : Timer(Config->DNSTimeout), Question(addr, qt), use_cache(cache), id(0), creator(c) -{ - if (!DNS::Engine || !DNS::Engine->udpsock) - throw SocketException("No DNS::Engine"); - if (DNS::Engine->udpsock->GetPackets().size() == 65535) - throw SocketException("DNS queue full"); - - do - { - static unsigned short cur_id = rand(); - this->id = cur_id++; - } - while (DNS::Engine->requests.count(this->id)); - - DNS::Engine->requests[this->id] = this; -} - -Request::~Request() -{ - DNS::Engine->requests.erase(this->id); -} - -void Request::Process() -{ - Log(LOG_DEBUG_2) << "Resolver: Processing request to lookup " << this->name << ", of type " << this->type; - - if (!DNS::Engine || !DNS::Engine->udpsock) - throw SocketException("DNS::Engine has not been initialized"); - - if (this->use_cache && DNS::Engine->CheckCache(this)) - { - Log(LOG_DEBUG_2) << "Resolver: Using cached result"; - delete this; - return; - } - - Packet *p = new Packet(&DNS::Engine->addrs); - p->flags = QUERYFLAGS_RD; - - p->id = this->id; - p->questions.push_back(*this); - DNS::Engine->udpsock->Reply(p); -} - -void Request::OnError(const Query *r) -{ -} - -void Request::Tick(time_t) -{ - Log(LOG_DEBUG_2) << "Resolver: timeout for query " << this->name; - Query rr(*this); - rr.error = ERROR_TIMEOUT; - this->OnError(&rr); -} - -void Packet::PackName(unsigned char *output, unsigned short output_size, unsigned short &pos, const Anope::string &name) -{ - if (name.length() + 2 > output_size) - throw SocketException("Unable to pack name"); - - Log(LOG_DEBUG_2) << "Resolver: PackName packing " << name; - - sepstream sep(name, '.'); - Anope::string token; - - while (sep.GetToken(token)) - { - output[pos++] = token.length(); - memcpy(&output[pos], token.c_str(), token.length()); - pos += token.length(); - } - - output[pos++] = 0; -} - -Anope::string Packet::UnpackName(const unsigned char *input, unsigned short input_size, unsigned short &pos) -{ - Anope::string name; - unsigned short pos_ptr = pos, lowest_ptr = input_size; - bool compressed = false; - - if (pos_ptr >= input_size) - throw SocketException("Unable to unpack name - no input"); - - while (input[pos_ptr] > 0) - { - unsigned short offset = input[pos_ptr]; - - if (offset & POINTER) - { - if ((offset & POINTER) != POINTER) - throw SocketException("Unable to unpack name - bogus compression header"); - if (pos_ptr + 1 >= input_size) - throw SocketException("Unable to unpack name - bogus compression header"); - - /* Place pos at the second byte of the first (farthest) compression pointer */ - if (compressed == false) - { - ++pos; - compressed = true; - } - - pos_ptr = (offset & LABEL) << 8 | input[pos_ptr + 1]; - - /* Pointers can only go back */ - if (pos_ptr >= lowest_ptr) - throw SocketException("Unable to unpack name - bogus compression pointer"); - lowest_ptr = pos_ptr; - } - else - { - if (pos_ptr + offset + 1 >= input_size) - throw SocketException("Unable to unpack name - offset too large"); - if (!name.empty()) - name += "."; - for (unsigned i = 1; i <= offset; ++i) - name += input[pos_ptr + i]; - - pos_ptr += offset + 1; - if (compressed == false) - /* Move up pos */ - pos = pos_ptr; - } - } - - /* +1 pos either to one byte after the compression pointer or one byte after the ending \0 */ - ++pos; - - Log(LOG_DEBUG_2) << "Resolver: UnpackName successfully unpacked " << name; - - return name; -} - -Question Packet::UnpackQuestion(const unsigned char *input, unsigned short input_size, unsigned short &pos) -{ - Question question; - - question.name = this->UnpackName(input, input_size, pos); - - if (pos + 4 > input_size) - throw SocketException("Unable to unpack question"); - - question.type = static_cast<QueryType>(input[pos] << 8 | input[pos + 1]); - pos += 2; - - question.qclass = input[pos] << 8 | input[pos + 1]; - pos += 2; - - return question; -} - -ResourceRecord Packet::UnpackResourceRecord(const unsigned char *input, unsigned short input_size, unsigned short &pos) -{ - ResourceRecord record = static_cast<ResourceRecord>(this->UnpackQuestion(input, input_size, pos)); - - if (pos + 6 > input_size) - throw SocketException("Unable to unpack resource record"); - - record.ttl = (input[pos] << 24) | (input[pos + 1] << 16) | (input[pos + 2] << 8) | input[pos + 3]; - pos += 4; - - //record.rdlength = input[pos] << 8 | input[pos + 1]; - pos += 2; - - switch (record.type) - { - case QUERY_A: - { - if (pos + 4 > input_size) - throw SocketException("Unable to unpack resource record"); - - in_addr a; - a.s_addr = input[pos] | (input[pos + 1] << 8) | (input[pos + 2] << 16) | (input[pos + 3] << 24); - pos += 4; - - sockaddrs addrs; - addrs.ntop(AF_INET, &a); - - record.rdata = addrs.addr(); - break; - } - case QUERY_AAAA: - { - if (pos + 16 > input_size) - throw SocketException("Unable to unpack resource record"); - - in6_addr a; - for (int j = 0; j < 16; ++j) - a.s6_addr[j] = input[pos + j]; - pos += 16; - - sockaddrs addrs; - addrs.ntop(AF_INET6, &a); - - record.rdata = addrs.addr(); - break; - } - case QUERY_CNAME: - case QUERY_PTR: - { - record.rdata = this->UnpackName(input, input_size, pos); - break; - } - default: - break; - } - - Log(LOG_DEBUG_2) << "Resolver: " << record.name << " -> " << record.rdata; - - return record; -} - -Packet::Packet(sockaddrs *a) : Query(), id(0), flags(0) -{ - if (a) - addr = *a; -} - -void Packet::Fill(const unsigned char *input, const unsigned short len) -{ - if (len < Packet::HEADER_LENGTH) - throw SocketException("Unable to fill packet"); - - unsigned short packet_pos = 0; - - this->id = (input[packet_pos] << 8) | input[packet_pos + 1]; - packet_pos += 2; - - this->flags = (input[packet_pos] << 8) | input[packet_pos + 1]; - packet_pos += 2; - - unsigned short qdcount = (input[packet_pos] << 8) | input[packet_pos + 1]; - packet_pos += 2; - - unsigned short ancount = (input[packet_pos] << 8) | input[packet_pos + 1]; - packet_pos += 2; - - unsigned short nscount = (input[packet_pos] << 8) | input[packet_pos + 1]; - packet_pos += 2; - - unsigned short arcount = (input[packet_pos] << 8) | input[packet_pos + 1]; - packet_pos += 2; - - Log(LOG_DEBUG_2) << "Resolver: qdcount: " << qdcount << " ancount: " << ancount << " nscount: " << nscount << " arcount: " << arcount; - - for (unsigned i = 0; i < qdcount; ++i) - this->questions.push_back(this->UnpackQuestion(input, len, packet_pos)); - - for (unsigned i = 0; i < ancount; ++i) - this->answers.push_back(this->UnpackResourceRecord(input, len, packet_pos)); - - for (unsigned i = 0; i < nscount; ++i) - this->authorities.push_back(this->UnpackResourceRecord(input, len, packet_pos)); - - for (unsigned i = 0; i < arcount; ++i) - this->additional.push_back(this->UnpackResourceRecord(input, len, packet_pos)); -} - -unsigned short Packet::Pack(unsigned char *output, unsigned short output_size) -{ - if (output_size < Packet::HEADER_LENGTH) - throw SocketException("Unable to pack packet"); - - unsigned short pos = 0; - - output[pos++] = this->id >> 8; - output[pos++] = this->id & 0xFF; - output[pos++] = this->flags >> 8; - output[pos++] = this->flags & 0xFF; - output[pos++] = this->questions.size() >> 8; - output[pos++] = this->questions.size() & 0xFF; - output[pos++] = this->answers.size() >> 8; - output[pos++] = this->answers.size() & 0xFF; - output[pos++] = this->authorities.size() >> 8; - output[pos++] = this->authorities.size() & 0xFF; - output[pos++] = this->additional.size() >> 8; - output[pos++] = this->additional.size() & 0xFF; - - for (unsigned i = 0; i < this->questions.size(); ++i) - { - Question &q = this->questions[i]; - - if (q.type == QUERY_PTR) - { - sockaddrs ip(q.name); - - if (q.name.find(':') != Anope::string::npos) - { - static const char *const hex = "0123456789abcdef"; - char reverse_ip[128]; - unsigned reverse_ip_count = 0; - for (int j = 15; j >= 0; --j) - { - reverse_ip[reverse_ip_count++] = hex[ip.sa6.sin6_addr.s6_addr[j] & 0xF]; - reverse_ip[reverse_ip_count++] = '.'; - reverse_ip[reverse_ip_count++] = hex[ip.sa6.sin6_addr.s6_addr[j] >> 4]; - reverse_ip[reverse_ip_count++] = '.'; - } - reverse_ip[reverse_ip_count++] = 0; - - q.name = reverse_ip; - q.name += "ip6.arpa"; - } - else - { - unsigned long forward = ip.sa4.sin_addr.s_addr; - in_addr reverse; - reverse.s_addr = forward << 24 | (forward & 0xFF00) << 8 | (forward & 0xFF0000) >> 8 | forward >> 24; - - ip.ntop(AF_INET, &reverse); - - q.name = ip.addr() + ".in-addr.arpa"; - } - } - - this->PackName(output, output_size, pos, q.name); - - if (pos + 4 >= output_size) - throw SocketException("Unable to pack packet"); - - short s = htons(q.type); - memcpy(&output[pos], &s, 2); - pos += 2; - - s = htons(q.qclass); - memcpy(&output[pos], &s, 2); - pos += 2; - } - - std::vector<ResourceRecord> types[] = { this->answers, this->authorities, this->additional }; - for (int i = 0; i < 3; ++i) - for (unsigned j = 0; j < types[i].size(); ++j) - { - ResourceRecord &rr = types[i][j]; - - this->PackName(output, output_size, pos, rr.name); - - if (pos + 8 >= output_size) - throw SocketException("Unable to pack packet"); - - short s = htons(rr.type); - memcpy(&output[pos], &s, 2); - pos += 2; - - s = htons(rr.qclass); - memcpy(&output[pos], &s, 2); - pos += 2; - - long l = htonl(rr.ttl); - memcpy(&output[pos], &l, 4); - pos += 4; - - switch (rr.type) - { - case QUERY_A: - { - if (pos + 6 > output_size) - throw SocketException("Unable to pack packet"); - - sockaddrs a(rr.rdata); - - s = htons(4); - memcpy(&output[pos], &s, 2); - pos += 2; - - memcpy(&output[pos], &a.sa4.sin_addr, 4); - pos += 4; - break; - } - case QUERY_AAAA: - { - if (pos + 18 > output_size) - throw SocketException("Unable to pack packet"); - - sockaddrs a(rr.rdata); - - s = htons(16); - memcpy(&output[pos], &s, 2); - pos += 2; - - memcpy(&output[pos], &a.sa6.sin6_addr, 16); - pos += 16; - break; - } - case QUERY_NS: - case QUERY_CNAME: - case QUERY_PTR: - { - if (pos + 2 >= output_size) - throw SocketException("Unable to pack packet"); - - unsigned short packet_pos_save = pos; - pos += 2; - - this->PackName(output, output_size, pos, rr.rdata); - - s = htons(pos - packet_pos_save - 2); - memcpy(&output[packet_pos_save], &s, 2); - break; - } - case QUERY_SOA: - { - if (pos + 2 >= output_size) - throw SocketException("Unable to pack packet"); - - unsigned short packet_pos_save = pos; - pos += 2; - - std::vector<Anope::string> nameservers; - spacesepstream(Config->DNSSOANS).GetTokens(nameservers); - this->PackName(output, output_size, pos, !nameservers.empty() ? nameservers[0] : ""); - this->PackName(output, output_size, pos, Config->DNSSOAAdmin.replace_all_cs('@', '.')); - - if (pos + 20 >= output_size) - throw SocketException("Unable to pack SOA"); - - l = htonl(DNS::Engine->GetSerial()); - memcpy(&output[pos], &l, 4); - pos += 4; - - l = htonl(Config->DNSSOARefresh); // Refresh - memcpy(&output[pos], &l, 4); - pos += 4; - - l = htonl(Config->DNSSOARefresh); // Retry - memcpy(&output[pos], &l, 4); - pos += 4; - - l = htonl(604800); // Expire - memcpy(&output[pos], &l, 4); - pos += 4; - - l = htonl(0); // Minimum - memcpy(&output[pos], &l, 4); - pos += 4; - - s = htons(pos - packet_pos_save - 2); - memcpy(&output[packet_pos_save], &s, 2); - - break; - } - default: - break; - } - } - - return pos; -} - -Manager::TCPSocket::Client::Client(TCPSocket *l, int fd, const sockaddrs &addr) : Socket(fd, l->IsIPv6()), ClientSocket(l, addr), Timer(5), tcpsock(l), packet(NULL), length(0) -{ - Log(LOG_DEBUG_2) << "Resolver: New client from " << addr.addr(); -} - -Manager::TCPSocket::Client::~Client() -{ - Log(LOG_DEBUG_2) << "Resolver: Exiting client from " << clientaddr.addr(); - delete packet; -} - -void Manager::TCPSocket::Client::Reply(Packet *p) -{ - delete packet; - packet = p; - SocketEngine::Change(this, true, SF_WRITABLE); -} - -bool Manager::TCPSocket::Client::ProcessRead() -{ - Log(LOG_DEBUG_2) << "Resolver: Reading from DNS TCP socket"; - - int i = recv(this->GetFD(), reinterpret_cast<char *>(packet_buffer) + length, sizeof(packet_buffer) - length, 0); - if (i <= 0) - return false; - - length += i; - - unsigned short want_len = packet_buffer[0] << 8 | packet_buffer[1]; - if (length >= want_len + 2) - { - int len = length - 2; - length -= want_len + 2; - return DNS::Engine->HandlePacket(this, packet_buffer + 2, len, NULL); - } - return true; -} - -bool Manager::TCPSocket::Client::ProcessWrite() -{ - Log(LOG_DEBUG_2) << "Resolver: Writing to DNS TCP socket"; - - if (packet != NULL) - { - try - { - unsigned char buffer[65535]; - unsigned short len = packet->Pack(buffer + 2, sizeof(buffer) - 2); - - short s = htons(len); - memcpy(buffer, &s, 2); - len += 2; - - send(this->GetFD(), reinterpret_cast<char *>(buffer), len, 0); - } - catch (const SocketException &) { } - - delete packet; - packet = NULL; - } - - SocketEngine::Change(this, false, SF_WRITABLE); - return true; /* Do not return false here, bind is unhappy we close the connection so soon after sending */ -} - -Manager::TCPSocket::TCPSocket(const Anope::string &ip, int port) : Socket(-1, ip.find(':') != Anope::string::npos), ListenSocket(ip, port, ip.find(':') != Anope::string::npos) -{ -} - -ClientSocket *Manager::TCPSocket::OnAccept(int fd, const sockaddrs &addr) -{ - return new Client(this, fd, addr); -} - -Manager::UDPSocket::UDPSocket(const Anope::string &ip, int port) : Socket(-1, ip.find(':') != Anope::string::npos, SOCK_DGRAM) -{ -} - -Manager::UDPSocket::~UDPSocket() -{ - for (unsigned i = 0; i < packets.size(); ++i) - delete packets[i]; -} - -void Manager::UDPSocket::Reply(Packet *p) -{ - packets.push_back(p); - SocketEngine::Change(this, true, SF_WRITABLE); -} - -bool Manager::UDPSocket::ProcessRead() -{ - Log(LOG_DEBUG_2) << "Resolver: Reading from DNS UDP socket"; - - unsigned char packet_buffer[524]; - sockaddrs from_server; - socklen_t x = sizeof(from_server); - int length = recvfrom(this->GetFD(), reinterpret_cast<char *>(&packet_buffer), sizeof(packet_buffer), 0, &from_server.sa, &x); - return DNS::Engine->HandlePacket(this, packet_buffer, length, &from_server); -} - -bool Manager::UDPSocket::ProcessWrite() -{ - Log(LOG_DEBUG_2) << "Resolver: Writing to DNS UDP socket"; - - Packet *r = !packets.empty() ? packets.front() : NULL; - if (r != NULL) - { - try - { - unsigned char buffer[524]; - unsigned short len = r->Pack(buffer, sizeof(buffer)); - - sendto(this->GetFD(), reinterpret_cast<char *>(buffer), len, 0, &r->addr.sa, r->addr.size()); - } - catch (const SocketException &) { } - - delete r; - packets.pop_front(); - } - - if (packets.empty()) - SocketEngine::Change(this, false, SF_WRITABLE); - - return true; -} - -Manager::Manager(const Anope::string &nameserver, const Anope::string &ip, int port) : Timer(300, Anope::CurTime, true), listen(false), serial(0), tcpsock(NULL), udpsock(NULL) -{ - this->addrs.pton(nameserver.find(':') != Anope::string::npos ? AF_INET6 : AF_INET, nameserver, port); - - try - { - udpsock = new UDPSocket(ip, port); - } - catch (const SocketException &ex) - { - Log() << "Unable to create socket for Manager: " << ex.GetReason(); - } - - try - { - udpsock->Bind(ip, port); - tcpsock = new TCPSocket(ip, port); - listen = true; - } - catch (const SocketException &ex) - { - /* This error can be from normal operation as most people don't use services to handle DNS queries, so put it in debug log */ - Log(LOG_DEBUG) << "Unable to bind Manager to port " << port << ": " << ex.GetReason(); - } - - this->UpdateSerial(); -} - -Manager::~Manager() -{ - delete udpsock; - delete tcpsock; - - for (std::map<unsigned short, Request *>::iterator it = this->requests.begin(), it_end = this->requests.end(); it != it_end; ++it) - { - Request *request = it->second; - - Query rr(*request); - rr.error = ERROR_UNKNOWN; - request->OnError(&rr); - - delete request; - } - this->requests.clear(); - - this->cache.clear(); - - DNS::Engine = NULL; -} - -bool Manager::HandlePacket(ReplySocket *s, const unsigned char *const packet_buffer, int length, sockaddrs *from) -{ - if (length < Packet::HEADER_LENGTH) - return true; - - Packet recv_packet(from); - - try - { - recv_packet.Fill(packet_buffer, length); - } - catch (const SocketException &ex) - { - Log(LOG_DEBUG_2) << ex.GetReason(); - return true; - } - - if (!(recv_packet.flags & QUERYFLAGS_QR)) - { - if (!listen) - return true; - else if (recv_packet.questions.empty()) - { - Log(LOG_DEBUG_2) << "Resolver: Received a question with no questions?"; - return true; - } - - Packet *packet = new Packet(recv_packet); - packet->flags |= QUERYFLAGS_QR; /* This is a reponse */ - packet->flags |= QUERYFLAGS_AA; /* And we are authoritative */ - - packet->answers.clear(); - packet->authorities.clear(); - packet->additional.clear(); - - for (unsigned i = 0; i < recv_packet.questions.size(); ++i) - { - const Question& q = recv_packet.questions[i]; - - if (q.type == QUERY_AXFR || q.type == QUERY_SOA) - { - ResourceRecord rr(q.name, QUERY_SOA); - packet->answers.push_back(rr); - - if (q.type == QUERY_AXFR) - { - Anope::string token; - spacesepstream sep(Config->DNSSOANS); - while (sep.GetToken(token)) - { - ResourceRecord rr2(q.name, QUERY_NS); - rr2.rdata = token; - packet->answers.push_back(rr2); - } - } - break; - } - } - - FOREACH_MOD(I_OnDnsRequest, OnDnsRequest(recv_packet, packet)); - - for (unsigned i = 0; i < recv_packet.questions.size(); ++i) - { - const Question& q = recv_packet.questions[i]; - - if (q.type == QUERY_AXFR) - { - ResourceRecord rr(q.name, QUERY_SOA); - packet->answers.push_back(rr); - break; - } - } - - s->Reply(packet); - return true; - } - - if (from == NULL) - { - Log(LOG_DEBUG_2) << "Resolver: Received an answer over TCP. This is not supported."; - return true; - } - else if (this->addrs != *from) - { - Log(LOG_DEBUG_2) << "Resolver: Received an answer from the wrong nameserver, Bad NAT or DNS forging attempt? '" << this->addrs.addr() << "' != '" << from->addr() << "'"; - return true; - } - - std::map<unsigned short, Request *>::iterator it = DNS::Engine->requests.find(recv_packet.id); - if (it == DNS::Engine->requests.end()) - { - Log(LOG_DEBUG_2) << "Resolver: Received an answer for something we didn't request"; - return true; - } - Request *request = it->second; - - if (recv_packet.flags & QUERYFLAGS_OPCODE) - { - Log(LOG_DEBUG_2) << "Resolver: Received a nonstandard query"; - recv_packet.error = ERROR_NONSTANDARD_QUERY; - request->OnError(&recv_packet); - } - else if (recv_packet.flags & QUERYFLAGS_RCODE) - { - Error error = ERROR_UNKNOWN; - - switch (recv_packet.flags & QUERYFLAGS_RCODE) - { - case 1: - Log(LOG_DEBUG_2) << "Resolver: format error"; - error = ERROR_FORMAT_ERROR; - break; - case 2: - Log(LOG_DEBUG_2) << "Resolver: server error"; - error = ERROR_SERVER_FAILURE; - break; - case 3: - Log(LOG_DEBUG_2) << "Resolver: domain not found"; - error = ERROR_DOMAIN_NOT_FOUND; - break; - case 4: - Log(LOG_DEBUG_2) << "Resolver: not implemented"; - error = ERROR_NOT_IMPLEMENTED; - break; - case 5: - Log(LOG_DEBUG_2) << "Resolver: refused"; - error = ERROR_REFUSED; - break; - default: - break; - } - - recv_packet.error = error; - request->OnError(&recv_packet); - } - else if (recv_packet.answers.empty()) - { - Log(LOG_DEBUG_2) << "Resolver: No resource records returned"; - recv_packet.error = ERROR_NO_RECORDS; - request->OnError(&recv_packet); - } - else - { - Log(LOG_DEBUG_2) << "Resolver: Lookup complete for " << request->name; - request->OnLookupComplete(&recv_packet); - DNS::Engine->AddCache(recv_packet); - } - - delete request; - return true; -} - -void Manager::AddCache(Query &r) -{ - for (unsigned i = 0; i < r.answers.size(); ++i) - { - ResourceRecord &rr = r.answers[i]; - Log(LOG_DEBUG_3) << "Resolver cache: added cache for " << rr.name << " -> " << rr.rdata << ", ttl: " << rr.ttl; - this->cache.insert(std::make_pair(rr.name, rr)); - } -} - -bool Manager::CheckCache(Request *request) -{ - cache_map::iterator it = this->cache.find(request->name); - if (it != this->cache.end()) - { - Query record(*request); - - for (cache_map::iterator it_end = this->cache.upper_bound(request->name); it != it_end; ++it) - { - ResourceRecord &rec = it->second; - if (rec.created + static_cast<time_t>(rec.ttl) >= Anope::CurTime) - record.answers.push_back(rec); - } - - if (!record.answers.empty()) - { - Log(LOG_DEBUG_3) << "Resolver: Using cached result for " << request->name; - request->OnLookupComplete(&record); - return true; - } - } - - return false; -} - -void Manager::Tick(time_t now) -{ - Log(LOG_DEBUG_2) << "Resolver: Purging DNS cache"; - - for (cache_map::iterator it = this->cache.begin(), it_next; it != this->cache.end(); it = it_next) - { - ResourceRecord &req = it->second; - it_next = it; - ++it_next; - - if (req.created + static_cast<time_t>(req.ttl) < now) - this->cache.erase(it); - } -} - -void Manager::Cleanup(Module *mod) -{ - for (std::map<unsigned short, Request *>::iterator it = this->requests.begin(), it_end = this->requests.end(); it != it_end;) - { - unsigned short id = it->first; - Request *req = it->second; - ++it; - - if (req->creator && req->creator == mod) - { - Query rr(*req); - rr.error = ERROR_UNLOADED; - req->OnError(&rr); - - delete req; - this->requests.erase(id); - } - } -} - -void Manager::UpdateSerial() -{ - serial = Anope::CurTime; -} - -uint32_t Manager::GetSerial() const -{ - return serial; -} - -Query Manager::BlockingQuery(const Anope::string &mask, QueryType qt) -{ - Question question(mask, qt); - Query result(question); - - int type = AF_UNSPEC; - if (qt == QUERY_A) - type = AF_INET; - else if (qt == QUERY_AAAA) - type = AF_INET6; - - addrinfo hints; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = type; - - Log(LOG_DEBUG_2) << "Resolver: BlockingQuery: Looking up " << mask; - - addrinfo *addrresult; - if (getaddrinfo(mask.c_str(), NULL, &hints, &addrresult) == 0) - { - for (addrinfo *cur = addrresult; cur; cur = cur->ai_next) - { - sockaddrs addr; - memcpy(&addr, addrresult->ai_addr, addrresult->ai_addrlen); - try - { - ResourceRecord rr(mask, qt); - rr.rdata = addr.addr(); - result.answers.push_back(rr); - - Log(LOG_DEBUG_2) << "Resolver: BlockingQuery: " << mask << " -> " << rr.rdata; - } - catch (const SocketException &) { } - } - - freeaddrinfo(addrresult); - } - - return result; -} - - - diff --git a/src/misc.cpp b/src/misc.cpp index 417849df4..3f74888ee 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -18,10 +18,13 @@ #include "bots.h" #include "language.h" #include "regexpr.h" +#include "sockets.h" #include <errno.h> #include <sys/types.h> #include <sys/stat.h> +#include <sys/socket.h> +#include <netdb.h> NumberList::NumberList(const Anope::string &list, bool descending) : is_valid(true), desc(descending) { @@ -652,3 +655,31 @@ Anope::string Anope::NormalizeBuffer(const Anope::string &buf) return newbuf; } +Anope::string Anope::Resolve(const Anope::string &host, int type) +{ + Anope::string result = host; + + addrinfo hints; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = type; + + Log(LOG_DEBUG_2) << "Resolver: BlockingQuery: Looking up " << host; + + addrinfo *addrresult = NULL; + if (getaddrinfo(host.c_str(), NULL, &hints, &addrresult) == 0) + { + sockaddrs addr; + memcpy(&addr, addrresult->ai_addr, addrresult->ai_addrlen); + try + { + result = addr.addr(); + Log(LOG_DEBUG_2) << "Resolver: " << host << " -> " << result; + } + catch (const SocketException &) { } + + freeaddrinfo(addrresult); + } + + return result; +} + diff --git a/src/module.cpp b/src/module.cpp index e9c130076..396aa74e2 100644 --- a/src/module.cpp +++ b/src/module.cpp @@ -9,8 +9,8 @@ #include "services.h" #include "modules.h" -#include "dns.h" #include "language.h" +#include "account.h" #ifdef GETTEXT_FOUND # include <libintl.h> @@ -46,8 +46,6 @@ Module::Module(const Anope::string &modname, const Anope::string &, ModType modt Module::~Module() { - if (DNS::Engine) - DNS::Engine->Cleanup(this); /* Detach all event hooks for this module */ ModuleManager::DetachAll(this); /* Clear any active callbacks this module has */ diff --git a/src/uplink.cpp b/src/uplink.cpp index ac77672b2..9490329b3 100644 --- a/src/uplink.cpp +++ b/src/uplink.cpp @@ -15,7 +15,6 @@ #include "config.h" #include "protocol.h" #include "servers.h" -#include "dns.h" UplinkSocket *UplinkSock = NULL; @@ -48,10 +47,9 @@ void Uplink::Connect() if (!Config->LocalHost.empty()) UplinkSock->Bind(Config->LocalHost); FOREACH_MOD(I_OnPreServerConnect, OnPreServerConnect()); - DNS::Query rep = DNS::Manager::BlockingQuery(u->host, u->ipv6 ? DNS::QUERY_AAAA : DNS::QUERY_A); - Anope::string reply_ip = !rep.answers.empty() ? rep.answers.front().rdata : u->host; - Log(LOG_TERMINAL) << "Attempting to connect to uplink #" << (Anope::CurrentUplink + 1) << " " << u->host << " (" << reply_ip << "), port " << u->port; - UplinkSock->Connect(reply_ip, u->port); + Anope::string ip = Anope::Resolve(u->host, u->ipv6 ? AF_INET6 : AF_INET); + Log(LOG_TERMINAL) << "Attempting to connect to uplink #" << (Anope::CurrentUplink + 1) << " " << u->host << " (" << ip << "), port " << u->port; + UplinkSock->Connect(ip, u->port); } |