hello-dns/tdns/tdns-c.cc
2018-10-12 16:27:03 +02:00

240 lines
6.1 KiB
C++

#include "tdns-c.h"
#include "comboaddress.hh"
#include "record-types.hh"
#include "swrappers.hh"
#include "sclasses.hh"
#include <memory>
using namespace std;
namespace {
template<typename T>
struct TDNSCleanUp
{
void operator()(vector<T*>* vec)
{
for(auto& p : *vec) {
delete p;
}
delete vec;
}
};
DNSMessageReader getDNSResponse(Socket& sock, const DNSName& dn, const DNSType& dt)
{
DNSMessageWriter dmw(dn, dt);
dmw.dh.rd = true;
dmw.randomizeID();
SWrite(sock, dmw.serialize());
ComboAddress server;
string resp =SRecvfrom(sock, 65535, server);
return DNSMessageReader(resp);
}
Socket makeResolverSocket()
{
ComboAddress server("192.168.1.91", 53);
Socket sock(server.sin4.sin_family, SOCK_DGRAM);
SConnect(sock, server);
return sock;
}
}
extern "C" {
const char* TDNSErrorMessage(int err)
{
static const char *errors[]={"No error", "Timeout", "Server failure", "No such domain", "Unknown error"};
static constexpr int size = sizeof(errors)/sizeof(errors[0]);
if(err >= size)
err = size-1;
return errors[err];
};
void freeTDNSIPAddresses(struct TDNSIPAddresses*vec)
{
auto ptr = (vector<struct sockaddr_storage*>*) vec->__handle;
TDNSCleanUp<struct sockaddr_storage>()(ptr);
delete vec;
}
int TDNSLookupIPs(const char* name, int timeoutMsec, int lookupIPv4, int lookupIPv6, struct TDNSIPAddresses** ret)
{
Socket sock = makeResolverSocket();
vector<DNSType> dtypes;
if(lookupIPv4)
dtypes.push_back(DNSType::A);
if(lookupIPv6)
dtypes.push_back(DNSType::AAAA);
DNSName dn = makeDNSName(name);
std::unique_ptr<vector<struct sockaddr_storage*>, TDNSCleanUp<struct sockaddr_storage>> sas(new vector<struct sockaddr_storage*>());
uint32_t resttl = std::numeric_limits<uint32_t>::max();
for(const auto& dt : dtypes) {
DNSMessageReader dmr = getDNSResponse(sock, dn, dt);
DNSName rrdn;
DNSType rrdt;
dmr.getQuestion(rrdn, rrdt);
if(dmr.dh.rcode) {
return 3;
}
// cout<<"Received response with RCode "<<(RCode)dmr.dh.rcode<<", qname " <<rrdn<<", qtype "<<rrdt<<endl;
std::unique_ptr<RRGen> rr;
DNSSection rrsection;
uint32_t rrttl;
while(dmr.getRR(rrsection, rrdn, rrdt, rrttl, rr)) {
if(rrttl < resttl)
resttl = rrttl;
// cout << rrsection << " " << rrdn<< " IN " << rrdt << " " << rrttl << " " <<rr->toString()<<endl;
if(rrsection != DNSSection::Answer || rrdt != dt)
continue;
ComboAddress ca;
if(dt == DNSType::A) {
auto agen =dynamic_cast<AGen*>(rr.get());
ca = agen->getIP();
}
else {
auto agen =dynamic_cast<AAAAGen*>(rr.get());
ca = agen->getIP();
}
auto sa = new struct sockaddr_storage();
memcpy(sa, &ca, sizeof(ca));
sas->push_back(sa);
}
}
sas->push_back(0);
*ret = new struct TDNSIPAddresses();
(*ret)->ttl = resttl;
(*ret)->addresses = (struct sockaddr_storage**)(&(*sas)[0]);
(*ret)->__handle = sas.get();
sas.release();
return 0;
}
int TDNSLookupMXs(const char* name, int timeoutMsec, struct TDNSMXs** ret)
{
Socket sock = makeResolverSocket();
std::unique_ptr<vector<struct TDNSMX*>, TDNSCleanUp<struct TDNSMX>> sas(new vector<struct TDNSMX*>());
uint32_t resttl = std::numeric_limits<uint32_t>::max();
DNSName dn = makeDNSName(name);
DNSMessageReader dmr = getDNSResponse(sock, dn, DNSType::MX);
DNSName rrdn;
DNSType rrdt;
dmr.getQuestion(rrdn, rrdt);
// cout<<"Received response with RCode "<<(RCode)dmr.dh.rcode<<", qname " <<rrdn<<", qtype "<<rrdt<<endl;
std::unique_ptr<RRGen> rr;
DNSSection rrsection;
uint32_t rrttl;
while(dmr.getRR(rrsection, rrdn, rrdt, rrttl, rr)) {
if(rrttl < resttl)
resttl = rrttl;
// cout << rrsection << " " << rrdn<< " IN " << rrdt << " " << rrttl << " " <<rr->toString()<<endl;
if(rrsection != DNSSection::Answer || rrdt != DNSType::MX)
continue;
if(rrdt == DNSType::MX) {
auto mxgen =dynamic_cast<MXGen*>(rr.get());
auto sa = new struct TDNSMX();
sa->priority = mxgen->d_prio;
sa->name = strdup(mxgen->d_name.toString().c_str());
sas->push_back(sa);
}
}
sas->push_back(0);
*ret = new struct TDNSMXs();
(*ret)->ttl = resttl;
(*ret)->mxs = (struct TDNSMX**)(&(*sas)[0]);
(*ret)->__handle = sas.get();
sas.release();
return 0;
}
void freeTDNSMXs(struct TDNSMXs* vec)
{
auto ptr = (vector<struct TDNSMX*>*) vec->__handle;
for(auto& p : *ptr) {
if(!p) break;
free((void*)p->name);
delete p;
}
delete ptr;
delete vec;
}
int TDNSLookupTXTs(const char* name, int timeoutMsec, struct TDNSTXTs** ret)
{
Socket sock = makeResolverSocket();
std::unique_ptr<vector<struct TDNSTXT*>, TDNSCleanUp<struct TDNSTXT>> sas(new vector<struct TDNSTXT*>());
uint32_t resttl = std::numeric_limits<uint32_t>::max();
DNSName dn = makeDNSName(name);
DNSMessageReader dmr = getDNSResponse(sock, dn, DNSType::TXT);
DNSName rrdn;
DNSType rrdt;
dmr.getQuestion(rrdn, rrdt);
// cout<<"Received response with RCode "<<(RCode)dmr.dh.rcode<<", qname " <<rrdn<<", qtype "<<rrdt<<endl;
std::unique_ptr<RRGen> rr;
DNSSection rrsection;
uint32_t rrttl;
while(dmr.getRR(rrsection, rrdn, rrdt, rrttl, rr)) {
if(rrttl < resttl)
resttl = rrttl;
// cout << rrsection << " " << rrdn<< " IN " << rrdt << " " << rrttl << " " <<rr->toString()<<endl;
if(rrsection != DNSSection::Answer || rrdt != DNSType::TXT)
continue;
if(rrdt == DNSType::TXT) {
auto txtgen =dynamic_cast<TXTGen*>(rr.get());
auto sa = new struct TDNSTXT();
sa->content = strdup(txtgen->toString().c_str());
sas->push_back(sa);
}
}
sas->push_back(0);
*ret = new struct TDNSTXTs();
(*ret)->ttl = resttl;
(*ret)->txts = (struct TDNSTXT**)(&(*sas)[0]);
(*ret)->__handle = sas.get();
sas.release();
return 0;
}
void freeTDNSTXTs(struct TDNSTXTs* vec)
{
auto ptr = (vector<struct TDNSTXT*>*) vec->__handle;
for(auto& p : *ptr) {
if(!p) break;
free((void*)p->content);
delete p;
}
delete ptr;
delete vec;
}
}