DNS TXT support

This commit is contained in:
Vlad Grigorescu 2012-10-30 12:24:12 -04:00
parent 9ec2bfe59f
commit bc79888190
5 changed files with 206 additions and 44 deletions

View file

@ -46,13 +46,14 @@ extern int select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
class DNS_Mgr_Request { class DNS_Mgr_Request {
public: public:
DNS_Mgr_Request(const char* h, int af) { host = copy_string(h); fam = af; } DNS_Mgr_Request(const char* h, int af, bool isTxt) { host = copy_string(h); fam = af; qtype = isTxt ? 16 : 0; }
DNS_Mgr_Request(const IPAddr& a) { addr = a; host = 0; fam = 0; } DNS_Mgr_Request(const IPAddr& a) { addr = a; host = 0; fam = 0; }
~DNS_Mgr_Request() { delete [] host; } ~DNS_Mgr_Request() { delete [] host; }
// Returns nil if this was an address request. // Returns nil if this was an address request.
const char* ReqHost() const { return host; } const char* ReqHost() const { return host; }
const IPAddr& ReqAddr() const { return addr; } const IPAddr& ReqAddr() const { return addr; }
const bool ReqIsTxt() const { return qtype == 16; }
int MakeRequest(nb_dns_info* nb_dns); int MakeRequest(nb_dns_info* nb_dns);
int RequestPending() const { return request_pending; } int RequestPending() const { return request_pending; }
@ -62,6 +63,7 @@ public:
protected: protected:
char* host; // if non-nil, this is a host request char* host; // if non-nil, this is a host request
int fam; // address family query type for host requests int fam; // address family query type for host requests
int qtype; // Query type
IPAddr addr; IPAddr addr;
int request_pending; int request_pending;
}; };
@ -75,7 +77,7 @@ int DNS_Mgr_Request::MakeRequest(nb_dns_info* nb_dns)
char err[NB_DNS_ERRSIZE]; char err[NB_DNS_ERRSIZE];
if ( host ) if ( host )
return nb_dns_host_request2(nb_dns, host, fam, (void*) this, err) >= 0; return nb_dns_host_request2(nb_dns, host, fam, qtype, (void*) this, err) >= 0;
else else
{ {
const uint32* bytes; const uint32* bytes;
@ -475,8 +477,8 @@ TableVal* DNS_Mgr::LookupHost(const char* name)
// Not found, or priming. // Not found, or priming.
switch ( mode ) { switch ( mode ) {
case DNS_PRIME: case DNS_PRIME:
requests.append(new DNS_Mgr_Request(name, AF_INET)); requests.append(new DNS_Mgr_Request(name, AF_INET, false));
requests.append(new DNS_Mgr_Request(name, AF_INET6)); requests.append(new DNS_Mgr_Request(name, AF_INET6, false));
return empty_addr_set(); return empty_addr_set();
case DNS_FORCE: case DNS_FORCE:
@ -484,8 +486,8 @@ TableVal* DNS_Mgr::LookupHost(const char* name)
return 0; return 0;
case DNS_DEFAULT: case DNS_DEFAULT:
requests.append(new DNS_Mgr_Request(name, AF_INET)); requests.append(new DNS_Mgr_Request(name, AF_INET, false));
requests.append(new DNS_Mgr_Request(name, AF_INET6)); requests.append(new DNS_Mgr_Request(name, AF_INET6, false));
Resolve(); Resolve();
return LookupHost(name); return LookupHost(name);
@ -636,6 +638,7 @@ int DNS_Mgr::Save()
Save(f, host_mappings); Save(f, host_mappings);
Save(f, addr_mappings); Save(f, addr_mappings);
Save(f, text_mappings);
fclose(f); fclose(f);
@ -704,6 +707,12 @@ void DNS_Mgr::AddResult(DNS_Mgr_Request* dr, struct nb_dns_result* r)
new_dm = new DNS_Mapping(dr->ReqHost(), h, ttl); new_dm = new DNS_Mapping(dr->ReqHost(), h, ttl);
prev_dm = 0; prev_dm = 0;
if ( dr->ReqIsTxt() ) {
TextMap::iterator it = text_mappings.find(dr->ReqHost());
if ( it == text_mappings.end() )
text_mappings[dr->ReqHost()] = new_dm;
}
else {
HostMap::iterator it = host_mappings.find(dr->ReqHost()); HostMap::iterator it = host_mappings.find(dr->ReqHost());
if ( it == host_mappings.end() ) if ( it == host_mappings.end() )
{ {
@ -726,7 +735,7 @@ void DNS_Mgr::AddResult(DNS_Mgr_Request* dr, struct nb_dns_result* r)
it->second.second = new_dm; it->second.second = new_dm;
} }
} }
}
if ( new_dm->Failed() && prev_dm && prev_dm->Valid() ) if ( new_dm->Failed() && prev_dm && prev_dm->Valid() )
{ {
// Put previous, valid entry back - CompareMappings // Put previous, valid entry back - CompareMappings
@ -889,6 +898,16 @@ void DNS_Mgr::Save(FILE* f, const AddrMap& m)
} }
} }
void DNS_Mgr::Save(FILE* f, const TextMap& m)
{
for ( TextMap::const_iterator it = m.begin(); it != m.end(); ++it )
{
if ( it->second )
it->second->Save(f);
}
}
void DNS_Mgr::Save(FILE* f, const HostMap& m) void DNS_Mgr::Save(FILE* f, const HostMap& m)
{ {
HostMap::const_iterator it; HostMap::const_iterator it;
@ -927,8 +946,10 @@ const char* DNS_Mgr::LookupAddrInCache(const IPAddr& addr)
TableVal* DNS_Mgr::LookupNameInCache(string name) TableVal* DNS_Mgr::LookupNameInCache(string name)
{ {
HostMap::iterator it = dns_mgr->host_mappings.find(name); HostMap::iterator it = dns_mgr->host_mappings.find(name);
if ( it == dns_mgr->host_mappings.end() ) if ( it == dns_mgr->host_mappings.end() ){
it = dns_mgr->host_mappings.begin();
return 0; return 0;
}
DNS_Mapping* d4 = it->second.first; DNS_Mapping* d4 = it->second.first;
DNS_Mapping* d6 = it->second.second; DNS_Mapping* d6 = it->second.second;
@ -951,6 +972,26 @@ TableVal* DNS_Mgr::LookupNameInCache(string name)
return tv6; return tv6;
} }
const char* DNS_Mgr::LookupTextInCache(string name)
{
TextMap::iterator it = dns_mgr->text_mappings.find(name);
if ( it == dns_mgr->text_mappings.end() )
return 0;
DNS_Mapping* d = it->second;
if ( d->Expired() )
{
dns_mgr->text_mappings.erase(it);
delete d;
return 0;
}
// The escapes in the following strings are to avoid having it
// interpreted as a trigraph sequence.
return d->names ? d->names[0] : "<\?\?\?>";
}
void DNS_Mgr::AsyncLookupAddr(const IPAddr& host, LookupCallback* callback) void DNS_Mgr::AsyncLookupAddr(const IPAddr& host, LookupCallback* callback)
{ {
if ( ! did_init ) if ( ! did_init )
@ -976,6 +1017,7 @@ void DNS_Mgr::AsyncLookupAddr(const IPAddr& host, LookupCallback* callback)
// A new one. // A new one.
req = new AsyncRequest; req = new AsyncRequest;
req->host = host; req->host = host;
req->isTxt = false;
asyncs_queued.push_back(req); asyncs_queued.push_back(req);
asyncs_addrs.insert(AsyncRequestAddrMap::value_type(host, req)); asyncs_addrs.insert(AsyncRequestAddrMap::value_type(host, req));
} }
@ -1020,6 +1062,35 @@ void DNS_Mgr::AsyncLookupName(string name, LookupCallback* callback)
IssueAsyncRequests(); IssueAsyncRequests();
} }
void DNS_Mgr::AsyncLookupNameText(string name, LookupCallback* callback)
{
if ( ! did_init )
Init();
// Do we already know the answer?
TableVal* addrs;
AsyncRequest* req = 0;
// Have we already a request waiting for this host?
AsyncRequestTextMap::iterator i = asyncs_texts.find(name);
if ( i != asyncs_texts.end() )
req = i->second;
else
{
// A new one.
req = new AsyncRequest;
req->name = name;
req->isTxt = true;
asyncs_queued.push_back(req);
asyncs_texts.insert(AsyncRequestTextMap::value_type(name, req));
}
req->callbacks.push_back(callback);
IssueAsyncRequests();
}
void DNS_Mgr::IssueAsyncRequests() void DNS_Mgr::IssueAsyncRequests()
{ {
while ( asyncs_queued.size() && asyncs_pending < MAX_PENDING_REQUESTS ) while ( asyncs_queued.size() && asyncs_pending < MAX_PENDING_REQUESTS )
@ -1036,8 +1107,9 @@ void DNS_Mgr::IssueAsyncRequests()
dr = new DNS_Mgr_Request(req->host); dr = new DNS_Mgr_Request(req->host);
else else
{ {
dr = new DNS_Mgr_Request(req->name.c_str(), AF_INET); dr = new DNS_Mgr_Request(req->name.c_str(), AF_INET, req->isTxt);
dr6 = new DNS_Mgr_Request(req->name.c_str(), AF_INET6); if ( !req->isTxt )
dr6 = new DNS_Mgr_Request(req->name.c_str(), AF_INET6, req->isTxt);
} }
if ( ! dr->MakeRequest(nb_dns) ) if ( ! dr->MakeRequest(nb_dns) )
@ -1143,6 +1215,40 @@ void DNS_Mgr::CheckAsyncHostRequest(const char* host, bool timeout)
} }
} }
void DNS_Mgr::CheckAsyncTextRequest(const char* host, bool timeout)
{
// Note that this code is a mirror of that for CheckAsyncAddrRequest.
AsyncRequestTextMap::iterator i = asyncs_texts.find(host);
if ( i != asyncs_texts.end() )
{
const char* name = LookupTextInCache(host);
if ( name )
{
++successful;
i->second->Resolved(name);
}
else if ( timeout )
{
AsyncRequestTextMap::iterator it = asyncs_texts.begin();
++failed;
i->second->Timeout();
}
else
return;
asyncs_texts.erase(i);
--asyncs_pending;
// Don't delete the request. That will be done once it
// eventually times out.
}
}
void DNS_Mgr::Flush() void DNS_Mgr::Flush()
{ {
DoProcess(false); DoProcess(false);
@ -1157,8 +1263,12 @@ void DNS_Mgr::Flush()
for ( AddrMap::iterator it2 = addr_mappings.begin(); it2 != addr_mappings.end(); ++it2 ) for ( AddrMap::iterator it2 = addr_mappings.begin(); it2 != addr_mappings.end(); ++it2 )
delete it2->second; delete it2->second;
for ( TextMap::iterator it3 = text_mappings.begin(); it3 != text_mappings.end(); ++it3 )
delete it3->second;
host_mappings.clear(); host_mappings.clear();
addr_mappings.clear(); addr_mappings.clear();
text_mappings.clear();
} }
void DNS_Mgr::Process() void DNS_Mgr::Process()
@ -1177,6 +1287,8 @@ void DNS_Mgr::DoProcess(bool flush)
if ( req->IsAddrReq() ) if ( req->IsAddrReq() )
CheckAsyncAddrRequest(req->host, true); CheckAsyncAddrRequest(req->host, true);
else if ( req->isTxt )
CheckAsyncTextRequest(req->name.c_str(), true);
else else
CheckAsyncHostRequest(req->name.c_str(), true); CheckAsyncHostRequest(req->name.c_str(), true);
@ -1184,7 +1296,7 @@ void DNS_Mgr::DoProcess(bool flush)
delete req; delete req;
} }
if ( asyncs_addrs.size() == 0 && asyncs_names.size() == 0 ) if ( asyncs_addrs.size() == 0 && asyncs_names.size() == 0 && asyncs_texts.size() == 0 )
return; return;
if ( AnswerAvailable(0) <= 0 ) if ( AnswerAvailable(0) <= 0 )
@ -1217,6 +1329,8 @@ void DNS_Mgr::DoProcess(bool flush)
if ( ! dr->ReqHost() ) if ( ! dr->ReqHost() )
CheckAsyncAddrRequest(dr->ReqAddr(), true); CheckAsyncAddrRequest(dr->ReqAddr(), true);
else if ( dr->ReqIsTxt() )
CheckAsyncTextRequest(dr->ReqHost(), do_host_timeout);
else else
CheckAsyncHostRequest(dr->ReqHost(), do_host_timeout); CheckAsyncHostRequest(dr->ReqHost(), do_host_timeout);
@ -1271,5 +1385,6 @@ void DNS_Mgr::GetStats(Stats* stats)
stats->pending = asyncs_pending; stats->pending = asyncs_pending;
stats->cached_hosts = host_mappings.size(); stats->cached_hosts = host_mappings.size();
stats->cached_addresses = addr_mappings.size(); stats->cached_addresses = addr_mappings.size();
stats->cached_texts = text_mappings.size();
} }

