void plog_response(int level, struct sockaddr *to, char sockchar, dns_msg_question_t *q, dns_header_t *h) { int rcode; char buf[256]; if (LogFlags & DNS_LOG_FLAG_QUERY) { dns_util_sa2str(buf, sizeof(buf), to); rcode = DNS_RCODE(ntohs(h->hdr_flags)); plog(level, "response to %s %c: %s %s %s %s", buf, sockchar, dns_proto_rcode_string(rcode), q->mq_name, dns_proto_class_string(q->mq_class), dns_proto_type_string(q->mq_type)); } }
struct dns_packet * get_next_packet(struct dns_packet *decoded, pcap_parser_file * input) { /* Misc. variables */ char fqdn[MAX_NAME + 1]; unsigned int fqdn_length; /* pcap-related variables */ const uint8_t *packet; /* The actual packet */ struct pcap_pkthdr header; /* The header that pcap gives us */ const struct sniff_ethernet *ethernet; /* The ethernet header */ unsigned short ethertype; const struct sniff_ipv4 *ipv4; /* The IP header */ const struct sniff_ipv6 *ipv6; const struct sniff_udp *udp; /* The UDP header */ const struct sniff_dns *dns; u_int size_ip; u_int size_layer2; unsigned short ip_version; uint32_t family; const uint8_t *qsection; uint8_t labelsize; uint16_t add_type; uint16_t edns_size; uint16_t extended_rcode_and_version; uint16_t zpart; const uint8_t *sectionptr; const uint8_t *where_am_i; /* Cursor in packet */ bool end_of_name; unsigned int size_header; bool end_of_headers, fragmented; uint8_t next_v6_header; const struct sniff_eh *eh; /* The IPv6 extension header, if present */ const struct sniff_frag *frag; assert(decoded->qname != NULL); /* Grab next packet */ decoded->rank = input->packetnum; next_packet: packet = (uint8_t *) pcap_next(input->handle, &header); if (packet == NULL) { /* End of file */ return NULL; } input->packetnum++; decoded->length = header.len; decoded->captured_length = header.caplen; decoded->date = header.ts; if (input->firstpacket.tv_sec == 0 && input->firstpacket.tv_usec == 0) { input->firstpacket = header.ts; } input->lastpacket = header.ts; if (input->datalink == DLT_EN10MB) { size_layer2 = SIZE_ETHERNET; ethernet = (struct sniff_ethernet *) (packet); ethertype = ntohs(ethernet->ether_type); if (ethertype == VLAN_ETHERTYPE) { packet += 4; ethernet = (struct sniff_ethernet *) (packet); ethertype = ntohs(ethernet->ether_type); } if (ethertype == IPv6_ETHERTYPE) { ip_version = 6; } else if (ethertype == IPv4_ETHERTYPE) { ip_version = 4; } else { /* Ignore other Ethernet types */ goto next_packet; } } else if (input->datalink == DLT_LOOP) { size_layer2 = SIZE_LOOP; family = (ntohl(*((uint32_t *) packet))); if (family == PF_INET6) { ip_version = 6; } else if (family == PF_INET) { ip_version = 4; } else { /* Ignore other packet types */ goto next_packet; } } else { fatal("Unsupported data link type %s (%i)\n", pcap_datalink_val_to_description(input->datalink), input->datalink); } if (ip_version == 6) { ipv6 = (struct sniff_ipv6 *) (packet + size_layer2); size_ip = SIZE_IPv6; assert(IPV6_VERSION(ipv6) == 6); next_v6_header = ipv6->ip_nxt; size_header = 0; where_am_i = where_am_i + SIZE_IPv6; end_of_headers = false; fragmented = false; while (!end_of_headers) { /* Extension headers defined in RFC 2460, section 4 */ if (next_v6_header == 0 || next_v6_header == 43 || next_v6_header == 50 || next_v6_header == 51 || next_v6_header == 60) { eh = (struct sniff_eh *) (where_am_i); next_v6_header = eh->eh_next; size_header = eh->eh_length; } /* Fragment */ else if (next_v6_header == 44) { fragmented = 1; frag = (struct sniff_frag *) (where_am_i); next_v6_header = frag->frag_next; size_header = SIZE_FRAGMENT_HDR; } else { end_of_headers = true; } where_am_i = where_am_i + size_header; size_ip += size_header; if ((size_layer2 + size_ip) > decoded->captured_length) { if (verbose) { fprintf(stdout, "Warning: ignoring packet #%li because IPv6 headers too large\n", input->packetnum); } goto next_packet; } } if (fragmented && FRAG_OFFSET(frag) == 0) { goto next_packet; } } else if (ip_version == 4) { ipv4 = (struct sniff_ipv4 *) (packet + size_layer2); size_ip = IP_HL(ipv4) * 4; assert(IPV4_VERSION(ipv4) == 4); } else { /* Should never happen */ assert(0); } if ((ip_version == 6 && next_v6_header == UDP) || (ip_version == 4 && ipv4->ip_p == UDP)) { if (ip_version == 6) { assert(decoded->src != NULL); assert(decoded->dst != NULL); inet_ntop(AF_INET6, &ipv6->ip_src, decoded->src, INET6_ADDRSTRLEN); inet_ntop(AF_INET6, &ipv6->ip_dst, decoded->dst, INET6_ADDRSTRLEN); } else if (ip_version == 4) { assert(decoded->src != NULL); assert(decoded->dst != NULL); inet_ntop(AF_INET, &ipv4->ip_src, decoded->src, INET_ADDRSTRLEN); inet_ntop(AF_INET, &ipv4->ip_dst, decoded->dst, INET_ADDRSTRLEN); } else { goto next_packet; } udp = (struct sniff_udp *) (packet + size_layer2 + size_ip); decoded->src_port = (u_short) ntohs(udp->sport); decoded->dst_port = (u_short) ntohs(udp->dport); if (decoded->src_port == DNS_PORT || decoded->dst_port == DNS_PORT) { if (maxpackets > 0 && input->dnspacketnum >= maxpackets) { return NULL; } dns = (struct sniff_dns *) (packet + size_layer2 + size_ip + SIZE_UDP); decoded->query = DNS_QR(dns) == 0 ? true : false; decoded->query_id = dns->query_id; decoded->opcode = DNS_OPCODE(dns); decoded->returncode = DNS_RCODE(dns); decoded->aa = DNS_AA(dns) ? true : false; decoded->tc = DNS_TC(dns) ? true : false; decoded->rd = DNS_RD(dns) ? true : false; decoded->ra = DNS_RA(dns) ? true : false; decoded->ancount = ntohs(dns->ancount); decoded->nscount = ntohs(dns->nscount); decoded->arcount = ntohs(dns->arcount); qsection = (uint8_t *) (packet + size_layer2 + size_ip + SIZE_UDP + SIZE_DNS); fqdn[0] = '\0'; end_of_name = false; for (sectionptr = qsection; !end_of_name;) { CHECK_SECTIONPTR(1); labelsize = (uint8_t) * sectionptr; if (labelsize == 0) { sectionptr++; end_of_name = true; } else if (labelsize > 63) { /* It can be an error/attack or it can be compression (RFC 1035, * section 4.1.4). Today, we ignore packets with compression (we * just parse the question section, anyway). * * * * * * * * * TODO */ if (verbose) { fprintf(stdout, "Warning: ignoring packet #%li because labelsize > 63\n", input->packetnum); } goto next_packet; } else { CHECK_SECTIONPTR(labelsize); if (strlen(fqdn) == 0) { strncpy(fqdn, (char *) sectionptr + 1, labelsize); fqdn_length = labelsize; } else { fqdn_length = strlen(fqdn); if (fqdn_length + labelsize > MAX_NAME) { if (verbose) { fprintf(stdout, "Warning: ignoring packet #%li because malformed (FQDN length is already %i and label size is %i bytes)\n", input->packetnum, fqdn_length, labelsize); }; goto next_packet; } strncat(fqdn, ".", 1); strncat(fqdn, (char *) sectionptr + 1, labelsize); fqdn_length += (labelsize + 1); } if (fqdn_length > MAX_NAME) { if (verbose) { fprintf(stdout, "Warning: ignoring packet #%li because FQDN length > %i\n", input->packetnum, MAX_NAME); } goto next_packet; } fqdn[fqdn_length] = '\0'; sectionptr = sectionptr + labelsize + 1; CHECK_SECTIONPTR(0); } } CHECK_SECTIONPTR(2); strcpy(decoded->qname, fqdn); #ifdef PICKY_WITH_ALIGNMENT decoded->qtype = unaligned_uint16(sectionptr); #else decoded->qtype = ntohs(*((uint16_t *) sectionptr)); #endif sectionptr += 2; CHECK_SECTIONPTR(2); #ifdef PICKY_WITH_ALIGNMENT decoded->qclass = unaligned_uint16(sectionptr); #else decoded->qclass = ntohs(*((uint16_t *) sectionptr)); #endif sectionptr += 2; decoded->edns0 = false; if (decoded->query) { edns_size = 0; if (dns->ancount == 0 && dns->nscount == 0) { /* Probably by far the most common case in queries... */ if (dns->arcount != 0) { /* There is an additional section. * Probably the OPT * * * * * * * * * * * * * of EDNS */ CHECK_SECTIONPTR(1); labelsize = (uint8_t) * sectionptr; if (labelsize == 0) { /* Yes, EDNS0 */ sectionptr += 1; CHECK_SECTIONPTR(2); #ifdef PICKY_WITH_ALIGNMENT add_type = unaligned_uint16(sectionptr); #else add_type = ntohs(*((uint16_t *) sectionptr)); #endif sectionptr += 2; CHECK_SECTIONPTR(2); if (add_type == OPT) { #ifdef PICKY_WITH_ALIGNMENT edns_size = unaligned_uint16(sectionptr); #else edns_size = ntohs(*((uint16_t *) sectionptr)); #endif decoded->edns0 = true; /* RFC 2671 */ sectionptr += 2; CHECK_SECTIONPTR(2); #ifdef PICKY_WITH_ALIGNMENT extended_rcode_and_version = unaligned_uint16(sectionptr); #else extended_rcode_and_version = ntohs(*((uint16_t *) sectionptr)); #endif sectionptr += 2; CHECK_SECTIONPTR(2); #ifdef PICKY_WITH_ALIGNMENT zpart = unaligned_uint16(sectionptr); #else zpart = ntohs(*((uint16_t *) sectionptr)); #endif /* RFC 3225 */ decoded->do_dnssec = DNS_DO_DNSSEC(zpart) ? true : false; } sectionptr += 2; /* TODO: dissect the RDATA to find things like the option code (such as 3 for NSID) http://www.iana.org/assignments/dns-parameters */ } } } } if (decoded->edns0) { decoded->edns0_size = (unsigned int) edns_size; } input->dnspacketnum++; return decoded; } } goto next_packet; }