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 {
public:
DNS_Mgr_Request(const char* h) { host = copy_string(h); }
DNS_Mgr_Request(const IPAddr& a) { addr = a; host = 0; }
DNS_Mgr_Request(const char* h, int af) { host = copy_string(h); fam = af; }
DNS_Mgr_Request(const IPAddr& a) { addr = a; host = 0; fam = 0; }
~DNS_Mgr_Request() { delete [] host; }
// Returns nil if this was an address request.
@ -61,8 +61,8 @@ public:
protected:
char* host; // if non-nil, this is a host request
int fam; // address family query type for host requests
IPAddr addr;
uint32 ttl;
int request_pending;
};
@ -75,7 +75,7 @@ int DNS_Mgr_Request::MakeRequest(nb_dns_info* nb_dns)
char err[NB_DNS_ERRSIZE];
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
{
const uint32* bytes;
@ -116,7 +116,14 @@ public:
int Valid() const { return ! failed; }
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:
friend class DNS_Mgr;
@ -141,6 +148,7 @@ protected:
int failed;
double creation_time;
int map_type;
};
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];
int is_req_host;
if ( sscanf(buf, "%lf %d %512s %d %512s %d", &creation_time, &is_req_host,
req_buf, &failed, name_buf, &num_addrs) != 6 )
if ( sscanf(buf, "%lf %d %512s %d %512s %d %d %"PRIu32, &creation_time,
&is_req_host, req_buf, &failed, name_buf, &map_type, &num_addrs,
&req_ttl) != 8 )
return;
if ( is_req_host )
@ -299,6 +308,7 @@ void DNS_Mapping::Init(struct hostent* h)
return;
}
map_type = h->h_addrtype;
num_names = 1; // for now, just use official name
names = new char*[num_names];
names[0] = h->h_name ? copy_string(h->h_name) : 0;
@ -331,15 +341,16 @@ void DNS_Mapping::Clear()
host_val = 0;
addrs_val = 0;
no_mapping = 0;
map_type = 0;
failed = 1;
}
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(),
failed, (names && names[0]) ? names[0] : "*",
num_addrs);
map_type, num_addrs, req_ttl);
for ( int i = 0; i < num_addrs; ++i )
fprintf(f, "%s\n", addrs[i].AsString().c_str());
@ -352,7 +363,6 @@ DNS_Mgr::DNS_Mgr(DNS_MgrMode arg_mode)
mode = arg_mode;
host_mappings.SetDeleteFunc(DNS_Mgr_mapping_delete_func);
addr_mappings.SetDeleteFunc(DNS_Mgr_mapping_delete_func);
char err[NB_DNS_ERRSIZE];
@ -441,24 +451,34 @@ TableVal* DNS_Mgr::LookupHost(const char* name)
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() )
return d->Addrs()->ConvertToSet();
else
DNS_Mapping* d4 = it->second.first;
DNS_Mapping* d6 = it->second.second;
if ( (d4 && d4->Failed()) || (d6 && d6->Failed()) )
{
reporter->Warning("no such host: %s", name);
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.
switch ( mode ) {
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();
case DNS_FORCE:
@ -466,7 +486,8 @@ TableVal* DNS_Mgr::LookupHost(const char* name)
return 0;
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();
return LookupHost(name);
@ -683,13 +704,43 @@ void DNS_Mgr::AddResult(DNS_Mgr_Request* dr, struct nb_dns_result* r)
if ( dr->ReqHost() )
{
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() )
{
// Put previous, valid entry back - CompareMappings
// 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;
}
}
@ -810,7 +861,17 @@ void DNS_Mgr::LoadCache(FILE* f)
for ( ; ! m->NoMapping() && ! m->InitFailed(); m = new DNS_Mapping(f) )
{
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
{
HashKey h(m->ReqAddr());
@ -834,6 +895,20 @@ void DNS_Mgr::Save(FILE* f, PDict(DNS_Mapping)& m)
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)
{
HashKey h(addr);
@ -856,20 +931,29 @@ const char* DNS_Mgr::LookupAddrInCache(const IPAddr& addr)
TableVal* DNS_Mgr::LookupNameInCache(string name)
{
DNS_Mapping* d = dns_mgr->host_mappings.Lookup(name.c_str());
if ( ! d || ! d->names )
HostMap::iterator it = dns_mgr->host_mappings.find(name);
if ( it == dns_mgr->host_mappings.end() )
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.Remove(&h);
delete d;
dns_mgr->host_mappings.erase(it);
delete d4;
delete d6;
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)
@ -951,10 +1035,15 @@ void DNS_Mgr::IssueAsyncRequests()
++num_requests;
DNS_Mgr_Request* dr;
DNS_Mgr_Request* dr6 = 0;
if ( req->IsAddrReq() )
dr = new DNS_Mgr_Request(req->host);
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) )
{
@ -964,6 +1053,14 @@ void DNS_Mgr::IssueAsyncRequests()
continue;
}
if ( dr6 && ! dr6->MakeRequest(nb_dns) )
{
reporter->Warning("can't issue DNS request");
++failed;
req->Timeout();
continue;
}
req->time = current_time();
asyncs_timeouts.push(req);
@ -1055,7 +1152,14 @@ void DNS_Mgr::Flush()
{
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();
}
@ -1099,6 +1203,14 @@ void DNS_Mgr::DoProcess(bool flush)
else if ( status > 0 )
{
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() )
{
AddResult(dr, &r);
@ -1108,7 +1220,7 @@ void DNS_Mgr::DoProcess(bool flush)
if ( ! dr->ReqHost() )
CheckAsyncAddrRequest(dr->ReqAddr(), true);
else
CheckAsyncHostRequest(dr->ReqHost(), true);
CheckAsyncHostRequest(dr->ReqHost(), do_host_timeout);
IssueAsyncRequests();
@ -1159,7 +1271,7 @@ void DNS_Mgr::GetStats(Stats* stats)
stats->successful = successful;
stats->failed = failed;
stats->pending = asyncs_pending;
stats->cached_hosts = host_mappings.Length();
stats->cached_hosts = host_mappings.size();
stats->cached_addresses = addr_mappings.Length();
}

View file

@ -6,6 +6,7 @@
#include <list>
#include <map>
#include <queue>
#include <utility>
#include "util.h"
#include "BroList.h"
@ -104,8 +105,10 @@ protected:
ListVal* AddrListDelta(ListVal* al1, ListVal* al2);
void DumpAddrList(FILE* f, ListVal* al);
typedef map<string, pair<DNS_Mapping*, DNS_Mapping*> > HostMap;
void LoadCache(FILE* f);
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
// is secs). Returns 0 on timeout, -1 on EINTR or other error, and 1
@ -133,7 +136,7 @@ protected:
PDict(ListVal) services;
PDict(DNS_Mapping) host_mappings;
HostMap host_mappings;
PDict(DNS_Mapping) addr_mappings;
DNS_mgr_request_list requests;