View file

@ -63,6 +63,7 @@ public:
const char* LookupAddrInCache(const IPAddr& addr); const char* LookupAddrInCache(const IPAddr& addr);
TableVal* LookupNameInCache(string name); TableVal* LookupNameInCache(string name);
const char* LookupTextInCache(string name);
// Support for async lookups. // Support for async lookups.
class LookupCallback { class LookupCallback {
@ -77,6 +78,7 @@ public:
void AsyncLookupAddr(const IPAddr& host, LookupCallback* callback); void AsyncLookupAddr(const IPAddr& host, LookupCallback* callback);
void AsyncLookupName(string name, LookupCallback* callback); void AsyncLookupName(string name, LookupCallback* callback);
void AsyncLookupNameText(string name, LookupCallback* callback);
struct Stats { struct Stats {
unsigned long requests; // These count only async requests. unsigned long requests; // These count only async requests.
@ -85,6 +87,7 @@ public:
unsigned long pending; unsigned long pending;
unsigned long cached_hosts; unsigned long cached_hosts;
unsigned long cached_addresses; unsigned long cached_addresses;
unsigned long cached_texts;
}; };
void GetStats(Stats* stats); void GetStats(Stats* stats);
@ -106,9 +109,11 @@ protected:
typedef map<string, pair<DNS_Mapping*, DNS_Mapping*> > HostMap; typedef map<string, pair<DNS_Mapping*, DNS_Mapping*> > HostMap;
typedef map<IPAddr, DNS_Mapping*> AddrMap; typedef map<IPAddr, DNS_Mapping*> AddrMap;
typedef map<string, DNS_Mapping* > TextMap;
void LoadCache(FILE* f); void LoadCache(FILE* f);
void Save(FILE* f, const AddrMap& m); void Save(FILE* f, const AddrMap& m);
void Save(FILE* f, const HostMap& m); void Save(FILE* f, const HostMap& m);
void Save(FILE* f, const TextMap& m);
// Selects on the fd to see if there is an answer available (timeout // Selects on the fd to see if there is an answer available (timeout
// is secs). Returns 0 on timeout, -1 on EINTR or other error, and 1 // is secs). Returns 0 on timeout, -1 on EINTR or other error, and 1
@ -122,6 +127,7 @@ protected:
// requested. // requested.
void CheckAsyncAddrRequest(const IPAddr& addr, bool timeout); void CheckAsyncAddrRequest(const IPAddr& addr, bool timeout);
void CheckAsyncHostRequest(const char* host, bool timeout); void CheckAsyncHostRequest(const char* host, bool timeout);
void CheckAsyncTextRequest(const char* host, bool timeout);
// Process outstanding requests. // Process outstanding requests.
void DoProcess(bool flush); void DoProcess(bool flush);
@ -138,6 +144,7 @@ protected:
HostMap host_mappings; HostMap host_mappings;
AddrMap addr_mappings; AddrMap addr_mappings;
TextMap text_mappings;
DNS_mgr_request_list requests; DNS_mgr_request_list requests;
@ -165,6 +172,7 @@ protected:
double time; double time;
IPAddr host; IPAddr host;
string name; string name;
bool isTxt;
CallbackList callbacks; CallbackList callbacks;
bool IsAddrReq() const { return name.length() == 0; } bool IsAddrReq() const { return name.length() == 0; }
@ -210,6 +218,9 @@ protected:
typedef map<string, AsyncRequest*> AsyncRequestNameMap; typedef map<string, AsyncRequest*> AsyncRequestNameMap;
AsyncRequestNameMap asyncs_names; AsyncRequestNameMap asyncs_names;
typedef map<string, AsyncRequest*> AsyncRequestTextMap;
AsyncRequestTextMap asyncs_texts;
typedef list<AsyncRequest*> QueuedList; typedef list<AsyncRequest*> QueuedList;
QueuedList asyncs_queued; QueuedList asyncs_queued;

View file

@ -3770,6 +3770,35 @@ function lookup_addr%(host: addr%) : string
return 0; return 0;
%} %}
## Issues an asynchronous TEXT DNS lookup and delays the function result.
## This function can therefore only be called inside a ``when`` condition,
## e.g., ``when ( local h = lookup_hostname_txt("www.bro-ids.org") ) { f(h); }``.
##
## host: The hostname to lookup.
##
## Returns: A set of DNS A and AAAA records associated with *host*.
##
## .. bro:see:: lookup_hostname
function lookup_hostname_txt%(host: string%) : addr_set
%{
// FIXME: Is should be easy to adapt the function to synchronous
// lookups if we're reading a trace.
Trigger* trigger = frame->GetTrigger();
if ( ! trigger)
{
builtin_error("lookup_hostname_txt() can only be called inside a when-condition");
return new StringVal("<error>");
}
frame->SetDelayed();
trigger->Hold();
dns_mgr->AsyncLookupNameText(host->CheckString(),
new LookupHostCallback(trigger, frame->GetCall(), false));
return 0;
%}
## Issues an asynchronous DNS lookup and delays the function result. ## Issues an asynchronous DNS lookup and delays the function result.
## This function can therefore only be called inside a ``when`` condition, ## This function can therefore only be called inside a ``when`` condition,
## e.g., ``when ( local h = lookup_hostname("www.bro-ids.org") ) { f(h); }``. ## e.g., ``when ( local h = lookup_hostname("www.bro-ids.org") ) { f(h); }``.

