Merge remote-tracking branch 'origin/topic/jsiwek/v6-dns-name-lookup' into topic/robin/v6-addr-merge

* origin/topic/jsiwek/v6-dns-name-lookup:
  DNS name lookups performed by Bro now also query AAAA records.

Conflicts:
	src/DNS_Mgr.cc
This commit is contained in:
Robin Sommer 2012-02-17 10:39:24 -08:00
commit be3fb5fb81
2 changed files with 148 additions and 33 deletions

View file

@ -46,8 +46,8 @@ 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) { host = copy_string(h); } DNS_Mgr_Request(const char* h, int af) { host = copy_string(h); fam = af; }
DNS_Mgr_Request(const IPAddr& a) { addr = a; host = 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.
@ -61,8 +61,8 @@ 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
IPAddr addr; IPAddr addr;
uint32 ttl;
int request_pending; int request_pending;
}; };
@ -75,7 +75,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_request(nb_dns, host, (void*) this, err) >= 0; return nb_dns_host_request2(nb_dns, host, fam, (void*) this, err) >= 0;
else else
{ {
const uint32* bytes; const uint32* bytes;
@ -116,7 +116,14 @@ public:
int Valid() const { return ! failed; } int Valid() const { return ! failed; }
bool Expired() const bool Expired() const
{ return current_time() > (creation_time + req_ttl); } {
if ( req_host && num_addrs == 0)
return false; // nothing to expire
return current_time() > (creation_time + req_ttl);
}
int Type() const { return map_type; }
protected: protected:
friend class DNS_Mgr; friend class DNS_Mgr;
@ -141,6 +148,7 @@ protected:
int failed; int failed;
double creation_time; double creation_time;
int map_type;
}; };
void DNS_Mgr_mapping_delete_func(void* v) void DNS_Mgr_mapping_delete_func(void* v)
@ -193,8 +201,9 @@ DNS_Mapping::DNS_Mapping(FILE* f)
char req_buf[512+1], name_buf[512+1]; char req_buf[512+1], name_buf[512+1];
int is_req_host; int is_req_host;
if ( sscanf(buf, "%lf %d %512s %d %512s %d", &creation_time, &is_req_host, if ( sscanf(buf, "%lf %d %512s %d %512s %d %d %"PRIu32, &creation_time,
req_buf, &failed, name_buf, &num_addrs) != 6 ) &is_req_host, req_buf, &failed, name_buf, &map_type, &num_addrs,
&req_ttl) != 8 )
return; return;
if ( is_req_host ) if ( is_req_host )
@ -299,6 +308,7 @@ void DNS_Mapping::Init(struct hostent* h)
return; return;
} }
map_type = h->h_addrtype;
num_names = 1; // for now, just use official name num_names = 1; // for now, just use official name
names = new char*[num_names]; names = new char*[num_names];
names[0] = h->h_name ? copy_string(h->h_name) : 0; names[0] = h->h_name ? copy_string(h->h_name) : 0;
@ -331,15 +341,16 @@ void DNS_Mapping::Clear()
host_val = 0; host_val = 0;
addrs_val = 0; addrs_val = 0;
no_mapping = 0; no_mapping = 0;
map_type = 0;
failed = 1; failed = 1;
} }
void DNS_Mapping::Save(FILE* f) const void DNS_Mapping::Save(FILE* f) const
{ {
fprintf(f, "%.0f %d %s %d %s %d\n", creation_time, req_host != 0, fprintf(f, "%.0f %d %s %d %s %d %d %"PRIu32"\n", creation_time, req_host != 0,
req_host ? req_host : req_addr.AsString().c_str(), req_host ? req_host : req_addr.AsString().c_str(),
failed, (names && names[0]) ? names[0] : "*", failed, (names && names[0]) ? names[0] : "*",
num_addrs); map_type, num_addrs, req_ttl);
for ( int i = 0; i < num_addrs; ++i ) for ( int i = 0; i < num_addrs; ++i )
fprintf(f, "%s\n", addrs[i].AsString().c_str()); fprintf(f, "%s\n", addrs[i].AsString().c_str());
@ -352,7 +363,6 @@ DNS_Mgr::DNS_Mgr(DNS_MgrMode arg_mode)
mode = arg_mode; mode = arg_mode;
host_mappings.SetDeleteFunc(DNS_Mgr_mapping_delete_func);
addr_mappings.SetDeleteFunc(DNS_Mgr_mapping_delete_func); addr_mappings.SetDeleteFunc(DNS_Mgr_mapping_delete_func);
char err[NB_DNS_ERRSIZE]; char err[NB_DNS_ERRSIZE];
@ -441,24 +451,34 @@ TableVal* DNS_Mgr::LookupHost(const char* name)
if ( mode != DNS_PRIME ) if ( mode != DNS_PRIME )
{ {
DNS_Mapping* d = host_mappings.Lookup(name); HostMap::iterator it = host_mappings.find(name);
if ( d ) if ( it != host_mappings.end() )
{ {
if ( d->Valid() ) DNS_Mapping* d4 = it->second.first;
return d->Addrs()->ConvertToSet(); DNS_Mapping* d6 = it->second.second;
else
if ( (d4 && d4->Failed()) || (d6 && d6->Failed()) )
{ {
reporter->Warning("no such host: %s", name); reporter->Warning("no such host: %s", name);
return empty_addr_set(); return empty_addr_set();
} }
else if ( d4 && d6 )
{
TableVal* tv4 = d4->AddrsSet();
TableVal* tv6 = d6->AddrsSet();
tv4->AddTo(tv6, false);
Unref(tv4);
return tv6;
}
} }
} }
// 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)); requests.append(new DNS_Mgr_Request(name, AF_INET));
requests.append(new DNS_Mgr_Request(name, AF_INET6));
return empty_addr_set(); return empty_addr_set();
case DNS_FORCE: case DNS_FORCE:
@ -466,7 +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)); requests.append(new DNS_Mgr_Request(name, AF_INET));
requests.append(new DNS_Mgr_Request(name, AF_INET6));
Resolve(); Resolve();
return LookupHost(name); return LookupHost(name);
@ -683,13 +704,43 @@ void DNS_Mgr::AddResult(DNS_Mgr_Request* dr, struct nb_dns_result* r)
if ( dr->ReqHost() ) if ( dr->ReqHost() )
{ {
new_dm = new DNS_Mapping(dr->ReqHost(), h, ttl); new_dm = new DNS_Mapping(dr->ReqHost(), h, ttl);
prev_dm = host_mappings.Insert(dr->ReqHost(), new_dm);
HostMap::iterator it = host_mappings.find(dr->ReqHost());
if ( it == host_mappings.end() )
{
host_mappings[dr->ReqHost()].first =
new_dm->Type() == AF_INET ? new_dm : 0;
host_mappings[dr->ReqHost()].second =
new_dm->Type() == AF_INET6 ? new_dm : 0;
prev_dm = 0;
}
else
{
prev_dm = 0;
if ( new_dm->Type() == AF_INET )
{
prev_dm = it->second.first;
it->second.first = new_dm;
}
else
{
prev_dm = it->second.second;
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
// will generate a corresponding warning. // will generate a corresponding warning.
(void) host_mappings.Insert(dr->ReqHost(), prev_dm); if ( prev_dm->Type() == AF_INET )
host_mappings[dr->ReqHost()].first = prev_dm;
else
host_mappings[dr->ReqHost()].second = prev_dm;
++keep_prev; ++keep_prev;
} }
} }
@ -810,7 +861,17 @@ void DNS_Mgr::LoadCache(FILE* f)
for ( ; ! m->NoMapping() && ! m->InitFailed(); m = new DNS_Mapping(f) ) for ( ; ! m->NoMapping() && ! m->InitFailed(); m = new DNS_Mapping(f) )
{ {
if ( m->ReqHost() ) if ( m->ReqHost() )
host_mappings.Insert(m->ReqHost(), m); {
if ( host_mappings.find(m->ReqHost()) == host_mappings.end() )
{
host_mappings[m->ReqHost()].first = 0;
host_mappings[m->ReqHost()].second = 0;
}
if ( m->Type() == AF_INET )
host_mappings[m->ReqHost()].first = m;
else
host_mappings[m->ReqHost()].second = m;
}
else else
{ {
HashKey h(m->ReqAddr()); HashKey h(m->ReqAddr());
@ -834,6 +895,20 @@ void DNS_Mgr::Save(FILE* f, PDict(DNS_Mapping)& m)
dm->Save(f); dm->Save(f);
} }
void DNS_Mgr::Save(FILE* f, const HostMap& m)
{
HostMap::const_iterator it;
for ( it = m.begin(); it != m.end(); ++it )
{
if ( it->second.first )
it->second.first->Save(f);
if ( it->second.second )
it->second.second->Save(f);
}
}
const char* DNS_Mgr::LookupAddrInCache(const IPAddr& addr) const char* DNS_Mgr::LookupAddrInCache(const IPAddr& addr)
{ {
HashKey h(addr); HashKey h(addr);
@ -856,20 +931,29 @@ const char* DNS_Mgr::LookupAddrInCache(const IPAddr& addr)
TableVal* DNS_Mgr::LookupNameInCache(string name) TableVal* DNS_Mgr::LookupNameInCache(string name)
{ {
DNS_Mapping* d = dns_mgr->host_mappings.Lookup(name.c_str()); HostMap::iterator it = dns_mgr->host_mappings.find(name);
if ( it == dns_mgr->host_mappings.end() )
if ( ! d || ! d->names )
return 0; return 0;
if ( d->Expired() ) DNS_Mapping* d4 = it->second.first;
DNS_Mapping* d6 = it->second.second;
if ( ! d4 || ! d4->names || ! d6 || ! d6->names )
return 0;
if ( d4->Expired() || d6->Expired() )
{ {
HashKey h(name.c_str()); dns_mgr->host_mappings.erase(it);
dns_mgr->host_mappings.Remove(&h); delete d4;
delete d; delete d6;
return 0; return 0;
} }
return d->AddrsSet(); TableVal* tv4 = d4->AddrsSet();
TableVal* tv6 = d6->AddrsSet();
tv4->AddTo(tv6, false);
Unref(tv4);
return tv6;
} }
void DNS_Mgr::AsyncLookupAddr(const IPAddr& host, LookupCallback* callback) void DNS_Mgr::AsyncLookupAddr(const IPAddr& host, LookupCallback* callback)
@ -951,10 +1035,15 @@ void DNS_Mgr::IssueAsyncRequests()
++num_requests; ++num_requests;
DNS_Mgr_Request* dr; DNS_Mgr_Request* dr;
DNS_Mgr_Request* dr6 = 0;
if ( req->IsAddrReq() ) if ( req->IsAddrReq() )
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()); {
dr = new DNS_Mgr_Request(req->name.c_str(), AF_INET);
dr6 = new DNS_Mgr_Request(req->name.c_str(), AF_INET6);
}
if ( ! dr->MakeRequest(nb_dns) ) if ( ! dr->MakeRequest(nb_dns) )
{ {
@ -964,6 +1053,14 @@ void DNS_Mgr::IssueAsyncRequests()
continue; continue;
} }
if ( dr6 && ! dr6->MakeRequest(nb_dns) )
{
reporter->Warning("can't issue DNS request");
++failed;
req->Timeout();
continue;
}
req->time = current_time(); req->time = current_time();
asyncs_timeouts.push(req); asyncs_timeouts.push(req);
@ -1055,7 +1152,14 @@ void DNS_Mgr::Flush()
{ {
DoProcess(false); DoProcess(false);
host_mappings.Clear(); HostMap::iterator it;
for ( it = host_mappings.begin(); it != host_mappings.end(); ++it )
{
delete it->second.first;
delete it->second.second;
}
host_mappings.clear();
addr_mappings.Clear(); addr_mappings.Clear();
} }
@ -1099,6 +1203,14 @@ void DNS_Mgr::DoProcess(bool flush)
else if ( status > 0 ) else if ( status > 0 )
{ {
DNS_Mgr_Request* dr = (DNS_Mgr_Request*) r.cookie; DNS_Mgr_Request* dr = (DNS_Mgr_Request*) r.cookie;
bool do_host_timeout = true;
if ( dr->ReqHost() &&
host_mappings.find(dr->ReqHost()) == host_mappings.end() )
// Don't timeout when this is the first result in an expected pair
// (one result each for A and AAAA queries).
do_host_timeout = false;
if ( dr->RequestPending() ) if ( dr->RequestPending() )
{ {
AddResult(dr, &r); AddResult(dr, &r);
@ -1108,7 +1220,7 @@ void DNS_Mgr::DoProcess(bool flush)
if ( ! dr->ReqHost() ) if ( ! dr->ReqHost() )
CheckAsyncAddrRequest(dr->ReqAddr(), true); CheckAsyncAddrRequest(dr->ReqAddr(), true);
else else
CheckAsyncHostRequest(dr->ReqHost(), true); CheckAsyncHostRequest(dr->ReqHost(), do_host_timeout);
IssueAsyncRequests(); IssueAsyncRequests();
@ -1159,7 +1271,7 @@ void DNS_Mgr::GetStats(Stats* stats)
stats->successful = successful; stats->successful = successful;
stats->failed = failed; stats->failed = failed;
stats->pending = asyncs_pending; stats->pending = asyncs_pending;
stats->cached_hosts = host_mappings.Length(); stats->cached_hosts = host_mappings.size();
stats->cached_addresses = addr_mappings.Length(); stats->cached_addresses = addr_mappings.Length();
} }

View file

@ -6,6 +6,7 @@
#include <list> #include <list>
#include <map> #include <map>
#include <queue> #include <queue>
#include <utility>
#include "util.h" #include "util.h"
#include "BroList.h" #include "BroList.h"
@ -104,8 +105,10 @@ protected:
ListVal* AddrListDelta(ListVal* al1, ListVal* al2); ListVal* AddrListDelta(ListVal* al1, ListVal* al2);
void DumpAddrList(FILE* f, ListVal* al); void DumpAddrList(FILE* f, ListVal* al);
typedef map<string, pair<DNS_Mapping*, DNS_Mapping*> > HostMap;
void LoadCache(FILE* f); void LoadCache(FILE* f);
void Save(FILE* f, PDict(DNS_Mapping)& m); void Save(FILE* f, PDict(DNS_Mapping)& m);
void Save(FILE* f, const HostMap& 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
@ -133,7 +136,7 @@ protected:
PDict(ListVal) services; PDict(ListVal) services;
PDict(DNS_Mapping) host_mappings; HostMap host_mappings;
PDict(DNS_Mapping) addr_mappings; PDict(DNS_Mapping) addr_mappings;
DNS_mgr_request_list requests; DNS_mgr_request_list requests;