diff options
Diffstat (limited to '')
-rw-r--r-- | contrib/queryparse/INSTALL | 48 | ||||
-rw-r--r-- | contrib/queryparse/USAGE | 52 | ||||
-rwxr-xr-x | contrib/queryparse/queryparse | 135 | ||||
-rw-r--r-- | contrib/queryparse/queryparse.1 | 65 |
4 files changed, 300 insertions, 0 deletions
diff --git a/contrib/queryparse/INSTALL b/contrib/queryparse/INSTALL new file mode 100644 index 0000000..c22d5b3 --- /dev/null +++ b/contrib/queryparse/INSTALL @@ -0,0 +1,48 @@ + +Installation +------------ + +Queryparse requires the dnspython and pcapy python modules. Pcapy depends +upon the pcap library. + +Libpcap may be obtained from http://www.tcpdump.org/ +Dnspython may be obtained from http://www.dnspython.org/ +Pcapy may be obtained from http://oss.coresecurity.com/projects/pcapy.html + +Ensure queryparse is somewhere in your path. + + +Usage +----- +queryparse -i <input file> -o <output file> + + -i <input file>: the tcpdump file that will be parsed to locate DNS + queries. + + -o <output file>: the file to which you wish to save the queries parsed + from <input file>. When complete, this file is suitable + for use as input to dnsperf. + + -r Keep packets whose RD flag is not set. + Use this flag when parsing captures from authoritative + servers. When parsing captures from caching servers, + do not use this flag unless you also want to parse the + queries the server itself is sending. + + -R Parse response packets (QR=1), instead of query packets + (QR=0). + + +Queryparse takes as input a packet capture file as created by tcpdump (or any +other program that can save data in pcap format). It parses every UDP packet, +looking for DNS queries. When it finds a potential query, it makes every +effort to parse it as a valid query. + +Once queryparse has finished, it will print a set of statistics regarding +the capture file to STDOUT. + + +NOTE: Currently, queryparse will correctly handle packets contained in either +Ethernet frames or Cisco HDLC frames. It is not guaranteed to work with other +framing formats. + diff --git a/contrib/queryparse/USAGE b/contrib/queryparse/USAGE new file mode 100644 index 0000000..d5672e9 --- /dev/null +++ b/contrib/queryparse/USAGE @@ -0,0 +1,52 @@ + + +To use queryparse, you need one or more files containing pcap-formatted packet +captures, such as those generated by tcpdump via the -w switch. + +Once you have such a file, call queryparse as follows: + +queryparse -i tcpdump.raw -o outputfile + +where "tcpdump.raw" is the name of the pcap-formatted packet capture file, and +"outputfile" is the name you wish to call the saved output of queryparse. + +When queryparse finishes, it will print to STDOUT a count of each type of query +encountered during its run. For example: + +Statistics: + A: 1175140 + SOA: 23639 + NAPTR: 113 + NS: 1329 + CNAME: 1667 + NONE: 38 + PTR: 186053 + AAAA: 50858 + ANY: 2117 + SRV: 49470 + KEY: 218 + A6: 245 + TXT: 24243 + MX: 517510 +------------------------- + TOTAL: 2032640 + + + +The resulting output is in a format suitable as input to resperf or dnsperf. +For example: + +example.biz. A +example.net. MX +foo.example.tv. A +example.enc. MX +example[2].txt. MX +foo.]. MX + + +Note that there are both valid and invalid host names in the output: Neither +queryparse nor resperf or dnsperf discriminate on the basis of a host name's +adherence to RFCs. If the query was put on the wire and can be recognized as a +properly-formed query, it will be saved. If this does not meet your needs, you +may wish to parse the resulting output file to eliminate nonconforming host +names. diff --git a/contrib/queryparse/queryparse b/contrib/queryparse/queryparse new file mode 100755 index 0000000..01edeaf --- /dev/null +++ b/contrib/queryparse/queryparse @@ -0,0 +1,135 @@ +#!/usr/bin/env python +# +# Copyright 2019-2021 OARC, Inc. +# Copyright 2017-2018 Akamai Technologies +# Copyright 2006-2016 Nominum, Inc. +# All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import dns.message +import dns.rrset +import dns.flags +import dns.name +import pcapy +import socket +import sys +import struct +from optparse import OptionParser + + +__author__ = "Nominum, Inc." +__version__ = "1.0.2.0" +__date__ = "2007-05-14" + +IPHeader = '!BBHHHBBHLL' + +IPHDRLEN = 20 +UDPHDRLEN = 8 +LINKTYPE_C_HDLC = 104 +LINKTYPE_ETHERNET = 1 +qtypecount = {} + + +def main(argv): + parser = OptionParser(usage="%prog [options]", + version = "%prog " + __version__ ) + parser.add_option("-i", "--input", dest="fin", + help="name of tcpdump file to parse", metavar="FILE") + parser.add_option("-o", "--output", dest="fout", + help="file in which to save parsed DNS queries", + metavar="FILE") + parser.add_option("-r", "--recursion", dest="recurse", action="store_true", + default=False, + help="Keep queries whose RD flag is 0 (default: discard)") + parser.add_option("-R", "--responses", dest="responses", + action="store_true", default=False, + help="Parse query responses instead of queries") + (opts, args) = parser.parse_args() + + if opts.fin: + pcap = pcapy.open_offline(opts.fin) + else: + pcap = pcapy.open_offline('-') + linktype = pcap.datalink() + if linktype == LINKTYPE_C_HDLC: + IPHDRSTART = 4 + else: + IPHDRSTART = 14 + if opts.fout: + outfile = open(opts.fout, "w") + else: + outfile = sys.stdout + while True: + try: + packet = pcap.next() + except Exception: + break + + if packet[0] is None: + break + packet = packet[1] + # Toss the stuff before the IP header + packet = packet[IPHDRSTART:] + + # Grab the rest of the packet so we can parse proto + iphdr = packet[0:IPHDRLEN] + if len(iphdr) < IPHDRLEN: + continue + (vhl, tos, tlen, ipid, fragoff, ttl, proto, cksum, srcip, dstip) = \ + struct.unpack(IPHeader, iphdr) + + # Toss the IP header, we're done with it. We need to account + # for any IP header options. + ihl = (vhl & 0xF) * 4 + packet = packet[ihl:] + + if proto == socket.IPPROTO_UDP: # UDP, 8-byte header + packet = packet[UDPHDRLEN:] + else: + continue + + try: + msg = dns.message.from_wire(packet) + except Exception: + continue + if not opts.recurse and not dns.flags.RD: + continue + if opts.responses: + querytest = msg.flags & dns.flags.QR + else: + querytest = not (msg.flags & dns.flags.QR) + if querytest: + for query in msg.question: # handle multiple queries per packet + fqdn = query.name.to_text() + qtype = dns.rdatatype.to_text(query.rdtype) + outfile.write("%s %s\n" % (fqdn, qtype)) + # add qtype to dict if not present, otherwise increment + qtypecount[query.rdtype] = qtypecount.get(query.rdtype, 0) + 1 + + if outfile is not sys.stdout: + outfile.close() + sum = 0 + print("Statistics:") + qtypes = list(qtypecount.keys()) + qtypes.sort() + for qtype in qtypes: + qtype_str = dns.rdatatype.to_text(qtype) + count = qtypecount[qtype] + print(" %10s:\t%d" % (qtype_str, count)) + sum += count + print("-------------------------") + print(" TOTAL:\t%d" % sum) + +if __name__ == '__main__': + main(sys.argv[1:]) diff --git a/contrib/queryparse/queryparse.1 b/contrib/queryparse/queryparse.1 new file mode 100644 index 0000000..bfcac8c --- /dev/null +++ b/contrib/queryparse/queryparse.1 @@ -0,0 +1,65 @@ +.\" Copyright 2019-2021 OARC, Inc. +.\" Copyright 2017-2018 Akamai Technologies +.\" Copyright 2006-2016 Nominum, Inc. +.\" All rights reserved. +.\" +.\" Licensed under the Apache License, Version 2.0 (the "License"); +.\" you may not use this file except in compliance with the License. +.\" You may obtain a copy of the License at +.\" +.\" http://www.apache.org/licenses/LICENSE-2.0 +.\" +.\" Unless required by applicable law or agreed to in writing, software +.\" distributed under the License is distributed on an "AS IS" BASIS, +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +.\" See the License for the specific language governing permissions and +.\" limitations under the License. +.TH "queryparse" 1 +.SH NAME +queryparse \- extract DNS queries from pcap capture files. +.SH SYNOPSIS +.B queryparse [-i +.I input file +.B ] [-o +.I output file +.B ] [-r +.I recursion only +.B ] [-R +.I parse responses +.B ] +.SH DESCRIPTION +.B queryparse +is a tool designed to extract DNS queries from pcap-formatted packet +capture files and save them in a form suitable for input to Nominum's +dnsperf or resperf benchmarking tools. +.B queryparse +will only examine UDP packets, and currently supports Ethernet and Cisco HDLC frame types. +.SH OPTIONS +.IP "\-i filename" +Attempt to extract DNS queries from +.I filename, +which should be a pcap-formatted packet capture session (e.g., a file created +by tcpdump or ethereal). +.IP "\-o filename" +Write queries to +.I filename +in a format suitable for input to Nominum's dnsperf or resperf benchmarking tools. +.IP "\-r" +Keep queries that do not have the RD (recursion desired) flag set. This is useful when parsing packet captures from authoritative nameservers. When parsing captures from caching nameservers, do not use it unless you also want to parse the outgoing queries from the nameserver. Defaults to discarding queries with RD=0. +.IP "\-R" +Parse responses (QR=1) instead of queries (QR=0). +.SH FILES +None +.SH ENVIRONMENT +None +.SH DIAGNOSTICS +None +.SH BUGS +None +.SH AUTHOR +Nominum, Inc. +.SH "SEE ALSO" +.BR dnsperf (1), +.BR resperf (1), +.BR pcap (3), +.BR tcpdump (8) |