View file

@ -307,14 +307,14 @@ nb_dns_host_request(register struct nb_dns_info *nd, register const char *name,
register void *cookie, register char *errstr) register void *cookie, register char *errstr)
{ {
return (nb_dns_host_request2(nd, name, AF_INET, cookie, errstr)); return (nb_dns_host_request2(nd, name, AF_INET, 0, cookie, errstr));
} }
int int
nb_dns_host_request2(register struct nb_dns_info *nd, register const char *name, nb_dns_host_request2(register struct nb_dns_info *nd, register const char *name,
register int af, register void *cookie, register char *errstr) register int af, register int qtype, register void *cookie, register char *errstr)
{ {
register int qtype; if (qtype != 16){
switch (af) { switch (af) {
@ -330,9 +330,10 @@ nb_dns_host_request2(register struct nb_dns_info *nd, register const char *name,
default: default:
snprintf(errstr, NB_DNS_ERRSIZE, snprintf(errstr, NB_DNS_ERRSIZE,
"nb_dns_host_request2(): uknown address family %d", af); "nb_dns_host_request2(): unknown address family %d", af);
return (-1); return (-1);
} }
}
return (_nb_dns_mkquery(nd, name, af, qtype, cookie, errstr)); return (_nb_dns_mkquery(nd, name, af, qtype, cookie, errstr));
} }
@ -603,6 +604,12 @@ nb_dns_activity(struct nb_dns_info *nd, struct nb_dns_result *nr, char *errstr)
nr->hostent = he; nr->hostent = he;
nr->ttl = rttl; nr->ttl = rttl;
return (1); return (1);
case T_TXT:
memcpy(bp, rdata, rdlen);
he->h_name = bp+1; /* First char is a control character. */
nr->hostent = he;
nr->ttl = rttl;
return (1);
} }
} }

View file

@ -22,7 +22,7 @@ void nb_dns_finish(struct nb_dns_info *);
int nb_dns_fd(struct nb_dns_info *); int nb_dns_fd(struct nb_dns_info *);
int nb_dns_host_request(struct nb_dns_info *, const char *, void *, char *); int nb_dns_host_request(struct nb_dns_info *, const char *, void *, char *);
int nb_dns_host_request2(struct nb_dns_info *, const char *, int, int nb_dns_host_request2(struct nb_dns_info *, const char *, int, int,
void *, char *); void *, char *);
int nb_dns_addr_request(struct nb_dns_info *, nb_uint32_t, void *, char *); int nb_dns_addr_request(struct nb_dns_info *, nb_uint32_t, void *, char *);