zeek/src/analyzer/protocol/dns/DNS.h

287 lines
8.3 KiB
C++

// See the file "COPYING" in the main distribution directory for copyright.
#ifndef ANALYZER_PROTOCOL_DNS_DNS_H
#define ANALYZER_PROTOCOL_DNS_DNS_H
#include "analyzer/protocol/tcp/TCP.h"
#include "binpac_bro.h"
namespace analyzer { namespace dns {
typedef enum {
DNS_OP_QUERY = 0, ///< standard query
DNS_OP_IQUERY = 1, ///< reverse query
// ### Is server status 2 or 3? RFC 1035 says it's 2
// DNS_OP_SERVER_STATUS = 3, ///< server status request
DNS_OP_SERVER_STATUS = 2, ///< server status request
// Netbios operations (query = 0).
NETBIOS_REGISTRATION = 5,
NETBIOS_RELEASE = 6,
NETBIOS_WACK = 7, // wait for ACK
NETBIOS_REFRESH = 8,
} DNS_Opcode;
typedef enum {
DNS_CODE_OK = 0, ///< no error
DNS_CODE_FORMAT_ERR = 1, ///< format error
DNS_CODE_SERVER_FAIL = 2, ///< server failure
DNS_CODE_NAME_ERR = 3, ///< no such domain
DNS_CODE_NOT_IMPL = 4, ///< not implemented
DNS_CODE_REFUSED = 5, ///< refused
} DNS_Code;
typedef enum {
TYPE_A = 1, ///< host address
TYPE_NS = 2, ///< authoritative name server
TYPE_CNAME = 5, ///< canonical name
TYPE_SOA = 6, ///< start of authority
TYPE_WKS = 11, ///< well known service
TYPE_PTR = 12, ///< domain name pointer
TYPE_HINFO = 13, ///< host information
TYPE_MX = 15, ///< mail routing information
TYPE_TXT = 16, ///< text strings
TYPE_SIG = 24, ///< digital signature (RFC 2535)
TYPE_KEY = 25, ///< public key (RFC 2535)
TYPE_PX = 26, ///< pointer to X.400/RFC822 mapping info (RFC 1664)
TYPE_AAAA = 28, ///< IPv6 address (RFC 1886
TYPE_NBS = 32, ///< Netbios name (RFC 1002)
TYPE_SRV = 33, ///< service location (RFC 2052)
TYPE_NAPTR = 35, ///< naming authority pointer (RFC 2168)
TYPE_KX = 36, ///< Key Exchange (RFC 2230)
TYPE_CERT = 37, ///< Certificate (RFC 2538)
TYPE_A6 = 38, ///< IPv6 address with indirection (RFC 2874)
TYPE_DNAME = 39, ///< Non-terminal DNS name redirection (RFC 2672)
TYPE_EDNS = 41, ///< OPT pseudo-RR (RFC 2671)
TYPE_TKEY = 249, ///< Transaction Key (RFC 2930)
TYPE_TSIG = 250, ///< Transaction Signature (RFC 2845)
// The following are only valid in queries.
TYPE_AXFR = 252,
TYPE_ALL = 255,
TYPE_WINS = 65281, ///< Microsoft's WINS RR
TYPE_WINSR = 65282, ///< Microsoft's WINS-R RR
} RR_Type;
#define DNS_CLASS_IN 1
#define DNS_CLASS_ANY 255
typedef enum {
DNS_QUESTION,
DNS_ANSWER,
DNS_AUTHORITY,
DNS_ADDITIONAL,
} DNS_AnswerType;
struct DNS_RawMsgHdr {
unsigned short id;
unsigned short flags;
unsigned short qdcount;
unsigned short ancount;
unsigned short nscount;
unsigned short arcount;
};
struct EDNS_ADDITIONAL { // size
unsigned short name; // -
unsigned short type; // 16 : ExtractShort(data, len)
unsigned short payload_size; // 16
unsigned short extended_rcode; // 8
unsigned short version; // 8
unsigned short z; // 16
unsigned short rdata_len; // 16
};
struct TSIG_DATA {
BroString* alg_name;
unsigned long time_s;
unsigned short time_ms;
BroString* sig;
unsigned short fudge;
unsigned short orig_id;
unsigned short rr_error;
};
class DNS_MsgInfo {
public:
DNS_MsgInfo(DNS_RawMsgHdr* hdr, int is_query);
~DNS_MsgInfo();
Val* BuildHdrVal();
Val* BuildAnswerVal();
Val* BuildEDNS_Val();
Val* BuildTSIG_Val();
int id;
int opcode; ///< query type, see DNS_Opcode
int rcode; ///< return code, see DNS_Code
int QR; ///< query record flag
int AA; ///< authoritiave answer flag
int TC; ///< truncated - size > 512 bytes for udp
int RD; ///< recursion desired
int RA; ///< recursion available
int Z; ///< zero - this 3 bit field *must* be zero
int qdcount; ///< number of questions
int ancount; ///< number of answers
int nscount; ///< number of authority RRs
int arcount; ///< number of additional RRs
int is_query; ///< whether it came from the session initiator
StringVal* query_name;
RR_Type atype;
int aclass; ///< normally = 1, inet
int ttl;
DNS_AnswerType answer_type;
int skip_event; ///< if true, don't generate corresponding events
// int answer_count; ///< count of responders. if >1 and not
///< identical answer, there may be problems
// uint32* addr; ///< cache value to pass back results
///< for forward lookups
// More values for spesific DNS types.
// struct EDNS_ADDITIONAL* edns;
struct TSIG_DATA* tsig;
};
class DNS_Interpreter {
public:
DNS_Interpreter(analyzer::Analyzer* analyzer);
int ParseMessage(const u_char* data, int len, int is_query);
void Timeout() { }
protected:
int EndMessage(DNS_MsgInfo* msg);
int ParseQuestions(DNS_MsgInfo* msg,
const u_char*& data, int& len,
const u_char* start);
int ParseAnswers(DNS_MsgInfo* msg, int n, DNS_AnswerType answer_type,
const u_char*& data, int& len,
const u_char* start);
int ParseQuestion(DNS_MsgInfo* msg,
const u_char*& data, int& len, const u_char* start);
int ParseAnswer(DNS_MsgInfo* msg,
const u_char*& data, int& len, const u_char* start);
u_char* ExtractName(const u_char*& data, int& len,
u_char* label, int label_len,
const u_char* msg_start);
int ExtractLabel(const u_char*& data, int& len,
u_char*& label, int& label_len,
const u_char* msg_start);
uint16 ExtractShort(const u_char*& data, int& len);
uint32 ExtractLong(const u_char*& data, int& len);
void ExtractOctets(const u_char*& data, int& len, BroString** p);
int ParseRR_Name(DNS_MsgInfo* msg,
const u_char*& data, int& len, int rdlength,
const u_char* msg_start);
int ParseRR_SOA(DNS_MsgInfo* msg,
const u_char*& data, int& len, int rdlength,
const u_char* msg_start);
int ParseRR_MX(DNS_MsgInfo* msg,
const u_char*& data, int& len, int rdlength,
const u_char* msg_start);
int ParseRR_NBS(DNS_MsgInfo* msg,
const u_char*& data, int& len, int rdlength,
const u_char* msg_start);
int ParseRR_SRV(DNS_MsgInfo* msg,
const u_char*& data, int& len, int rdlength,
const u_char* msg_start);
int ParseRR_EDNS(DNS_MsgInfo* msg,
const u_char*& data, int& len, int rdlength,
const u_char* msg_start);
int ParseRR_A(DNS_MsgInfo* msg,
const u_char*& data, int& len, int rdlength);
int ParseRR_AAAA(DNS_MsgInfo* msg,
const u_char*& data, int& len, int rdlength);
int ParseRR_WKS(DNS_MsgInfo* msg,
const u_char*& data, int& len, int rdlength);
int ParseRR_HINFO(DNS_MsgInfo* msg,
const u_char*& data, int& len, int rdlength);
int ParseRR_TXT(DNS_MsgInfo* msg,
const u_char*& data, int& len, int rdlength,
const u_char* msg_start);
int ParseRR_TSIG(DNS_MsgInfo* msg,
const u_char*& data, int& len, int rdlength,
const u_char* msg_start);
void SendReplyOrRejectEvent(DNS_MsgInfo* msg, EventHandlerPtr event,
const u_char*& data, int& len,
BroString* question_name);
analyzer::Analyzer* analyzer;
bool first_message;
};
typedef enum {
DNS_LEN_HI, ///< looking for the high-order byte of the length
DNS_LEN_LO, ///< looking for the low-order byte of the length
DNS_MESSAGE_BUFFER, ///< building up the message in the buffer
} TCP_DNS_state;
// Support analyzer which chunks the TCP stream into "packets".
// ### This should be merged with TCP_Contents_RPC.
class Contents_DNS : public tcp::TCP_SupportAnalyzer {
public:
Contents_DNS(Connection* c, bool orig, DNS_Interpreter* interp);
~Contents_DNS();
void Flush(); ///< process any partially-received data
TCP_DNS_state State() const { return state; }
protected:
virtual void DeliverStream(int len, const u_char* data, bool orig);
DNS_Interpreter* interp;
u_char* msg_buf;
int buf_n; ///< number of bytes in msg_buf
int buf_len; ///< size of msg_buf
int msg_size; ///< expected size of message
TCP_DNS_state state;
};
// Works for both TCP and UDP.
class DNS_Analyzer : public tcp::TCP_ApplicationAnalyzer {
public:
DNS_Analyzer(Connection* conn);
~DNS_Analyzer();
virtual void DeliverPacket(int len, const u_char* data, bool orig,
uint64 seq, const IP_Hdr* ip, int caplen);
virtual void Init();
virtual void Done();
virtual void ConnectionClosed(tcp::TCP_Endpoint* endpoint,
tcp::TCP_Endpoint* peer, int gen_event);
void ExpireTimer(double t);
static analyzer::Analyzer* Instantiate(Connection* conn)
{ return new DNS_Analyzer(conn); }
protected:
DNS_Interpreter* interp;
Contents_DNS* contents_dns_orig;
Contents_DNS* contents_dns_resp;
int did_session_done;
};
// FIXME: Doesn't really fit into new analyzer structure. What to do?
int IsReuse(double t, const u_char* pkt);
} } // namespace analyzer::*
#endif