diff options
Diffstat (limited to 'external/unbound/testcode/testpkts.h')
-rw-r--r-- | external/unbound/testcode/testpkts.h | 268 |
1 files changed, 268 insertions, 0 deletions
diff --git a/external/unbound/testcode/testpkts.h b/external/unbound/testcode/testpkts.h new file mode 100644 index 000000000..864f33fee --- /dev/null +++ b/external/unbound/testcode/testpkts.h @@ -0,0 +1,268 @@ +/* + * testpkts. Data file parse for test packets, and query matching. + * + * Data storage for specially crafted replies for testing purposes. + * + * (c) NLnet Labs, 2005, 2006, 2007 + * See the file LICENSE for the license + */ + +#ifndef TESTPKTS_H +#define TESTPKTS_H +struct sldns_buffer; +struct sldns_file_parse_state; + +/** + * \file + * + * This is a debugging aid. It is not efficient, especially + * with a long config file, but it can give any reply to any query. + * This can help the developer pre-script replies for queries. + * + * You can specify a packet RR by RR with header flags to return. + * + * Missing features: + * - matching content different from reply content. + * - find way to adjust mangled packets? + * + */ + + /* + The data file format is as follows: + + ; comment. + ; a number of entries, these are processed first to last. + ; a line based format. + + $ORIGIN origin + $TTL default_ttl + + ENTRY_BEGIN + ; first give MATCH lines, that say what queries are matched + ; by this entry. + ; 'opcode' makes the query match the opcode from the reply + ; if you leave it out, any opcode matches this entry. + ; 'qtype' makes the query match the qtype from the reply + ; 'qname' makes the query match the qname from the reply + ; 'subdomain' makes the query match subdomains of qname from the reply + ; 'serial=1023' makes the query match if ixfr serial is 1023. + ; 'all' has to match header byte for byte and all rrs in packet. + ; 'ttl' used with all, rrs in packet must also have matching TTLs. + ; 'DO' will match only queries with DO bit set. + ; 'noedns' matches queries without EDNS OPT records. + MATCH [opcode] [qtype] [qname] [serial=<value>] [all] [ttl] + MATCH [UDP|TCP] DO + MATCH ... + ; Then the REPLY header is specified. + REPLY opcode, rcode or flags. + (opcode) QUERY IQUERY STATUS NOTIFY UPDATE + (rcode) NOERROR FORMERR SERVFAIL NXDOMAIN NOTIMPL YXDOMAIN + YXRRSET NXRRSET NOTAUTH NOTZONE + (flags) QR AA TC RD CD RA AD DO + REPLY ... + ; any additional actions to do. + ; 'copy_id' copies the ID from the query to the answer. + ADJUST copy_id + ; 'copy_query' copies the query name, type and class to the answer. + ADJUST copy_query + ; 'sleep=10' sleeps for 10 seconds before giving the answer (TCP is open) + ADJUST [sleep=<num>] ; sleep before giving any reply + ADJUST [packet_sleep=<num>] ; sleep before this packet in sequence + SECTION QUESTION + <RRs, one per line> ; the RRcount is determined automatically. + SECTION ANSWER + <RRs, one per line> + SECTION AUTHORITY + <RRs, one per line> + SECTION ADDITIONAL + <RRs, one per line> + EXTRA_PACKET ; follow with SECTION, REPLY for more packets. + HEX_ANSWER_BEGIN ; follow with hex data + ; this replaces any answer packet constructed + ; with the SECTION keywords (only SECTION QUERY + ; is used to match queries). If the data cannot + ; be parsed, ADJUST rules for the answer packet + ; are ignored. Only copy_id is done. + HEX_ANSWER_END + ENTRY_END + + + Example data file: +$ORIGIN nlnetlabs.nl +$TTL 3600 + +ENTRY_BEGIN +MATCH qname +REPLY NOERROR +ADJUST copy_id +SECTION QUESTION +www.nlnetlabs.nl. IN A +SECTION ANSWER +www.nlnetlabs.nl. IN A 195.169.215.155 +SECTION AUTHORITY +nlnetlabs.nl. IN NS www.nlnetlabs.nl. +ENTRY_END + +ENTRY_BEGIN +MATCH qname +REPLY NOERROR +ADJUST copy_id +SECTION QUESTION +www2.nlnetlabs.nl. IN A +HEX_ANSWER_BEGIN +; 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 +;-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- + 00 bf 81 80 00 01 00 01 00 02 00 02 03 77 77 77 0b 6b 61 6e ; 1- 20 + 61 72 69 65 70 69 65 74 03 63 6f 6d 00 00 01 00 01 03 77 77 ; 21- 40 + 77 0b 6b 61 6e 61 72 69 65 70 69 65 74 03 63 6f 6d 00 00 01 ; 41- 60 + 00 01 00 01 50 8b 00 04 52 5e ed 32 0b 6b 61 6e 61 72 69 65 ; 61- 80 + 70 69 65 74 03 63 6f 6d 00 00 02 00 01 00 01 50 8b 00 11 03 ; 81- 100 + 6e 73 31 08 68 65 78 6f 6e 2d 69 73 02 6e 6c 00 0b 6b 61 6e ; 101- 120 + 61 72 69 65 70 69 65 74 03 63 6f 6d 00 00 02 00 01 00 01 50 ; 121- 140 + 8b 00 11 03 6e 73 32 08 68 65 78 6f 6e 2d 69 73 02 6e 6c 00 ; 141- 160 + 03 6e 73 31 08 68 65 78 6f 6e 2d 69 73 02 6e 6c 00 00 01 00 ; 161- 180 + 01 00 00 46 53 00 04 52 5e ed 02 03 6e 73 32 08 68 65 78 6f ; 181- 200 + 6e 2d 69 73 02 6e 6c 00 00 01 00 01 00 00 46 53 00 04 d4 cc ; 201- 220 + db 5b +HEX_ANSWER_END +ENTRY_END + + + + note that this file will link with your + void verbose(int level, char* format, ...); output function. +*/ + +/** Type of transport, since some entries match based on UDP or TCP of query */ +enum transport_type {transport_any = 0, transport_udp, transport_tcp }; + +/** struct to keep a linked list of reply packets for a query */ +struct reply_packet { + /** next in list of reply packets, for TCP multiple pkts on wire */ + struct reply_packet* next; + /** the reply pkt */ + uint8_t* reply_pkt; + /** length of reply pkt */ + size_t reply_len; + /** or reply pkt in hex if not parsable */ + struct sldns_buffer* reply_from_hex; + /** seconds to sleep before giving packet */ + unsigned int packet_sleep; +}; + +/** data structure to keep the canned queries in. + format is the 'matching query' and the 'canned answer' */ +struct entry { + /* match */ + /* How to match an incoming query with this canned reply */ + /** match query opcode with answer opcode */ + uint8_t match_opcode; + /** match qtype with answer qtype */ + uint8_t match_qtype; + /** match qname with answer qname */ + uint8_t match_qname; + /** match qname as subdomain of answer qname */ + uint8_t match_subdomain; + /** match SOA serial number, from auth section */ + uint8_t match_serial; + /** match all of the packet */ + uint8_t match_all; + /** match ttls in the packet */ + uint8_t match_ttl; + /** match DO bit */ + uint8_t match_do; + /** match absence of EDNS OPT record in query */ + uint8_t match_noedns; + /** match query serial with this value. */ + uint32_t ixfr_soa_serial; + /** match on UDP/TCP */ + enum transport_type match_transport; + + /** pre canned reply */ + struct reply_packet *reply_list; + + /** how to adjust the reply packet */ + /** copy over the ID from the query into the answer */ + uint8_t copy_id; + /** copy the query nametypeclass from query into the answer */ + uint8_t copy_query; + /** in seconds */ + unsigned int sleeptime; + + /** some number that names this entry, line number in file or so */ + int lineno; + + /** next in list */ + struct entry* next; +}; + +/** + * reads the canned reply file and returns a list of structs + * does an exit on error. + * @param name: name of the file to read. + * @param skip_whitespace: skip leftside whitespace. + */ +struct entry* read_datafile(const char* name, int skip_whitespace); + +/** + * Delete linked list of entries. + */ +void delete_entry(struct entry* list); + +/** + * Read one entry from the data file. + * @param in: file to read from. Filepos must be at the start of a new line. + * @param name: name of the file for prettier errors. + * @param pstate: file parse state with lineno, default_ttl, + * oirigin and prev_rr name. + * @param skip_whitespace: skip leftside whitespace. + * @return: The entry read (malloced) or NULL if no entry could be read. + */ +struct entry* read_entry(FILE* in, const char* name, + struct sldns_file_parse_state* pstate, int skip_whitespace); + +/** + * finds entry in list, or returns NULL. + */ +struct entry* find_match(struct entry* entries, uint8_t* query_pkt, + size_t query_pkt_len, enum transport_type transport); + +/** + * match two packets, all must match + * @param q: packet 1 + * @param qlen: length of q. + * @param p: packet 2 + * @param plen: length of p. + * @param mttl: if true, ttls must match, if false, ttls do not need to match + * @param noloc: if true, rrs may be reordered in their packet-section. + * rrs are then matches without location of the rr being important. + * @return true if matched. + */ +int match_all(uint8_t* q, size_t qlen, uint8_t* p, size_t plen, int mttl, + int noloc); + +/** + * copy & adjust packet, mallocs a copy. + */ +void adjust_packet(struct entry* match, uint8_t** answer_pkt, + size_t* answer_pkt_len, uint8_t* query_pkt, size_t query_pkt_len); + +/** + * Parses data buffer to a query, finds the correct answer + * and calls the given function for every packet to send. + * if verbose_out filename is given, packets are dumped there. + * @param inbuf: the packet that came in + * @param inlen: length of packet. + * @param entries: entries read in from datafile. + * @param count: is increased to count number of queries answered. + * @param transport: set to UDP or TCP to match some types of entries. + * @param sendfunc: called to send answer (buffer, size, userarg). + * @param userdata: userarg to give to sendfunc. + * @param verbose_out: if not NULL, verbose messages are printed there. + */ +void handle_query(uint8_t* inbuf, ssize_t inlen, struct entry* entries, + int* count, enum transport_type transport, + void (*sendfunc)(uint8_t*, size_t, void*), void* userdata, + FILE* verbose_out); + +#endif /* TESTPKTS_H */ |