fix: populate ldns submodule and add autotools to LDNS build stage

- Re-cloned zonemaster-ldns with --recurse-submodules so the bundled
  ldns C library source (including Changelog and configure.ac) is present
- Added autoconf, automake, libtool to Dockerfile.backend ldns-build stage
  so libtoolize + autoreconf can generate ldns/configure during make

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-21 08:33:38 +02:00
parent 8d4eaa1489
commit eaaa8f6a11
541 changed files with 138189 additions and 0 deletions

View File

@@ -0,0 +1,66 @@
# Standard installation pathnames
# See the file LICENSE for the license
SHELL = @SHELL@
VERSION = @PACKAGE_VERSION@
basesrcdir = $(shell basename `pwd`)
srcdir = @srcdir@
prefix = @prefix@
exec_prefix = @exec_prefix@
bindir = @bindir@
mandir = @mandir@
CC = @CC@
CFLAGS = @CFLAGS@ -Wall -I.
CPPFLAGS = @CPPFLAGS@
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@
LDNSDIR= @LDNSDIR@
INSTALL = $(srcdir)/../install-sh
COMPILE = $(CC) $(CPPFLAGS) $(CFLAGS)
LINK = $(CC) $(CFLAGS) $(LDFLAGS)
LIBS_STC = -lpcap $(LDNSDIR)/lib/libldns.a -lcrypto -ldl
HEADER = config.h
.PHONY: all clean realclean all-static
all: p
all-static: pcat-stc pcat-diff-stc pcat-print-stc
p: pcat pcat-diff pcat-print
# strip pcat
# strip pcat-diff
# strip pcat-print
pcat: pcat.o getdelim.o
$(LINK) -o $@ $+ $(LIBS)
pcat-diff: pcat-diff.o getdelim.o
$(LINK) -o $@ $+ $(LIBS)
pcat-print: pcat-print.o getdelim.o
$(LINK) -o $@ $+ $(LIBS)
pcat-stc: pcat.o getdelim.o
$(LINK) -o $(@:-stc=) $+ $(LIBS_STC)
pcat-diff-stc: pcat-diff.o getdelim.o
$(LINK) -o $(@:-stc=) $+ $(LIBS_STC)
pcat-print-stc: pcat-print.o getdelim.o
$(LINK) -o $(@:-stc=) $+ $(LIBS_STC)
clean:
rm -f pcat pcat-diff pcat-print
rm -f pcat.o pcat-diff.o pcat-print.o
realclean: clean
rm -f configure config.h config.log config.status
## implicit rule
%.o: $(srcdir)/%.c
$(COMPILE) -c $<

View File

