/* * Copyright (c) 2019-2021, OARC, Inc. * Copyright (c) 2019, DENIC eG * All rights reserved. * * This file is part of dnsmeter. * * dnsmeter is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * dnsmeter is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with dnsmeter. If not, see . */ #include "config.h" #include "query.h" #include "exceptions.h" #include #include #include #include #include static const char* rr_types[] = { "A", "AAAA", "MX", "NS", "DS", "DNSKEY", "TXT", "SOA", "NAPTR", "RRSIG", "NSEC", "NSEC3", "NSEC3PARAM", "PTR", "SRV", "CNAME", "TSIG", "*", "ANY", "AXFR", "IXFR", "SPF", "A6", "HINFO", "WKS", "NULL", NULL }; static int rr_code[] = { 1, 28, 15, 2, 43, 48, 16, 6, 35, 46, 47, 50, 51, 12, 33, 5, 250, 255, 255, 252, 251, 99, 38, 13, 11, 10, 0 }; #pragma pack(push) /* push current alignment to stack */ #pragma pack(1) /* set alignment to 1 byte boundary */ struct DNS_OPT { unsigned char name; unsigned short type; unsigned short udp_payload_size; unsigned char extended_rcode; unsigned char edns0_version; unsigned short z; unsigned short data_length; }; #pragma pack(pop) /* restore original alignment from stack */ int MakeQuery(const ppl7::String& query, unsigned char* buffer, size_t buffersize, bool dnssec, int udp_payload_size) { ppl7::Array tok(query, " "); if (tok.size() != 2) throw InvalidDNSQuery(query); ppl7::String Type = tok[1].toUpperCase(); int t = 0; const char* str = Type.c_str(); while (rr_types[t] != NULL) { if (!strcmp(str, rr_types[t])) { int bytes = res_mkquery(QUERY, (const char*)tok[0], C_IN, rr_code[t], NULL, 0, NULL, buffer, (int)buffersize); if (bytes < 0) throw InvalidDNSQuery("%s", hstrerror(h_errno)); if (!dnssec) return bytes; return AddDnssecToQuery(buffer, buffersize, bytes, udp_payload_size); } t++; } throw UnknownRRType(tok[1]); } int AddDnssecToQuery(unsigned char* buffer, size_t buffersize, int querysize, int udp_payload_size) { DNS_HEADER* dns = (DNS_HEADER*)buffer; dns->ad = 1; dns->add_count = htons(1); DNS_OPT* opt = (DNS_OPT*)(buffer + querysize); memset(opt, 0, 11); opt->type = htons(41); opt->udp_payload_size = htons(udp_payload_size); opt->z = htons(0x8000); // DO-bit return querysize + 11; } unsigned short getQueryTimestamp() { struct timeval tp; if (gettimeofday(&tp, NULL) == 0) { return (tp.tv_sec % 6) * 10000 + (tp.tv_usec / 100); } return 0; } double getQueryRTT(unsigned short start) { unsigned short now = getQueryTimestamp(); unsigned short diff = now - start; if (now < start) diff = 60000 - start + now; return (double)(diff) / 10000.0f; }