/*! \brief Return RR count for given section (from wire xxCOUNT in header). */ static uint16_t pkt_rr_wirecount(knot_pkt_t *pkt, knot_section_t section_id) { assert(pkt); switch (section_id) { case KNOT_ANSWER: return knot_wire_get_ancount(pkt->wire); case KNOT_AUTHORITY: return knot_wire_get_nscount(pkt->wire); case KNOT_ADDITIONAL: return knot_wire_get_arcount(pkt->wire); default: assert(0); return 0; } }
/* @note Packet equivalence test, 5 checks. */ static void packet_match(knot_pkt_t *in, knot_pkt_t *out) { /* Check counts */ is_int(knot_wire_get_qdcount(out->wire), knot_wire_get_qdcount(in->wire), "pkt: QD match"); is_int(knot_wire_get_ancount(out->wire), knot_wire_get_ancount(in->wire), "pkt: AN match"); is_int(knot_wire_get_nscount(out->wire), knot_wire_get_nscount(in->wire), "pkt: NS match"); is_int(knot_wire_get_arcount(out->wire), knot_wire_get_arcount(in->wire), "pkt: AR match"); /* Check RRs */ int rr_matched = 0; for (unsigned i = 0; i < NAMECOUNT; ++i) { if (knot_rrset_equal(&out->rr[i], &in->rr[i], KNOT_RRSET_COMPARE_WHOLE) > 0) { ++rr_matched; } } is_int(NAMECOUNT, rr_matched, "pkt: RR content match"); }
static int rosedb_synth(knot_pkt_t *pkt, const knot_dname_t *key, struct iter *it, struct query_data *qdata) { struct entry entry; int ret = KNOT_EOK; uint16_t qtype = knot_pkt_qtype(qdata->query); /* Answer section. */ while (ret == KNOT_EOK) { if (cache_iter_val(it, &entry) == 0) { ret = rosedb_synth_rr(pkt, &entry, qtype); } if (cache_iter_next(it) != 0) { break; } } /* Authority section. */ knot_pkt_begin(pkt, KNOT_AUTHORITY); /* Not found (zone cut if records exist). */ ret = cache_iter_begin(it, key); while (ret == KNOT_EOK) { if (cache_iter_val(it, &entry) == 0) { ret = rosedb_synth_rr(pkt, &entry, KNOT_RRTYPE_NS); ret = rosedb_synth_rr(pkt, &entry, KNOT_RRTYPE_SOA); } if (cache_iter_next(it) != 0) { break; } } /* Our response is authoritative. */ if (knot_wire_get_nscount(pkt->wire) > 0) { knot_wire_set_aa(pkt->wire); if (knot_wire_get_ancount(pkt->wire) == 0) { qdata->rcode = KNOT_RCODE_NXDOMAIN; } } /* Send message to syslog. */ struct sockaddr_storage syslog_addr; if (sockaddr_set(&syslog_addr, AF_INET, entry.syslog_ip, DEFAULT_PORT) == KNOT_EOK) { int sock = net_unbound_socket(AF_INET, &syslog_addr); if (sock > 0) { rosedb_send_log(sock, (struct sockaddr *)&syslog_addr, pkt, entry.threat_code, qdata); close(sock); } } return ret; }
static uint8_t rrl_clsid(rrl_req_t *p) { /* Check error code */ int ret = CLS_NULL; switch (knot_wire_get_rcode(p->w)) { case KNOT_RCODE_NOERROR: ret = CLS_NORMAL; break; case KNOT_RCODE_NXDOMAIN: return CLS_NXDOMAIN; break; default: return CLS_ERROR; break; } /* Check if answered from a qname */ if (ret == CLS_NORMAL && p->flags & RRL_WILDCARD) { return CLS_WILDCARD; } /* Check query type for spec. classes. */ if (p->query) { switch(knot_pkt_qtype(p->query)) { case KNOT_RRTYPE_ANY: /* ANY spec. class */ return CLS_ANY; break; case KNOT_RRTYPE_DNSKEY: case KNOT_RRTYPE_RRSIG: case KNOT_RRTYPE_DS: /* DNSSEC-related RR class. */ return CLS_DNSSEC; break; default: break; } } /* Check packet size for threshold. */ if (p->len >= RRL_PSIZE_LARGE) { return CLS_LARGE; } /* Check ancount */ if (knot_wire_get_ancount(p->w) == 0) { return CLS_EMPTY; } return ret; }
_public_ int knot_pkt_parse_payload(knot_pkt_t *pkt, unsigned flags) { if (pkt == NULL) { return KNOT_EINVAL; } assert(pkt->wire != NULL); assert(pkt->size > 0); /* Reserve memory in advance to avoid resizing. */ size_t rr_count = knot_wire_get_ancount(pkt->wire) + knot_wire_get_nscount(pkt->wire) + knot_wire_get_arcount(pkt->wire); int ret = pkt_rr_array_alloc(pkt, rr_count); if (ret != KNOT_EOK) { return ret; } for (knot_section_t i = KNOT_ANSWER; i <= KNOT_ADDITIONAL; ++i) { ret = knot_pkt_begin(pkt, i); if (ret != KNOT_EOK) { return ret; } ret = knot_pkt_parse_section(pkt, flags); if (ret != KNOT_EOK) { return ret; } } /* TSIG must be last record of AR if present. */ const knot_pktsection_t *ar = knot_pkt_section(pkt, KNOT_ADDITIONAL); if (pkt->tsig_rr != NULL) { const knot_rrset_t *last_rr = knot_pkt_rr(ar, ar->count - 1); if (ar->count > 0 && pkt->tsig_rr->rrs.data != last_rr->rrs.data) { return KNOT_EMALF; } } /* Check for trailing garbage. */ if (pkt->parsed < pkt->size) { return KNOT_EMALF; } return KNOT_EOK; }
void print_packet(const knot_pkt_t *packet, const net_t *net, const size_t size, const float elapsed, const time_t exec_time, const bool incoming, const style_t *style) { if (packet == NULL || style == NULL) { DBG_NULL; return; } const knot_pktsection_t *answers = knot_pkt_section(packet, KNOT_ANSWER); const knot_pktsection_t *authority = knot_pkt_section(packet, KNOT_AUTHORITY); const knot_pktsection_t *additional = knot_pkt_section(packet, KNOT_ADDITIONAL); uint16_t qdcount = knot_wire_get_qdcount(packet->wire); uint16_t ancount = knot_wire_get_ancount(packet->wire); uint16_t nscount = knot_wire_get_nscount(packet->wire); uint16_t arcount = knot_wire_get_arcount(packet->wire); // Get Extended RCODE from the packet. uint16_t rcode = knot_pkt_get_ext_rcode(packet); // Disable additionals printing if there are no other records. // OPT record may be placed anywhere within additionals! if (knot_pkt_has_edns(packet) && arcount == 1) { arcount = 0; } // Print packet information header. if (style->show_header) { print_header(packet, style, rcode); } // Print EDNS section. if (style->show_edns && knot_pkt_has_edns(packet)) { printf("\n;; EDNS PSEUDOSECTION:\n;; "); print_section_opt(packet->opt_rr, knot_wire_get_rcode(packet->wire)); } // Print DNS sections. switch (style->format) { case FORMAT_DIG: if (ancount > 0) { print_section_dig(knot_pkt_rr(answers, 0), ancount, style); } break; case FORMAT_HOST: if (ancount > 0) { print_section_host(knot_pkt_rr(answers, 0), ancount, style); } else { print_error_host(rcode, packet, style); } break; case FORMAT_NSUPDATE: if (style->show_question && qdcount > 0) { printf("\n;; ZONE SECTION:\n;; "); print_section_question(knot_pkt_qname(packet), knot_pkt_qclass(packet), knot_pkt_qtype(packet), style); } if (style->show_answer && ancount > 0) { printf("\n;; PREREQUISITE SECTION:\n"); print_section_full(knot_pkt_rr(answers, 0), ancount, style, true); } if (style->show_authority && nscount > 0) { printf("\n;; UPDATE SECTION:\n"); print_section_full(knot_pkt_rr(authority, 0), nscount, style, true); } if (style->show_additional && arcount > 0) { printf("\n;; ADDITIONAL DATA:\n"); print_section_full(knot_pkt_rr(additional, 0), arcount, style, true); } break; case FORMAT_FULL: if (style->show_question && qdcount > 0) { printf("\n;; QUESTION SECTION:\n;; "); print_section_question(knot_pkt_qname(packet), knot_pkt_qclass(packet), knot_pkt_qtype(packet), style); } if (style->show_answer && ancount > 0) { printf("\n;; ANSWER SECTION:\n"); print_section_full(knot_pkt_rr(answers, 0), ancount, style, true); } if (style->show_authority && nscount > 0) { printf("\n;; AUTHORITY SECTION:\n"); print_section_full(knot_pkt_rr(authority, 0), nscount, style, true); } if (style->show_additional && arcount > 0) { printf("\n;; ADDITIONAL SECTION:\n"); print_section_full(knot_pkt_rr(additional, 0), arcount, style, true); } break; default: break; } // Print TSIG section. if (style->show_tsig && knot_pkt_has_tsig(packet)) { printf("\n;; TSIG PSEUDOSECTION:\n"); print_section_full(packet->tsig_rr, 1, style, false); } // Print packet statistics. if (style->show_footer) { printf("\n"); print_footer(size, 0, 0, net, elapsed, exec_time, incoming); } }
static void print_header(const knot_pkt_t *packet, const style_t *style, const uint16_t ext_rcode) { char flags[64] = ""; uint8_t opcode_id; const char *rcode_str = "Unknown"; const char *opcode_str = "Unknown"; lookup_table_t *rcode, *opcode; // Get RCODE from Header and check for Extended RCODE from OPT RR. rcode = lookup_by_id(knot_rcode_names, ext_rcode); if (rcode != NULL) { rcode_str = rcode->name; } // Get OPCODE. opcode_id = knot_wire_get_opcode(packet->wire); opcode = lookup_by_id(knot_opcode_names, opcode_id); if (opcode != NULL) { opcode_str = opcode->name; } // Get flags. size_t flags_rest = sizeof(flags); const size_t flag_len = 4; if (knot_wire_get_qr(packet->wire) != 0 && flags_rest > flag_len) { flags_rest -= strlcat(flags, " qr", flags_rest); } if (knot_wire_get_aa(packet->wire) != 0 && flags_rest > flag_len) { flags_rest -= strlcat(flags, " aa", flags_rest); } if (knot_wire_get_tc(packet->wire) != 0 && flags_rest > flag_len) { flags_rest -= strlcat(flags, " tc", flags_rest); } if (knot_wire_get_rd(packet->wire) != 0 && flags_rest > flag_len) { flags_rest -= strlcat(flags, " rd", flags_rest); } if (knot_wire_get_ra(packet->wire) != 0 && flags_rest > flag_len) { flags_rest -= strlcat(flags, " ra", flags_rest); } if (knot_wire_get_z(packet->wire) != 0 && flags_rest > flag_len) { flags_rest -= strlcat(flags, " z", flags_rest); } if (knot_wire_get_ad(packet->wire) != 0 && flags_rest > flag_len) { flags_rest -= strlcat(flags, " ad", flags_rest); } if (knot_wire_get_cd(packet->wire) != 0 && flags_rest > flag_len) { strlcat(flags, " cd", flags_rest); } uint16_t id = knot_wire_get_id(packet->wire); uint16_t qdcount = knot_wire_get_qdcount(packet->wire); uint16_t ancount = knot_wire_get_ancount(packet->wire); uint16_t nscount = knot_wire_get_nscount(packet->wire); uint16_t arcount = knot_wire_get_arcount(packet->wire); if (knot_pkt_has_tsig(packet)) { arcount++; } // Print formatted info. switch (style->format) { case FORMAT_NSUPDATE: printf(";; ->>HEADER<<- opcode: %s; status: %s; id: %u\n" ";; Flags:%1s; " "ZONE: %u; PREREQ: %u; UPDATE: %u; ADDITIONAL: %u\n", opcode_str, rcode_str, id, flags, qdcount, ancount, nscount, arcount); break; default: printf(";; ->>HEADER<<- opcode: %s; status: %s; id: %u\n" ";; Flags:%1s; " "QUERY: %u; ANSWER: %u; AUTHORITY: %u; ADDITIONAL: %u\n", opcode_str, rcode_str, id, flags, qdcount, ancount, nscount, arcount); break; } }