Correlate DNS request/response with TCP/UDP connections

Is there a good way to correlate DNS requests/responses with subsequent TCP/UDP connections using Bro (in realtime)? With how my tap is configured I can see the client’s DNS request/response and all their traffic. I want to be able to combine their DNS request (if there is one) with the corresponding TCP/UDP following it. For my use case I need this to be done in realtime (not later by simply doing a JOIN). So, I am interested in a single log entry with DNS request/response AND connection info.

It seems like this should be possible by basically doing the following:

dns_response.dst_ip == conn.src_ip AND
conn.dst_ip == dns_response.answer_ip AND
(conn.timestamp - dns_response.timestamp) < THRESHOLD

Has anyone done this? Any guidance would be greatly appreciated.

Thanks,

–Jason

Are you running a cluster? This type of problem is one of the hardest to solve on distributed analysis.

Otherwise if you are running a single node then it should be fairly easy. I *think* you would essentially want to create a 2-tuple set with a short timeout.

global watch_for_connections: set[addr, addr] = {} &create_timeout=2secs;

You would fill out that set in one or more DNS event handlers and then check to see if any connections are being made in a connection_established handler.

Again though, if you are running a cluster this is a really hard problem.

  .Seth

I think Seth meant &create_expire. But yeah, this is totally possible if you’re running a single node/standalone mode. You could also use something like

type DNSqr record {

query: string;

asking_host: addr;

};
dns_query_cache: table[addr] of DNSqr &create_expire=2secs;

where the dns_query_cache is indexed by answer addresses (the a value in dns_A_reply events).

-AK