diff --git a/src/network.c b/src/network.c index 76a645d..6e969c8 100644 --- a/src/network.c +++ b/src/network.c @@ -460,6 +460,143 @@ void dl_pkt(u_char* user, const struct pcap_pkthdr* hdr, const u_char* pkt, cons main_exit = TRUE; } +/* + * Determine if packet should be filtered based on query type + * return values: -1 error + * 0 don't filter + * 1 filter + * for non-zero return status, reason should be set to a + * static string. + */ +static int +_filter_by_qtype(const ldns_pkt* lpkt, char** reason) +{ + ldns_rr_list* rrs = ldns_pkt_question(lpkt); + if (!rrs) { + *reason = "failed to get list of questions"; + return -1; + } + /* Look at each RR in the section (or each QNAME in + the question section). */ + size_t i, n; + for (i = 0, n = ldns_rr_list_rr_count(rrs); i < n; i++) { + ldns_rr* rr = ldns_rr_list_rr(rrs, i); + if (!rr) { + *reason = "failed to get question"; + return -1; + } + if (match_qtype && ldns_rr_get_type(rr) == match_qtype) { + if (dumptrace >= 2) + fprintf(stderr, "Packet query type %u matches filter on type == %u\n", ldns_rr_get_type(rr), match_qtype); + return 0; + } else if (nmatch_qtype && ldns_rr_get_type(rr) == nmatch_qtype) { + if (dumptrace >= 2) + fprintf(stderr, "Packet query type %u matches filter on type != %u\n", ldns_rr_get_type(rr), nmatch_qtype); + *reason = "matched unwanted qtype"; + return 1; + } + } + if (match_qtype) { + *reason = "didn't match wanted qtype"; + return 1; // didn't match any question RRs + } + return 0; +} + +/* + * Determine if packet should be filtered based on query name + * return values: -1 error + * 0 don't filter + * 1 filter + * for non-zero return status, reason should be set to a + * static string. + */ +static int +_filter_by_qname(const ldns_pkt* lpkt, char** reason) +{ + int match = -1; + int negmatch = -1; + ldns_buffer* buf = ldns_buffer_new(512); + if (!buf) { + fprintf(stderr, "%s: out of memory", ProgramName); + exit(1); + } + + /* Look at each section of the message: + question, answer, authority, additional */ + ldns_rr_list* rrs = ldns_pkt_all(lpkt); + if (!rrs) { + ldns_buffer_free(buf); + *reason = "failed to get list of RRs"; + return -1; + } + + /* + * Initialize matching counters + */ + myregex_ptr myregex; + for (myregex = HEAD(myregexes); myregex != NULL; myregex = NEXT(myregex, link)) { + if (myregex->not) { + negmatch = 0; + } else { + match = 0; + } + } + + /* Look at each RR in the section (or each QNAME in + the question section). */ + size_t i, n; + for (i = 0, n = ldns_rr_list_rr_count(rrs); i < n; i++) { + ldns_rr* rr = ldns_rr_list_rr(rrs, i); + if (!rr) { + ldns_rr_list_deep_free(rrs); + ldns_buffer_free(buf); + *reason = "failed to get RR"; + return -1; + } + + ldns_buffer_clear(buf); + if (ldns_rdf2buffer_str(buf, ldns_rr_owner(rr)) != LDNS_STATUS_OK) { + ldns_rr_list_deep_free(rrs); + ldns_buffer_free(buf); + *reason = "failed to get RR"; + return -1; + } + + for (myregex = HEAD(myregexes); + myregex != NULL; + myregex = NEXT(myregex, link)) { + + if (regexec(&myregex->reg, (char*)ldns_buffer_begin(buf), 0, NULL, 0) == 0) { + if (myregex->not) + negmatch++; + else + match++; + + if (dumptrace >= 2) + fprintf(stderr, + "; \"%s\" %s~ /%s/ %d %d\n", + (char*)ldns_buffer_begin(buf), + myregex->not ? "!" : "", + myregex->str, + match, + negmatch); + } + } + } + ldns_rr_list_deep_free(rrs); + ldns_buffer_free(buf); + + /* + * Fail if any negative matches or if no positive matches + */ + if (negmatch > 0 || match == 0) { + *reason = "failed regex match"; + return 1; + } + return 0; +} + void network_pkt2(const char* descr, my_bpftimeval ts, const pcap_thread_packet_t* packet, const u_char* payload, size_t length) { u_char pkt_copy[SNAPLEN], *pkt = pkt_copy; @@ -471,7 +608,6 @@ void network_pkt2(const char* descr, my_bpftimeval ts, const pcap_thread_packet_ tcpstate_ptr tcpstate = NULL; size_t len, dnslen = 0; HEADER dns; - ldns_pkt* lpkt = 0; /* Make a writable copy of the packet and use that copy from now on. */ if (length > SNAPLEN) @@ -889,6 +1025,7 @@ void network_pkt2(const char* descr, my_bpftimeval ts, const pcap_thread_packet_ } } if (!EMPTY(myregexes) || match_qtype || nmatch_qtype) { + ldns_pkt* lpkt = 0; if (ldns_wire2pkt(&lpkt, dnspkt, dnslen) != LDNS_STATUS_OK) { /* DNS message may have padding, try get actual size */ size_t dnslen2 = calcdnslen(dnspkt, dnslen); @@ -902,121 +1039,17 @@ void network_pkt2(const char* descr, my_bpftimeval ts, const pcap_thread_packet_ return; } } - } - if (match_qtype || nmatch_qtype) { - ldns_rr_list* rrs = ldns_pkt_question(lpkt); - if (!rrs) { - ldns_pkt_free(lpkt); - tcpstate_discard(tcpstate, "failed to get list of questions"); - return; - } - /* Look at each RR in the section (or each QNAME in - the question section). */ - size_t i, n; - for (i = 0, n = ldns_rr_list_rr_count(rrs); i < n; i++) { - ldns_rr* rr = ldns_rr_list_rr(rrs, i); - if (!rr) { - ldns_pkt_free(lpkt); - tcpstate_discard(tcpstate, "failed to get question"); - return; - } - - if (match_qtype && ldns_rr_get_type(rr) != match_qtype) { - ldns_pkt_free(lpkt); - tcpstate_discard(tcpstate, "qtype not match"); - return; - } else if (nmatch_qtype && ldns_rr_get_type(rr) == nmatch_qtype) { - ldns_pkt_free(lpkt); - tcpstate_discard(tcpstate, "!qtype match"); - return; - } - } - } - if (!EMPTY(myregexes)) { - int match, negmatch; - ldns_buffer* buf = ldns_buffer_new(512); - - if (!buf) { - fprintf(stderr, "%s: out of memory", ProgramName); - exit(1); - } - - match = -1; - negmatch = -1; - /* Look at each section of the message: - question, answer, authority, additional */ - ldns_rr_list* rrs = ldns_pkt_all(lpkt); - if (!rrs) { + char* reason = 0; + if ((match_qtype || nmatch_qtype) && _filter_by_qtype(lpkt, &reason)) { ldns_pkt_free(lpkt); - ldns_buffer_free(buf); - tcpstate_discard(tcpstate, "failed to get list of RRs"); + tcpstate_discard(tcpstate, reason); return; } - /* Look at each RR in the section (or each QNAME in - the question section). */ - size_t i, n; - for (i = 0, n = ldns_rr_list_rr_count(rrs); i < n; i++) { - ldns_rr* rr = ldns_rr_list_rr(rrs, i); - if (!rr) { - ldns_rr_list_deep_free(rrs); - ldns_pkt_free(lpkt); - ldns_buffer_free(buf); - tcpstate_discard(tcpstate, "failed to get RR"); - return; - } - - ldns_buffer_clear(buf); - if (ldns_rdf2buffer_str(buf, ldns_rr_owner(rr)) != LDNS_STATUS_OK) { - ldns_rr_list_deep_free(rrs); - ldns_pkt_free(lpkt); - ldns_buffer_free(buf); - tcpstate_discard(tcpstate, "failed to get RR"); - return; - } - - myregex_ptr myregex; - for (myregex = HEAD(myregexes); - myregex != NULL; - myregex = NEXT(myregex, link)) { - if (myregex->not ) { - if (negmatch < 0) - negmatch = 0; - } else { - if (match < 0) - match = 0; - } - - if (regexec(&myregex->reg, (char*)ldns_buffer_begin(buf), 0, NULL, 0) == 0) { - if (myregex->not ) - negmatch++; - else - match++; - - if (dumptrace >= 2) - fprintf(stderr, - "; \"%s\" %s~ /%s/ %d %d\n", - (char*)ldns_buffer_begin(buf), - myregex->not ? "!" : "", - myregex->str, - match, - negmatch); - } - } - } - ldns_rr_list_deep_free(rrs); - ldns_buffer_free(buf); - - /* - * Fail if any negative matching or if no match, match can be -1 which - * indicates that there are only negative matching - */ - if (negmatch > 0 || match == 0) { + if (!EMPTY(myregexes) && _filter_by_qname(lpkt, &reason)) { ldns_pkt_free(lpkt); - tcpstate_discard(tcpstate, "failed regex match"); + tcpstate_discard(tcpstate, reason); return; } - } - if (lpkt) { ldns_pkt_free(lpkt); } @@ -1053,7 +1086,6 @@ void network_pkt(const char* descr, my_bpftimeval ts, unsigned pf, struct ip* ip; size_t len, dnslen = 0; HEADER dns; - ldns_pkt* lpkt = 0; if (dumptrace >= 4) fprintf(stderr, "processing %s packet: len=%zu\n", (pf == PF_INET ? "IPv4" : (pf == PF_INET6 ? "IPv6" : "unknown")), olen); @@ -1559,6 +1591,7 @@ void network_pkt(const char* descr, my_bpftimeval ts, unsigned pf, } } if (!EMPTY(myregexes) || match_qtype || nmatch_qtype) { + ldns_pkt* lpkt = 0; if (ldns_wire2pkt(&lpkt, dnspkt, dnslen) != LDNS_STATUS_OK) { /* DNS message may have padding, try get actual size */ size_t dnslen2 = calcdnslen(dnspkt, dnslen); @@ -1572,111 +1605,16 @@ void network_pkt(const char* descr, my_bpftimeval ts, unsigned pf, goto network_pkt_end; } } - } - if (match_qtype || nmatch_qtype) { - ldns_rr_list* rrs = ldns_pkt_question(lpkt); - if (!rrs) { - tcpstate_discard(tcpstate, "failed to get list of questions"); - goto network_pkt_end; - } - /* Look at each RR in the section (or each QNAME in - the question section). */ - size_t i, n; - for (i = 0, n = ldns_rr_list_rr_count(rrs); i < n; i++) { - ldns_rr* rr = ldns_rr_list_rr(rrs, i); - if (!rr) { - tcpstate_discard(tcpstate, "failed to get question"); - goto network_pkt_end; - } - - if (match_qtype && ldns_rr_get_type(rr) != match_qtype) { - tcpstate_discard(tcpstate, "qtype not match"); - goto network_pkt_end; - } else if (nmatch_qtype && ldns_rr_get_type(rr) == nmatch_qtype) { - tcpstate_discard(tcpstate, "!qtype match"); - goto network_pkt_end; - } - } - } - if (!EMPTY(myregexes)) { - int match, negmatch; - ldns_buffer* buf = ldns_buffer_new(512); - - if (!buf) { - fprintf(stderr, "%s: out of memory", ProgramName); - exit(1); - } - - match = -1; - negmatch = -1; - /* Look at each section of the message: - question, answer, authority, additional */ - ldns_rr_list* rrs = ldns_pkt_all(lpkt); - if (!rrs) { - ldns_buffer_free(buf); - tcpstate_discard(tcpstate, "failed to get list of RRs"); + char* reason = 0; + if ((match_qtype || nmatch_qtype) && _filter_by_qtype(lpkt, &reason)) { + tcpstate_discard(tcpstate, reason); goto network_pkt_end; } - /* Look at each RR in the section (or each QNAME in - the question section). */ - size_t i, n; - for (i = 0, n = ldns_rr_list_rr_count(rrs); i < n; i++) { - ldns_rr* rr = ldns_rr_list_rr(rrs, i); - if (!rr) { - ldns_rr_list_deep_free(rrs); - ldns_buffer_free(buf); - tcpstate_discard(tcpstate, "failed to get RR"); - goto network_pkt_end; - } - - ldns_buffer_clear(buf); - if (ldns_rdf2buffer_str(buf, ldns_rr_owner(rr)) != LDNS_STATUS_OK) { - ldns_rr_list_deep_free(rrs); - ldns_buffer_free(buf); - tcpstate_discard(tcpstate, "failed to get RR"); - goto network_pkt_end; - } - - myregex_ptr myregex; - for (myregex = HEAD(myregexes); - myregex != NULL; - myregex = NEXT(myregex, link)) { - if (myregex->not ) { - if (negmatch < 0) - negmatch = 0; - } else { - if (match < 0) - match = 0; - } - - if (regexec(&myregex->reg, (char*)ldns_buffer_begin(buf), 0, NULL, 0) == 0) { - if (myregex->not ) - negmatch++; - else - match++; - - if (dumptrace >= 2) - fprintf(stderr, - "; \"%s\" %s~ /%s/ %d %d\n", - (char*)ldns_buffer_begin(buf), - myregex->not ? "!" : "", - myregex->str, - match, - negmatch); - } - } - } - ldns_rr_list_deep_free(rrs); - ldns_buffer_free(buf); - - /* - * Fail if any negative matching or if no match, match can be -1 which - * indicates that there are only negative matching - */ - if (negmatch > 0 || match == 0) { - tcpstate_discard(tcpstate, "failed regex match"); + if (!EMPTY(myregexes) && _filter_by_qname(lpkt, &reason)) { + tcpstate_discard(tcpstate, reason); goto network_pkt_end; } + ldns_pkt_free(lpkt); } /* Policy hiding. */ @@ -1754,9 +1692,6 @@ void network_pkt(const char* descr, my_bpftimeval ts, unsigned pf, network_pkt_end: network_ip = 0; network_ipv6 = 0; - if (lpkt) { - ldns_pkt_free(lpkt); - } } uint16_t in_checksum(const u_char* ptr, size_t len)