@@ -0,0 +1,176 @@
PCAT README
PCAT -- cat pcap streams
1. Introduction
Pcat consists out of three programs:
1. pcat
This program reads a raw pcap stream, extract the payload of
each packet and sends the payload to a nameserver of the user's
choice.
Each payload and reply from the server is printed to standard
output as ASCII. The binary packet/payload contents is printed
as hexadecimal in network order.
2. pcat-diff
This utility reads two streams/files as generated by 'pcat' it
then compare these and prints the differences to standard
output.
The output format is simular to that of 'pcat', and can be
viewed with pcat-print.
Alternatively, pcat-diff can do advanced checking on differences,
in which case the output will differ. See "Advanced Differences"
for more on this.
3. pcat-print
This program reads the 'diff' as printed by 'pcat-diff' and
tries to re-generate to original DNS packets. If this succeeds
the packet is printed to standard output. If it fails an error
is printed instead.
4. pcat-grep.pl
This is a small perl script that can 'grep' pcat streams. If you
know for instance that query number 1023 doesn't match you can
filter that query out by means of pcat-grep.pl
2. Format Used
The format used is a simple line based ASCII format. Each "record"
consists out of 4 lines. Empty lines are discarded. The format is
specified as follows:
1. sequence number
2. hex dump
3. hex dump
4. hex dump or empty line
Each hex dump is a query in network order, printed as hexadecimal.
3. Usage
All pcat utils are created as filters, thus they will read from a file
or standard input. All output is send to standard output.
Send a steam to a nameserver:
./pcat -a 213.154.224.1 20011009-134418-q50000.pkt > reply.53
Or print it directly:
./pcat -a 213.154.224.1 20011009-134418-q50000.pkt | pcat-print
Send the stream to another nameserver:
./pcat -a 213.154.224.1 -p 5454 20011009-134418-q50000.pkt > reply.5454
The two pcat-stream, 'reply.53' and 'reply.5454' can now be diffed with
pcat-diff:
./pcat-diff reply.53 reply.54 > reply.diff
If we to see what actual packets that differ (if they can be parsed) we
can use pcap-print:
pcap-print reply.diff
Or it can all be done with pipes, eliminating the need of files.
./pcat-diff <(./pcat -a 213.154.224.1 20011009-134418-q50000.pkt) \
<(./pcat 213.154.224.1 -p 5454 20011009-134418-q50000.pkt) | ./pcat-print
4. Advanced differences
You can let pcat-diff do more intelligent checking on the differences between
two outputs of pcat. In this mode, pcat-diff takes an argument specifying a
directory containing files whose name end in .match. These files specify
'Known' differences. It works like this:
If a difference between two answer packets is found, the packet is first
normalized; the packet dates is changed to match, and each section is
sorted. If these changes still don't make the packets equal, the
match-specifications in the specified directory are consulted.
These specifications contain 3 elements; a 1-line description of the type of
difference, a specification the question must match, and a specification
that both answer packets must match.
The first line contains the specification, the following lines the
specifications, separated by a line starting with an exclamation mark.
A specification looks like the normal output of drill and dig. It is based
on the text representation format from the DNS RFCs. It can contain the
following special characters:
* whitespace: whitespace is skipped and ignored
* ?: Following a question mark, all characters up to the next
whitespace are optional, so they can either exist or not in the answer
* []: Square brackets contain a list of words/values of which exactly
one must be present in the packets.
* *: A star specifies that the packets may contain everything until it
matches the next character in the specification. You can use
multiple stars in a row, the number of stars specify the number of
next characters that must match before continuing.
* &: The ampersand works the same as the *, but in this case the value
that matches must be exactly the same in both packets.
There are 2 special cases that can be used instead of a packet description:
* BADPACKET: if you use this as the complete description of the query
packet, this matches any query that cannot be parsed
* NOANSWER: if you use this as the complete description of the answer
packet, this matches *both* packets if *one* had no answer
(the other packet is ignored, if both packets had no answer,
they were equal anyway)
Example:
Different additional section
*
!
;; ->>HEADER<<- opcode: &, rcode: &, id: &
;; flags: & ; QUERY: &, ANSWER: &, AUTHORITY: &, ADDITIONAL: &
;; QUESTION SECTION:
;; &&&&&
;; ANSWER SECTION:
&&&&&
;; AUTHORITY SECTION:
&&&&&
;; ADDITIONAL SECTION:
*****
;; Query time: & msec
&&&&&
;; WHEN: &
;; MSG SIZE rcvd: &
The description of this examples is 'Different additional section'.
The query specification contains only one *, so every query matches this.
The answer specification specifies that the packets must be completely
equal, except for the additional part. The additional part must, however,
contain an equal amount of entries (see the & after ADDITIONAL in line 2).
In the question section, 5 &'s are used, so that everything passes until the
packets contain the text ';; AU'. This could of course be expanded to
completely match the text ';; AUTHORITY SECTION', by using even more
ampersands.
If pcat-diff in advanced mode encounters a difference which is not known, it
prints the index number, query, and both answers, and then quits. It is
expected that the user studies the new and unexpected difference, captures
it in a match specification, and runs pcat-diff again. To speed up the
process of finding all differences, you can start from the index number that
was printed by using the option -s <index>.
If you want to know a bit more about why the packets did not match, you can
specify verbose mode with -v. It is not advisable to do this on the complete
input, but rather use -s to start with the offending packet. Verbose mode
produces a LOT of output.
If the complete files have been read, and no unknown differences have been
found, statistics are printed about the known differences encountered.
Because this can take a long time, you can use '-p <nr>' to print
preliminary results every nr packets.

View File

