// 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