summaryrefslogtreecommitdiff
path: root/regress
diff options
context:
space:
mode:
authorAlexander Bluhm <bluhm@cvs.openbsd.org>2013-06-05 04:34:28 +0000
committerAlexander Bluhm <bluhm@cvs.openbsd.org>2013-06-05 04:34:28 +0000
commit2e3d70900192e0ccffe93bb48352ee65789ebdd9 (patch)
treef4970ed15b28542600c0fc0c68cda0ac7a4338e1 /regress
parent3a2030f8d5c86b6fd26391f0992713849284d68b (diff)
Add tests for ICMP and ICMP6 divert-to.
Diffstat (limited to 'regress')
-rw-r--r--regress/sys/net/pf_divert/Client.pm19
-rw-r--r--regress/sys/net/pf_divert/Server.pm11
-rw-r--r--regress/sys/net/pf_divert/args-icmp-to.pl13
-rw-r--r--regress/sys/net/pf_divert/funcs.pl92
-rw-r--r--regress/sys/net/pf_divert/remote.pl47
5 files changed, 147 insertions, 35 deletions
diff --git a/regress/sys/net/pf_divert/Client.pm b/regress/sys/net/pf_divert/Client.pm
index 11c84151408..20787d41f2c 100644
--- a/regress/sys/net/pf_divert/Client.pm
+++ b/regress/sys/net/pf_divert/Client.pm
@@ -1,4 +1,4 @@
-# $OpenBSD: Client.pm,v 1.2 2013/06/04 04:17:42 bluhm Exp $
+# $OpenBSD: Client.pm,v 1.3 2013/06/05 04:34:27 bluhm Exp $
# Copyright (c) 2010-2013 Alexander Bluhm <bluhm@openbsd.org>
#
@@ -34,9 +34,10 @@ sub new {
$args{down} ||= $args{alarm} ? "Alarm" :
"Shutdown|Broken pipe|Connection reset by peer";
my $self = Proc::new($class, %args);
- $self->{protocol} ||= "tcp";
- $self->{connectdomain}
- or croak "$class connect domain not given";
+ $self->{domain}
+ or croak "$class domain not given";
+ $self->{protocol}
+ or croak "$class protocol not given";
$self->{connectaddr}
or croak "$class connect addr not given";
$self->{connectport} || $self->{protocol} !~ /^(tcp|udp)$/
@@ -47,20 +48,20 @@ sub new {
do { local $> = 0; $cs = IO::Socket::INET6->new(
Type => $self->{socktype},
Proto => $self->{protocol},
- Domain => $self->{connectdomain},
+ Domain => $self->{domain},
Blocking => ($self->{nonblocking} ? 0 : 1),
) } or die ref($self), " socket connect failed: $!";
do { local $> = 0; $cs->setsockopt(SOL_SOCKET, SO_BINDANY, 1) }
or die ref($self), " setsockopt SO_BINDANY failed: $!";
my @rres = getaddrinfo($self->{bindaddr}, $self->{bindport}||0,
- $self->{connectdomain}, SOCK_STREAM, 0, AI_PASSIVE);
+ $self->{domain}, SOCK_STREAM, 0, AI_PASSIVE);
$cs->bind($rres[3])
or die ref($self), " bind failed: $!";
} elsif ($self->{bindaddr} || $self->{bindport}) {
do { local $> = 0; $cs = IO::Socket::INET6->new(
Type => $self->{socktype},
Proto => $self->{protocol},
- Domain => $self->{connectdomain},
+ Domain => $self->{domain},
Blocking => ($self->{nonblocking} ? 0 : 1),
LocalAddr => $self->{bindaddr},
LocalPort => $self->{bindport},
@@ -81,7 +82,7 @@ sub child {
my $cs = $self->{cs} || do { local $> = 0; IO::Socket::INET6->new(
Type => $self->{socktype},
Proto => $self->{protocol},
- Domain => $self->{connectdomain},
+ Domain => $self->{domain},
Blocking => ($self->{nonblocking} ? 0 : 1),
) } or die ref($self), " socket connect failed: $!";
if ($self->{oobinline}) {
@@ -103,7 +104,7 @@ sub child {
or die ref($self), " set nodelay connect failed: $!";
}
my @rres = getaddrinfo($self->{connectaddr}, $self->{connectport},
- $self->{connectdomain}, SOCK_STREAM);
+ $self->{domain}, SOCK_STREAM);
$cs->connect($rres[3])
or die ref($self), " connect failed: $!";
print STDERR "connect sock: ",$cs->sockhost()," ",$cs->sockport(),"\n";
diff --git a/regress/sys/net/pf_divert/Server.pm b/regress/sys/net/pf_divert/Server.pm
index d0f1fafbe9e..6e737996df1 100644
--- a/regress/sys/net/pf_divert/Server.pm
+++ b/regress/sys/net/pf_divert/Server.pm
@@ -1,4 +1,4 @@
-# $OpenBSD: Server.pm,v 1.2 2013/06/04 04:17:42 bluhm Exp $
+# $OpenBSD: Server.pm,v 1.3 2013/06/05 04:34:27 bluhm Exp $
# Copyright (c) 2010-2013 Alexander Bluhm <bluhm@openbsd.org>
#
@@ -31,14 +31,15 @@ sub new {
$args{logfile} ||= "server.log";
$args{up} ||= "Accepted";
my $self = Proc::new($class, %args);
- $self->{protocol} ||= "tcp";
- $self->{listendomain}
- or croak "$class listen domain not given";
+ $self->{domain}
+ or croak "$class domain not given";
+ $self->{protocol}
+ or croak "$class protocol not given";
my $ls = do { local $> = 0; IO::Socket::INET6->new(
Type => $self->{socktype},
Proto => $self->{protocol},
ReuseAddr => 1,
- Domain => $self->{listendomain},
+ Domain => $self->{domain},
$self->{listenaddr} ? (LocalAddr => $self->{listenaddr}) : (),
$self->{listenport} ? (LocalPort => $self->{listenport}) : (),
) } or die ref($self), " socket failed: $!";
diff --git a/regress/sys/net/pf_divert/args-icmp-to.pl b/regress/sys/net/pf_divert/args-icmp-to.pl
new file mode 100644
index 00000000000..172dea9322a
--- /dev/null
+++ b/regress/sys/net/pf_divert/args-icmp-to.pl
@@ -0,0 +1,13 @@
+# test divert-to with icmp
+
+use strict;
+use warnings;
+use Socket;
+
+our %args = (
+ socktype => Socket::SOCK_RAW,
+ protocol => sub { shift->{af} eq "inet" ? "icmp" : "icmp6" },
+ client => { func => \&write_icmp_echo, out => "ICMP", noin => 1, },
+ server => { func => \&read_icmp_echo, in => "ICMP", noout => 1, },
+ divert => "to",
+);
diff --git a/regress/sys/net/pf_divert/funcs.pl b/regress/sys/net/pf_divert/funcs.pl
index 3fb71811d89..91987d156ef 100644
--- a/regress/sys/net/pf_divert/funcs.pl
+++ b/regress/sys/net/pf_divert/funcs.pl
@@ -1,4 +1,4 @@
-# $OpenBSD: funcs.pl,v 1.3 2013/06/04 04:17:42 bluhm Exp $
+# $OpenBSD: funcs.pl,v 1.4 2013/06/05 04:34:27 bluhm Exp $
# Copyright (c) 2010-2013 Alexander Bluhm <bluhm@openbsd.org>
#
@@ -59,6 +59,84 @@ sub read_datagram {
print STDERR "<<< $in";
}
+sub in_cksum {
+ my $data = shift;
+ my $sum = 0;
+
+ $data .= pack("x") if (length($data) & 1);
+ while (length($data)) {
+ $sum += unpack("n", substr($data, 0, 2, ""));
+ $sum = ($sum >> 16) + ($sum & 0xffff) if ($sum > 0xffff);
+ }
+ return (~$sum & 0xffff);
+}
+
+use constant IPPROTO_ICMPV6 => 58;
+use constant ICMP_ECHO => 8;
+use constant ICMP6_ECHO_REQUEST => 128;
+
+my $seq = 0;
+sub write_icmp_echo {
+ my $self = shift;
+ my $af = $self->{af};
+
+ my $type = $af eq "inet" ? ICMP_ECHO : ICMP6_ECHO_REQUEST;
+ # type, code, cksum, id, seq
+ my $icmp = pack("CCnnn", $type, 0, 0, $$, ++$seq);
+ if ($af eq "inet") {
+ substr($icmp, 2, 2, pack("n", in_cksum($icmp)));
+ } else {
+ # src, dst, plen, pad, next
+ my $phdr = "";
+ $phdr .= inet_pton(AF_INET6, $self->{srcaddr});
+ $phdr .= inet_pton(AF_INET6, $self->{dstaddr});
+ $phdr .= pack("NxxxC", length($icmp), IPPROTO_ICMPV6);
+ print STDERR "pseudo header: ", unpack("H*", $phdr), "\n";
+ substr($icmp, 2, 2, pack("n", in_cksum($phdr. $icmp)));
+ }
+
+ print $icmp;
+ IO::Handle::flush(\*STDOUT);
+ my $text = $af eq "inet" ? "ICMP" : "ICMP6";
+ print STDERR ">>> $text ", unpack("H*", $icmp), "\n";
+}
+
+sub read_icmp_echo {
+ my $self = shift;
+ my $af = $self->{af};
+
+ # Raw sockets include the IPv4 header.
+ sysread(STDIN, my $icmp, 70000);
+ # Cut the header off.
+ if ($af eq "inet") {
+ substr($icmp, 0, 20, "");
+ }
+
+ my $text = $af eq "inet" ? "ICMP" : "ICMP6";
+ my $phdr = "";
+ if ($af eq "inet6") {
+ # src, dst, plen, pad, next
+ $phdr .= inet_pton(AF_INET6, $self->{srcaddr});
+ $phdr .= inet_pton(AF_INET6, $self->{dstaddr});
+ $phdr .= pack("NxxxC", length($icmp), IPPROTO_ICMPV6);
+ print STDERR "pseudo header: ", unpack("H*", $phdr), "\n";
+ }
+ if (length($icmp) < 8) {
+ $text = "BAD $text LENGTH";
+ } elsif (in_cksum($phdr. $icmp) != 0) {
+ $text = "BAD $text CHECKSUM";
+ } else {
+ my($type, $code, $cksum, $id, $seq) = unpack("CCnnn", $icmp);
+ if ($type != ($af eq "inet" ? ICMP_ECHO : ICMP6_ECHO_REQUEST)) {
+ $text = "BAD $text TYPE";
+ } elsif ($code != 0) {
+ $text = "BAD $text CODE";
+ }
+ }
+
+ print STDERR "<<< $text ", unpack("H*", $icmp), "\n";
+}
+
########################################################################
# Script funcs
########################################################################
@@ -75,15 +153,19 @@ sub check_inout {
my ($c, $s, %args) = @_;
if ($c && !$args{client}{nocheck}) {
- $c->loggrep(qr/^>>> Client$/) or die "no client output"
+ my $out = $args{client}{out} || "Client";
+ $c->loggrep(qr/^>>> $out/) or die "no client output"
unless $args{client}{noout};
- $c->loggrep(qr/^<<< Server$/) or die "no client input"
+ my $in = $args{client}{in} || "Server";
+ $c->loggrep(qr/^<<< $in/) or die "no client input"
unless $args{client}{noin};
}
if ($s && !$args{server}{nocheck}) {
- $s->loggrep(qr/^>>> Server$/) or die "no server output"
+ my $out = $args{server}{out} || "Server";
+ $s->loggrep(qr/^>>> $out/) or die "no server output"
unless $args{server}{noout};
- $s->loggrep(qr/^<<< Client$/) or die "no server input"
+ my $in = $args{server}{in} || "Client";
+ $s->loggrep(qr/^<<< $in/) or die "no server input"
unless $args{server}{noin};
}
}
diff --git a/regress/sys/net/pf_divert/remote.pl b/regress/sys/net/pf_divert/remote.pl
index 30992ef5658..15c9ebf041d 100644
--- a/regress/sys/net/pf_divert/remote.pl
+++ b/regress/sys/net/pf_divert/remote.pl
@@ -1,5 +1,5 @@
#!/usr/bin/perl
-# $OpenBSD: remote.pl,v 1.3 2013/06/04 04:17:42 bluhm Exp $
+# $OpenBSD: remote.pl,v 1.4 2013/06/05 04:34:27 bluhm Exp $
# Copyright (c) 2010-2013 Alexander Bluhm <bluhm@openbsd.org>
#
@@ -47,18 +47,21 @@ EOF
my $test;
our %args;
-if (@ARGV and -f $ARGV[-1]) {
+if (@ARGV) {
$test = pop;
do $test
or die "Do test file $test failed: ", $@ || $!;
}
-my($af, $domain);
+my($af, $domain, $protocol);
if (@ARGV) {
$af = shift;
$domain =
$af eq "inet" ? AF_INET :
$af eq "inet6" ? AF_INET6 :
die "address family must be 'inet' or 'inet6\n";
+ $protocol = $args{protocol};
+ $protocol = $protocol->({ %args, af => $af, domain => $domain, })
+ if ref $protocol eq 'CODE';
}
my $mode =
@ARGV == 3 && $ARGV[0] !~ /^\d+$/ && $ARGV[2] =~ /^\d+$/ ? "divert" :
@@ -66,33 +69,42 @@ my $mode =
usage();
my($c, $l, $r, $s, $logfile);
-my $func = \&write_read_stream;
-my $divert = $args{divert} || "to";
-my $local = $divert eq "to" ? "client" : "server";
-my $remote = $divert eq "to" ? "server" : "client";
+my $func = \&write_read_stream;
+my $divert = $args{divert} || "to";
+my $local = $divert eq "to" ? "client" : "server";
+my $remote = $divert eq "to" ? "server" : "client";
if ($mode eq "divert") {
$local = $divert eq "to" ? "server" : "client";
+ $remote = $divert eq "to" ? "client" : "server";
$logfile = dirname($0)."/remote.log";
}
+my $srcaddr = $ARGV[0];
+my $dstaddr = $ARGV[1];
+if ($mode eq "divert" xor $divert eq "reply") {
+ ($srcaddr, $dstaddr) = ($dstaddr, $srcaddr);
+}
if ($local eq "server") {
$l = $s = Server->new(
func => $func,
%args,
%{$args{server}},
- af => $af,
logfile => $logfile,
- listendomain => $domain,
+ af => $af,
+ domain => $domain,
+ protocol => $protocol,
listenaddr => $mode ne "divert" ? $ARGV[0] :
$af eq "inet" ? "127.0.0.1" : "::1",
+ srcaddr => $srcaddr,
+ dstaddr => $dstaddr,
);
}
if ($mode eq "auto") {
$r = Remote->new(
%args,
- af => $af,
logfile => "$remote.log",
testfile => $test,
+ af => $af,
remotessh => $ARGV[2],
bindaddr => $ARGV[1],
connect => $remote eq "client",
@@ -108,13 +120,16 @@ if ($local eq "client") {
func => $func,
%args,
%{$args{client}},
- af => $af,
logfile => $logfile,
- connectdomain => $domain,
+ af => $af,
+ domain => $domain,
+ protocol => $protocol,
connectaddr => $ARGV[1],
connectport => $r ? $r->{listenport} : $ARGV[2],
bindany => $mode eq "divert",
bindaddr => $ARGV[0],
+ srcaddr => $srcaddr,
+ dstaddr => $dstaddr,
);
}
@@ -134,16 +149,16 @@ if ($mode eq "divert") {
do { local $> = 0; open($pf, '|-', @cmd) }
or die "Open pipe to pf '@cmd' failed: $!";
if ($local eq "server") {
- my $port = $args{protocol} =~ /^(tcp|udp)$/ ?
+ my $port = $protocol =~ /^(tcp|udp)$/ ?
"port $s->{listenport}" : "";
my $divertport = $port || "port 1"; # XXX bad pf syntax
- print $pf "pass in log $af proto $args{protocol} ".
+ print $pf "pass in log $af proto $protocol ".
"from $ARGV[1] to $ARGV[0] $port ".
"divert-to $s->{listenaddr} $divertport\n";
} else {
- my $port = $args{protocol} =~ /^(tcp|udp)$/ ?
+ my $port = $protocol =~ /^(tcp|udp)$/ ?
"port $ARGV[2]" : "";
- print $pf "pass out log $af proto $args{protocol} ".
+ print $pf "pass out log $af proto $protocol ".
"from $c->{bindaddr} to $ARGV[1] $port divert-reply\n";
}
close($pf) or die $! ?