@@ -0,0 +1,331 @@
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.57)
AC_INIT(pcat, 1.7.0, dns-team@nlnetlabs.nl,pcat)
AC_CONFIG_SRCDIR([pcat.c])
OURCPPFLAGS=''
CPPFLAGS=${CPPFLAGS:-${OURCPPFLAGS}}
OURCFLAGS='-g'
CFLAGS=${CFLAGS:-${OURCFLAGS}}
AC_AIX
# Checks for programs.
AC_PROG_CC
AC_PROG_MAKE_SET
dnl routine to help check for compiler flags.
AC_DEFUN([CHECK_COMPILER_FLAG],
[
AC_REQUIRE([AC_PROG_CC])
AC_MSG_CHECKING(whether $CC supports -$1)
cache=`echo $1 | sed 'y%.=/+-%___p_%'`
AC_CACHE_VAL(cv_prog_cc_flag_$cache,
[
echo 'void f(){}' >conftest.c
if test -z "`$CC -$1 -c conftest.c 2>&1`"; then
eval "cv_prog_cc_flag_$cache=yes"
else
eval "cv_prog_cc_flag_$cache=no"
fi
rm -f conftest*
])
if eval "test \"`echo '$cv_prog_cc_flag_'$cache`\" = yes"; then
AC_MSG_RESULT(yes)
:
$2
else
AC_MSG_RESULT(no)
:
$3
fi
])
dnl routine to help check for needed compiler flags.
# if the given code compiles without the flag, execute argument 4
# if the given code only compiles with the flag, execute argument 3
# otherwise fail, execute argument 5.
AC_DEFUN([CHECK_COMPILER_FLAG_NEEDED],
[
AC_REQUIRE([AC_PROG_CC])
AC_MSG_CHECKING(whether we need $1 as a flag for $CC)
cache=`echo $1 | sed 'y%.=/+- %___p__%'`
AC_CACHE_VAL(cv_prog_cc_flag_needed_$cache,
[
echo '$2' > conftest.c
echo 'void f(){}' >>conftest.c
if test -z "`$CC -Werror -Wall $CFLAGS -c conftest.c 2>&1`"; then
eval "cv_prog_cc_flag_needed_$cache=no"
else
[
if test -z "`$CC $1 -Werror -Wall $CFLAGS -c conftest.c 2>&1`"; then
eval "cv_prog_cc_flag_needed_$cache=yes"
else
eval "cv_prog_cc_flag_needed_$cache=fail"
#echo 'Test with flag fails too!'
#cat conftest.c
#echo "$CC $1 -Werror -Wall $CFLAGS -c conftest.c 2>&1"
#echo `$CC $1 -Werror -Wall $CFLAGS -c conftest.c`
#exit 1
fi
]
fi
rm -f conftest
])
if eval "test \"`echo '$cv_prog_cc_flag_needed_'$cache`\" = yes"; then
AC_MSG_RESULT(yes)
:
$3
else
if eval "test \"`echo '$cv_prog_cc_flag_needed_'$cache`\" = no"; then
AC_MSG_RESULT(no)
:
$4
else
AC_MSG_RESULT(failed)
:
#cat conftest.c
#echo "$CC -Werror -Wall $CFLAGS -c conftest.c"
#echo `$CC -Werror -Wall $CFLAGS -c conftest.c`
#echo "$CC $1 -Werror -Wall $CFLAGS -c conftest.c"
#echo `$CC $1 -Werror -Wall $CFLAGS -c conftest.c`
$5
fi
fi
])
CHECK_COMPILER_FLAG(O2, [CFLAGS="$CFLAGS -O2"])
CHECK_COMPILER_FLAG(std=c99, [C99FLAG="-std=c99"])
CHECK_COMPILER_FLAG(xc99, [C99FLAG="-xc99"])
CHECK_COMPILER_FLAG_NEEDED($C99FLAG -D__EXTENSIONS__ -D_BSD_SOURCE -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600,
[
#include "confdefs.h"
#include <stdlib.h>
#include <ctype.h>
#include <sys/time.h>
#ifdef HAVE_TIME_H
#include <time.h>
#endif
#include <unistd.h>
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#endif
int test() {
int a;
char **opts = NULL;
struct timeval tv;
char *t;
time_t time = 0;
char *buf = NULL;
t = ctime_r(&time, buf);
tv.tv_usec = 10;
srandom(32);
a = getopt(2, opts, "a");
a = isascii(32);
return a;
}
], [CFLAGS="$CFLAGS $C99FLAG -D__EXTENSIONS__ -D_BSD_SOURCE -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600"])
CHECK_COMPILER_FLAG_NEEDED($C99FLAG,
[
#include <stdbool.h>
#include <ctype.h>
int test() {
int a = 0;
a = isblank(12);
return a;
}
], [CFLAGS="$CFLAGS $C99FLAG"])
CHECK_COMPILER_FLAG_NEEDED(-D_BSD_SOURCE,
[
#include <ctype.h>
int test() {
int a;
a = isascii(32);
return a;
}
], [CFLAGS="$CFLAGS -D_BSD_SOURCE"])
CHECK_COMPILER_FLAG_NEEDED(-D_POSIX_C_SOURCE=200112,
[
#include <time.h>
int test() {
int a = 0;
char *t;
time_t time = 0;
char *buf = NULL;
t = ctime_r(&time, buf);
return a;
}
], [CFLAGS="$CFLAGS -D_POSIX_C_SOURCE=200112"])
CHECK_COMPILER_FLAG_NEEDED(-D__EXTENSIONS__,
[
#include <stdlib.h>
#include <ctype.h>
#include <sys/time.h>
#ifdef HAVE_TIME_H
#include <time.h>
#endif
#include <unistd.h>
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#endif
int test() {
int a;
char **opts = NULL;
struct timeval tv;
tv.tv_usec = 10;
srandom(32);
#ifdef HAVE_GETOPT_H
a = getopt(2, opts, "a");
#else
opts = opts;
#endif
a = isascii(32);
return a;
}
], [CFLAGS="$CFLAGS -D__EXTENSIONS__"])
AC_CHECK_HEADERS([sys/types.h getopt.h stdlib.h stdio.h assert.h netinet/in.h ctype.h time.h pcap.h arpa/inet.h sys/time.h sys/socket.h],,, [AC_INCLUDES_DEFAULT])
AC_CHECK_HEADERS([netinet/in_systm.h net/if.h netinet/ip.h netinet/udp.h netinet/if_ether.h],,, [
AC_INCLUDES_DEFAULT
#ifdef HAVE_NETINET_IN_SYSTM_H
#include <netinet/in_systm.h>
#endif
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#ifdef HAVE_NET_IF_H
#include <net/if.h>
#endif])
AC_CHECK_HEADERS([sys/param.h sys/mount.h],,,
[AC_INCLUDES_DEFAULT]
[
[
#if HAVE_SYS_PARAM_H
# include <sys/param.h>
#endif
]
])
# check for ldns
AC_ARG_WITH(ldns,
AC_HELP_STRING([--with-ldns=PATH specify prefix of path of ldns library to use])
,
[
specialldnsdir="$withval"
CPPFLAGS="$CPPFLAGS -I$withval/include"
LDFLAGS="$LDFLAGS -L$withval/lib"
]
)
# check for ldns development source tree
AC_MSG_CHECKING([for ldns devel source])
ldns_dev_dir=..
if test -f $ldns_dev_dir/ldns/util.h && \
grep LDNS_VERSION $ldns_dev_dir/ldns/util.h >/dev/null; then
ldns_version=`grep LDNS_VERSION $ldns_dev_dir/ldns/util.h | sed -e 's/^.*"\(.*\)".*$/\1/'`
AC_MSG_RESULT([using $ldns_dev_dir with $ldns_version])
CPPFLAGS="$CPPFLAGS -I$ldns_dev_dir/include"
LDFLAGS="$LDFLAGS -L$ldns_dev_dir/lib"
LIBS="$LIBS -lldns"
AC_DEFINE(HAVE_LIBLDNS, 1, [If the ldns library is available.])
LDNSDIR="$ldns_dev_dir"
else
AC_MSG_RESULT([no])
AC_CHECK_LIB(ldns, ldns_rr_new,, [
AC_MSG_ERROR([Can't find ldns library])
]
)
fi
AC_SUBST(LDNSDIR)
AC_CHECK_HEADER(ldns/ldns.h,, [
AC_MSG_ERROR([Can't find ldns headers])
], [AC_INCLUDES_DEFAULT]
)
AC_CHECK_LIB(pcap, pcap_open_offline,, [
AC_MSG_ERROR([Can't find pcap library.])
]
)
AC_CHECK_FUNCS(getdelim)
AC_CHECK_FUNCS(isblank)
AC_CHECK_FUNCS(strndup)
AH_BOTTOM([
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#if STDC_HEADERS
#include <stdlib.h>
#include <stddef.h>
#endif
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#ifdef HAVE_NETINET_UDP_H
#include <netinet/udp.h>
#endif
#ifdef HAVE_TIME_H
#include <time.h>
#endif
#ifdef HAVE_PCAP_H
#include <pcap.h>
#endif
#ifdef HAVE_NETINET_IN_SYSTM_H
#include <netinet/in_systm.h>
#endif
#ifdef HAVE_NETINET_IP_H
#include <netinet/ip.h>
#endif
#ifdef HAVE_NET_IF_H
#include <net/if.h>
#endif
#ifdef HAVE_NETINET_IF_ETHER_H
#include <netinet/if_ether.h>
#endif
])
AC_CONFIG_FILES([Makefile])
AC_CONFIG_HEADER([config.h])
AC_OUTPUT

View File

@@ -0,0 +1,63 @@
#include "config.h"
#ifndef HAVE_GETDELIM
#define GETDELIM_BUFFER 128
/* copied from xine-devel */
size_t
getdelim( char **lineptr, size_t *n, int delimiter, FILE *stream )
{
char *p;
int c;
size_t len = 0;
if (!lineptr || !n || (!*lineptr && *n))
return -1;
/* allocate initial buffer */
if (!*lineptr || !*n) {
char *np;
np = realloc( *lineptr, GETDELIM_BUFFER );
if (!np)
return -1;
*n = GETDELIM_BUFFER;
*lineptr = np;
}
p = *lineptr;
/* read characters from stream */
while ((c = fgetc( stream )) != EOF) {
if (len >= *n) {
char *np = realloc( *lineptr, *n * 2 );
if (!np)
return -1;
p = np + (p - *lineptr);
*lineptr = np;
*n *= 2;
}
*p++ = (char) c;
len++;
if (delimiter == c)
break;
}
/* end of file without any bytes read */
if ((c == EOF) && (len == 0))
return -1;
/* trailing "\0" */
if (len >= *n) {
char *np = realloc( *lineptr, *n + 1 );
if (!np)
return -1;
p = np + (p - *lineptr);
*lineptr = np;
*n += 1;
}
*p = '\0';
return len;
}
#endif /* !HAVE_GETDELIM */

View File

@@ -0,0 +1,184 @@
'\" t
.TH PCAT-DIFF 1 "08 Mar 2006" "pcat utils"
.SH NAME
pcat-diff \- show the difference between two pcat files.
.SH SYNOPSIS
.B pcat-diff
.IR PCAT_FILE1
.IR PCAT_FILE2
.SH DESCRIPTION
\fBpcat-diff\fR reads in two pcat files and show the differences
between them.
Its output is another pcat stream which can then be interpreted by
pcat-print.
pcat-diff can also do advanced checking against a number of specification,
for instance to count the number of known differences between two
implementations.
You can let pcat-diff do more intelligent checking on the differences between
two outputs of pcat. In this mode, pcat-diff takes an argument specifying a
directory containing files whose name end in .match. These files specify
'Known' differences. It works like this:
If a difference between two answer packets is found, the packet is first
normalized; the packet dates is changed to match, and each section is
sorted. If these changes still don't make the packets equal, the
match-specifications in the specified directory are consulted.
These specifications contain 3 elements; a 1-line description of the type of
difference, a specification the question must match, and a specification
that both answer packets must match.
The first line contains the specification, the following lines the
specifications, separated by a line starting with an exclamation mark.
A specification looks like the normal output of drill and dig. It is based
on the text representation format from the DNS RFCs. It can contain the
following special characters:
* whitespace: whitespace is skipped and ignored
* ?: Following a question mark, all characters up to the
next whitespace are optional, so they can either
exist or not in the answer
* []: Square brackets contain a list of words/values of
which exactly one must be present in the packets.
* *: A star specifies that the packets may contain
everything until it matches the next character in
the specification. You can use multiple stars in a
row, the number of stars specify the number of next
characters that must match before continuing.
* &: The ampersand works the same as the *, but in this
case the value that matches must be exactly the
same in both packets.
There are 2 special cases that can be used instead of a packet description:
* BADPACKET: if you use this as the complete description
of the query packet, this matches any query
that cannot be parsed
* NOANSWER: if you use this as the complete description
of the answer packet, this matches *both*
packets if *one* had no answer (the other
packet is ignored, if both packets had no
answer, they were equal anyway)
Example:
Different additional section
*
!
;; ->>HEADER<<- opcode: &, rcode: &, id: &
;; flags: & ; QUERY: &, ANSWER: &, AUTHORITY: &, ADDITIONAL: &
;; QUESTION SECTION:
;; &&&&&
;; ANSWER SECTION:
&&&&&
;; AUTHORITY SECTION:
&&&&&
;; ADDITIONAL SECTION:
*****
;; Query time: & msec
&&&&&
;; WHEN: &
;; MSG SIZE rcvd: &
The description of this examples is 'Different additional section'.
The query specification contains only one *, so every query matches this.
The answer specification specifies that the packets must be completely
equal, except for the additional part. The additional part must, however,
contain an equal amount of entries (see the & after ADDITIONAL in line 2).
In the question section, 5 &'s are used, so that everything passes until the
packets contain the text ';; AU'. This could of course be expanded to
completely match the text ';; AUTHORITY SECTION', by using even more
ampersands.
If pcat-diff in advanced mode encounters a difference which is not known, it
prints the index number, query, and both answers, and then quits. It is
expected that the user studies the new and unexpected difference, captures
it in a match specification, and runs pcat-diff again. To speed up the
process of finding all differences, you can start from the index number that
was printed by using the option -s <index>.
If you want to know a bit more about why the packets did not match, you can
specify verbose mode with -v. It is not advisable to do this on the complete
input, but rather use -s to start with the offending packet. Verbose mode
produces a LOT of output.
If the complete files have been read, and no unknown differences have been
found, statistics are printed about the known differences encountered.
Because this can take a long time, you can use '-p <nr>' to print
preliminary results every nr packets.
.PP
If PCAT_FILE2 is not given, standard input is read.
.SH OPTIONS
.TP
\fB-d\fR \fIdirectory\fR
Directory containing match files, this options sets the advanced checking mode, see manpage
.TP
\fB-h\fR
Show usage
.TP
\fB-m\fR \fInumber\fR
only check up to <number> packets
.TP
\fB-o\fR
show original packets when printing diffs (by default, packets are normalized)
.TP
\fB-p\fR \fInumber\fR
show intermediate results every <number> packets
.TP
\fB-s\fR \fInumber\fR
only start checking after <number> packets
.TP
\fB-v\fR
verbose mode
.SH OUTPUT FORMAT
The default output of \fBpcat-diff\fR consists "records". Each record has four lines:
.PP
1. xxx - (decimal) sequence number
2. hex dump - query in hex, network order
3. hex dump - answer of FILE1 in hex, network order
4. hex dump - answer of FILE2 in hex, network order.
The advanced output only prints statistics about the types of differences
found and their percentages. If an unknown difference is found it prints
the relevant packets and exits.
.SH ALSO SEE
Also see pcat(1) and pcat-print(1).
.SH AUTHOR
Written by Miek Gieben for NLnet Labs.
.SH REPORTING BUGS
Report bugs to <dns-team@nlnetlabs.nl>.
.SH COPYRIGHT
Copyright (C) 2005, 2006 NLnet Labs. This is free software. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.
.PP
Licensed under the BSD License.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,75 @@
#!/usr/bin/perl
# take a numerical range and ranges and
# only show those ranges or not (-v)
# single numbers: 4
# ranges: 5-10 (inclusive)
# separated by comma's
# -v reverse
use strict;
my %numbers = ();
my $reverse = 0;
my $i;
my $k;
foreach my $r (@ARGV) {
if ($r eq "-v") {
$reverse = 1;
next;
}
if ($r =~ /-/) {
my ($s, $e) = split /-/, $r;
if ($s > $e) {
next;
}
for ($i = $s; $i <= $e; $i++) {
$numbers{$i} = 1;
}
next;
}
$numbers{$r} = 1;
}
# read in the input, pcat style
my $line; my $left; my $right;
$i = 1;
my $print = 0;
while(<STDIN>) {
if ($i % 4 == 1) {
s/^q: //; # kill it, if we do query diff
($left, $right) = split /:/, $_;
foreach $k (keys %numbers) {
if ($k == $left) {
if ($reverse == 1) {
$print = 0;
} else {
$print = 1;
}
last;
}
if ($reverse == 1) {
$print = 1;
} else {
$print = 0;
}
}
}
if ($print == 1) {
print $_;
}
if ($i % 4 == 0) {
if ($reverse == 1) {
$print = 1;
} else {
$print = 0;
}
}
$i++;
}

View File

@@ -0,0 +1,64 @@
'\" t
.TH PCAT-PRINT 1 "08 Mar 2006" "pcat utils"
.SH NAME
pcat-print \- reformat hexadecimal packets back to dig-like syntax
.SH SYNOPSIS
.B pcat-printp
[
.IR \-h
]
.IR PCAT_STREAM
.SH DESCRIPTION
\fBpcat-print\fR reads in a pcat file and reformats the hexadecimal
packets back into a dig-like syntax. If a packet cannot be transformed
back into a sane syntax an error is emitted.
This makes the manual inspection of the packets easier.
.PP
If no pcat file is given, standard input is read.
.SH OPTIONS
There are no options. Like \fBpcat-diff\fR this utility always does
what you want.
.SH OUTPUT FORMAT
\fBpcat-print\fR will output records.
Each record consists of an index and then three packets.
Each packet is separated by a line of '='s. All in all the output looks
like:
==========================
==========================
Index: xxx:yyy
==========================
query packet
==========================
first answer/query packet
==========================
second answer/query packet
==========================
.PP
For the index: xxx:yyy. xxx is the query ID of the first answer/query and
yyy is the query ID of the second one. These two IDs should match. The query
ID of the query packet is also equal to xxx.
.SH ALSO SEE
Also see pcat(1) and pcat-diff(1).
.SH AUTHOR
Written by Miek Gieben for NLnet Labs.
.SH REPORTING BUGS
Report bugs to <dns-team@nlnetlabs.nl>.
.SH COPYRIGHT
Copyright (C) 2005, 2006 NLnet Labs. This is free software. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.
.PP
Licensed under the BSD License.

View File

@@ -0,0 +1,88 @@
#define _GNU_SOURCE
#include "config.h"
#include <ldns/ldns.h>
#define SEQUENCE 1
#define QUERY 2
#define ANSWER1 3
#define ANSWER2 0
#define LINES 4
#ifndef HAVE_GETDELIM
ssize_t getdelim(char **lineptr, size_t *n, int delim, FILE *stream);
#endif
void
printf_bar(void)
{
fprintf(stdout, "===================================================================\n");
}
int
main(int argc, char **argv)
{
ssize_t read;
char *line;
size_t i, j, k, len;
u_char pkt_buf[LDNS_MAX_PACKETLEN];
ldns_pkt *p;
ldns_status s;
FILE *diff = stdin;
i = 1;
len = 0;
line = NULL;
if (argc > 1) {
if (!(diff = fopen(argv[1], "r"))) {
fprintf(stderr, "Cannot open pcat diff file `%s\'\n", argv[1]);
exit(EXIT_FAILURE);
}
}
while((read = getdelim(&line, &len, '\n', diff)) != -1) {
if (read < 2 || read > LDNS_MAX_PACKETLEN) {
if(read == 1)
fprintf(stdout, "NO ANSWER (line %d)\n", (int)i);
else
fprintf(stdout, "Under- or overflow (%d) - "
"skipping line %d\n", (int)read, (int)i);
i++;
printf_bar();
continue;
}
line[read - 1] = '\0';
switch(i % LINES) {
case SEQUENCE:
printf_bar();
fprintf(stdout, "Index: %s\n", line);
printf_bar();
break;
case QUERY:
case ANSWER1:
case ANSWER2:
k = 0;
for(j = 0; j < read - 1; j += 2) {
pkt_buf[k] =
ldns_hexdigit_to_int(line[j]) * 16 +
ldns_hexdigit_to_int(line[j + 1]);
k++;
}
s = ldns_wire2pkt(&p, pkt_buf, k);
fprintf(stdout, "=* %s\n", line);
if (s != LDNS_STATUS_OK) {
fprintf(stdout, "%s\n", ldns_get_errorstr_by_id(s));
} else {
ldns_pkt_print(stdout, p);
}
printf_bar();
break;
}
i++;
len = 0;
}
return 0;
}

View File

@@ -0,0 +1,59 @@
'\" t
.TH PCAT 1 "08 Mar 2006" "pcat utils"
.SH NAME
pcat \- (re)-send a pcap trace to a nameserver
.SH SYNOPSIS
.B pcat
[
.IR \-a
IP
]
[
.IR \-p
PORT
]
.IR PCAP_STRACE
.SH DESCRIPTION
\fBpcat\fR reads in a pcap trace file and re-sends the packet's payload
to a nameserver. It prints each query and the reply to standard output
is a hexadecimal format.
.PP
If no pcap file is given, standard input is read.
.SH OPTIONS
.TP
.B \-a IP
Use IP as address to send the queries to.
.TP
.B \-p PORT
Use PORT as port number.
.SH OUTPUT FORMAT
The output of \fBpcat\fR consists "records". Each record has four lines:
.PP
1. xxx - (decimal) sequence number
2. hex dump - query in hex, network order
3. hex dump - answer in hex, network order
4. empty line
The reason for the fourth line is that \fBpcat-print\fR can now parse
both \fBpcat\fRs and \fBpcat-diff\fRs output.
.PP
This format is dubbed: \fBpcat\fR.
.SH ALSO SEE
Also see pcat-print(1) and pcat-diff(1).
.SH AUTHOR
Written by Miek Gieben for NLnet Labs.
.SH REPORTING BUGS
Report bugs to <dns-team@nlnetlabs.nl>.
.SH COPYRIGHT
Copyright (C) 2005, 2006 NLnet Labs. This is free software. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.
.PP
Licensed under the BSD License.

View File

@@ -0,0 +1,311 @@
#ifdef HAVE_GETDELIM
#define _GNU_SOURCE
#endif
#include "config.h"
#ifdef HAVE_GETOPT_H
# include <getopt.h>
#endif
#include <ldns/ldns.h>
#include <errno.h>
#include <pcap.h>
#define FAILURE 10000
#ifndef ETHERTYPE_IPV6
#define ETHERTYPE_IPV6 0x86dd
#endif
#define DNS_UDP_OFFSET 42
#ifndef HAVE_GETDELIM
size_t getdelim(char **lineptr, size_t *n, int delim, FILE *stream);
#endif
/* output: see usage() */
void
usage(FILE *fp)
{
fprintf(fp, "pcat [-a IP] [-p PORT] [-r] PCAP_FILE\n\n");
fprintf(fp, " -a IP\tuse IP as nameserver, defaults to 127.0.0.1\n");
fprintf(fp, " -p PORT\tuse PORT as port, defaults to 53\n");
fprintf(fp, " -r \t\tthe file is a pcat output file to resend queries from\n");
fprintf(fp, " -h \t\tthis help\n");
fprintf(fp, " PCAP_FILE\tuse this file as source\n");
fprintf(fp, " If no file is given standard input is read\n");
fprintf(fp, "\nOUTPUT FORMAT:\n");
fprintf(fp, " Line based output format, each record consists of 3 lines:\n");
fprintf(fp, " 1. xxx\t\tdecimal sequence number\n");
fprintf(fp, " 2. hex dump\t\tquery in hex, network order\n");
fprintf(fp, " 3. hex dump\t\tanswer in hex, network order\n");
fprintf(fp, " 4. empty line\n");
fprintf(fp, " The reason for 4. is that pcat-print now can be used on the output of pcat.\n");
}
void
data2hex(FILE *fp, u_char *p, size_t l)
{
size_t i;
for(i = 0; i < l; i++) {
fprintf(fp, "%02x", (unsigned int) p[i]);
}
fputs("\n", fp);
}
/**
* Converts a hex string to binary data
* len is the length of the string
* buf is the buffer to store the result in
* offset is the starting position in the result buffer
*
* This function returns the length of the result
*/
static size_t
hexstr2bin(char *hexstr, int len, uint8_t *buf, size_t offset, size_t buf_len)
{
char c;
int i;
uint8_t int8 = 0;
int sec = 0;
size_t bufpos = 0;
if (len % 2 != 0) {
return 0;
}
for (i=0; i<len; i++) {
c = hexstr[i];
/* case insensitive, skip spaces */
if (c != ' ') {
if (c >= '0' && c <= '9') {
int8 += c & 0x0f;
} else if (c >= 'a' && c <= 'z') {
int8 += (c & 0x0f) + 9;
} else if (c >= 'A' && c <= 'Z') {
int8 += (c & 0x0f) + 9;
} else {
return 0;
}
if (sec == 0) {
int8 = int8 << 4;
sec = 1;
} else {
if (bufpos + offset + 1 <= buf_len) {
buf[bufpos+offset] = int8;
int8 = 0;
sec = 0;
bufpos++;
} else {
fprintf(stderr, "Buffer too small in hexstr2bin");
exit(1);
}
}
}
}
return bufpos;
}
u_char *
pcap2ldns_pkt_ip(const u_char *packet, struct pcap_pkthdr *h)
{
h->caplen -= DNS_UDP_OFFSET;
if (h->caplen < 0) {
return NULL;
} else {
return (u_char*)(packet + DNS_UDP_OFFSET);
}
}
u_char *
pcap2ldns_pkt(const u_char *packet, struct pcap_pkthdr *h)
{
struct ether_header *eptr;
eptr = (struct ether_header *) h;
switch(eptr->ether_type) {
case ETHERTYPE_IP:
return pcap2ldns_pkt_ip(packet, h);
break;
case ETHERTYPE_IPV6:
break;
case ETHERTYPE_ARP:
fprintf(stderr, "ARP pkt, dropping\n");
break;
default:
fprintf(stderr, "Not IP pkt, dropping\n");
break;
}
return 0;
}
int
main(int argc, char **argv)
{
char errbuf[PCAP_ERRBUF_SIZE];
pcap_t *p = NULL;
struct pcap_pkthdr h;
const u_char *x;
size_t i = 0;
ldns_rdf *ip;
char *ip_str;
int c;
size_t failure;
FILE *infile = NULL;
int pcat_input_file = 0;
uint8_t *result;
uint16_t port;
ldns_buffer *qpkt;
u_char *q;
size_t size;
socklen_t tolen;
size_t query_pkt_len;
struct timeval timeout;
struct sockaddr_storage *data;
struct sockaddr_in *data_in;
ldns_status send_status;
port = 0;
ip = NULL;
ip_str = NULL;
failure = 0;
while ((c = getopt(argc, argv, "ha:p:r")) != -1) {
switch(c) {
case 'h':
usage(stdout);
exit(EXIT_SUCCESS);
case 'a':
ip_str = optarg;
ip = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_A, optarg);
if (!ip) {
fprintf(stderr, "-a requires an IP address\n");
exit(EXIT_FAILURE);
}
break;
case 'r':
pcat_input_file = 1;
break;
case 'p':
port = atoi(optarg);
if (port == 0) {
fprintf(stderr, "-p requires a port number\n");
exit(EXIT_FAILURE);
}
break;
default:
usage(stdout);
exit(EXIT_FAILURE);
}
}
argc -= optind;
argv += optind;
if (port == 0)
port = 53;
if (!ip) {
ip_str = "127.0.0.1";
ip = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_A, "127.0.0.1");
}
if (pcat_input_file) {
if (argc < 1) {
infile = fopen("/dev/stdin", "r");
} else {
infile = fopen(argv[0], "r");
}
if (!infile) {
fprintf(stderr, "Cannot open input file: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
} else {
if (argc < 1) {
/* no file given - use standard input */
p = pcap_open_offline("/dev/stdin", errbuf);
} else {
p = pcap_open_offline(argv[0], errbuf);
}
if (!p) {
fprintf(stderr, "Cannot open pcap lib %s\n", errbuf);
exit(EXIT_FAILURE);
}
}
qpkt = ldns_buffer_new(LDNS_MAX_PACKETLEN);
data = LDNS_MALLOC(struct sockaddr_storage);
timeout.tv_sec = 5;
timeout.tv_usec = 0;
/* setup the socket */
data->ss_family = AF_INET;
data_in = (struct sockaddr_in*) data;
data_in->sin_port = (in_port_t)htons(port);
memcpy(&(data_in->sin_addr), ldns_rdf_data(ip), ldns_rdf_size(ip));
tolen = sizeof(struct sockaddr_in);
i = 1; /* start counting at 1 */
while (1) {
if(pcat_input_file) {
/* read pcat format and repeat query in it */
char buf[65535*2+100];
uint8_t decoded[65535+100];
if(!fgets(buf, sizeof(buf), infile)) /* number */
break;
if(!fgets(buf, sizeof(buf), infile)) /* query */
break;
query_pkt_len = hexstr2bin(buf, strlen(buf)&0xfffffffe,
decoded, 0, sizeof(decoded));
ldns_buffer_write(qpkt, decoded, query_pkt_len);
if(!fgets(buf, sizeof(buf), infile)) /* answer */
break;
if(!fgets(buf, sizeof(buf), infile)) /* empty line */
break;
} else {
if(!(x = pcap_next(p, &h)))
break;
q = pcap2ldns_pkt_ip(x, &h);
ldns_buffer_write(qpkt, q, h.caplen);
query_pkt_len = h.caplen;
}
send_status =ldns_udp_send(&result, qpkt, data, tolen, timeout, &size);
if (send_status == LDNS_STATUS_OK) {
/* double check if we are dealing with correct replies
* by converting to a pkt... todo */
fprintf(stdout, "%d\n", (int)i);
/* query */
data2hex(stdout, ldns_buffer_begin(qpkt), query_pkt_len);
/* answer */
data2hex(stdout, result, size);
fflush(stdout);
} else {
/* todo print failure */
failure++;
fprintf(stderr, "Failure to send packet %u (attempt %u, error %s)\n", i, (unsigned int) failure, ldns_get_errorstr_by_id(send_status));
fprintf(stdout, "%d\n", (int)i);
/* query */
data2hex(stdout, ldns_buffer_begin(qpkt), query_pkt_len);
/* answer, thus empty */
fprintf(stdout, "\n");
}
fputs("\n", stdout);
ldns_buffer_clear(qpkt);
i++;
if (failure > FAILURE) {
fprintf(stderr, "More than %u failures, bailing out\n", FAILURE);
exit(EXIT_FAILURE);
}
}
if(pcat_input_file)
fclose(infile);
else pcap_close(p);
return 0;
}

View File

@@ -0,0 +1,11 @@
maxpacketlen? We're are dealing with hex so it should prob. be
twice as large?
ipv6
tcp packets
better pcap payload inspection - currently it only works for udp,
ethernet
a speed setting to send queries faster?