bind9/bin/tests/system/packet.pl
Mark Andrews 20bc6aefff Check rcode is FORMERR
(cherry picked from commit 88ff6b846c)
2020-08-04 23:04:34 +10:00

133 lines
3.2 KiB
Perl

#!/usr/bin/perl
#
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# See the COPYRIGHT file distributed with this work for additional
# information regarding copyright ownership.
# This is a tool for sending an arbitrary packet via UDP or TCP to an
# arbitrary address and port. The packet is specified in a file or on
# the standard input, in the form of a series of bytes in hexadecimal.
# Whitespace is ignored, as is anything following a '#' symbol.
#
# For example, the following input would generate normal query for
# isc.org/NS/IN":
#
# # QID:
# 0c d8
# # header:
# 01 00 00 01 00 00 00 00 00 00
# # qname isc.org:
# 03 69 73 63 03 6f 72 67 00
# # qtype NS:
# 00 02
# # qclass IN:
# 00 01
#
# Note that we do not wait for a response for the server. This is simply
# a way of injecting arbitrary packets to test server resposnes.
#
# Usage: packet.pl [-a <address>] [-p <port>] [-t (udp|tcp)] [filename]
#
# If not specified, address defaults to 127.0.0.1, port to 53, protocol
# to udp, and file to stdin.
#
# XXX: Doesn't support IPv6 yet
require 5.006.001;
use strict;
use Getopt::Std;
use IO::File;
use IO::Socket;
sub usage {
print ("Usage: packet.pl [-a address] [-p port] [-t (tcp|udp)] -d [file]\n");
exit 1;
}
my %options={};
getopts("a:dp:t:", \%options);
my $addr = "127.0.0.1";
$addr = $options{a} if defined $options{a};
my $port = 53;
$port = $options{p} if defined $options{p};
my $proto = "udp";
$proto = lc $options{t} if defined $options{t};
usage if ($proto !~ /^(udp|tcp)$/);
my $file = "STDIN";
if (@ARGV >= 1) {
my $filename = shift @ARGV;
open FH, "<$filename" or die "$filename: $!";
$file = "FH";
}
my $input = "";
while (defined(my $line = <$file>) ) {
chomp $line;
$line =~ s/#.*$//;
$input .= $line;
}
$input =~ s/\s+//g;
my $data = pack("H*", $input);
my $len = length $data;
my $output = unpack("H*", $data);
print ("sending: $output\n");
my $sock = IO::Socket::INET->new(PeerAddr => $addr, PeerPort => $port,
Proto => $proto,) or die "$!";
my $bytes;
if ($proto eq "udp") {
$bytes = $sock->send($data);
} else {
$bytes = $sock->syswrite(pack("n", $len), 2);
$bytes += $sock->syswrite($data, $len);
}
print ("sent $bytes bytes to $addr:$port\n");
if (defined $options{d}) {
use Net::DNS;
use Net::DNS::Packet;
my $rin;
my $rout;
$rin = '';
vec($rin, fileno($sock), 1) = 1;
select($rout = $rin, undef, undef, 1);
if (vec($rout, fileno($sock), 1)) {{
my $buf;
if ($proto eq "udp") {
$sock->recv($buf, 512);
} else {
my $n = $sock->sysread($buf, 2);
last unless $n == 2;
my $len = unpack("n", $buf);
$n = $sock->sysread($buf, $len);
last unless $n == $len;
}
my $response;
if ($Net::DNS::VERSION > 0.68) {
$response = new Net::DNS::Packet(\$buf, 0);
$@ and die $@;
} else {
my $err;
($response, $err) = new Net::DNS::Packet(\$buf, 0);
$err and die $err;
}
$response->print;
}}
}
$sock->close;
close $file;