summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--regress/sys/net/pf_divert/LICENSE2
-rw-r--r--regress/sys/net/pf_divert/Makefile6
-rw-r--r--regress/sys/net/pf_divert/README48
-rw-r--r--regress/sys/net/pf_divert/args-icmp-reply-reuse.pl23
-rw-r--r--regress/sys/net/pf_divert/args-icmp-reply-to.pl21
-rw-r--r--regress/sys/net/pf_divert/args-icmp-to.pl10
-rw-r--r--regress/sys/net/pf_divert/args-rip-reply-to.pl27
-rw-r--r--regress/sys/net/pf_divert/args-rip-reply.pl11
-rw-r--r--regress/sys/net/pf_divert/args-rip-to.pl11
-rw-r--r--regress/sys/net/pf_divert/args-tcp-reply.pl6
-rw-r--r--regress/sys/net/pf_divert/args-tcp-to.pl6
-rw-r--r--regress/sys/net/pf_divert/args-udp-reply-to.pl26
-rw-r--r--regress/sys/net/pf_divert/args-udp-reply.pl8
-rw-r--r--regress/sys/net/pf_divert/args-udp-to.pl8
-rw-r--r--regress/sys/net/pf_divert/funcs.pl100
-rw-r--r--regress/sys/net/pf_divert/remote.pl13
16 files changed, 258 insertions, 68 deletions
diff --git a/regress/sys/net/pf_divert/LICENSE b/regress/sys/net/pf_divert/LICENSE
index a6e1dd38fcf..407681ad0a6 100644
--- a/regress/sys/net/pf_divert/LICENSE
+++ b/regress/sys/net/pf_divert/LICENSE
@@ -1,4 +1,4 @@
-# Copyright (c) 2010-2014 Alexander Bluhm <bluhm@openbsd.org>
+# Copyright (c) 2010-2015 Alexander Bluhm <bluhm@openbsd.org>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
diff --git a/regress/sys/net/pf_divert/Makefile b/regress/sys/net/pf_divert/Makefile
index b2917173084..f2798df2c68 100644
--- a/regress/sys/net/pf_divert/Makefile
+++ b/regress/sys/net/pf_divert/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.11 2014/08/18 22:58:19 bluhm Exp $
+# $OpenBSD: Makefile,v 1.12 2015/07/28 12:31:29 bluhm Exp $
# The following ports must be installed for the regression tests:
# p5-IO-Socket-INET6 object interface for AF_INET and AF_INET6 domain sockets
@@ -54,9 +54,13 @@ TARGETS ?= inet-args-tcp-to inet6-args-tcp-to \
inet-args-tcp-reply inet6-args-tcp-reply \
inet-args-udp-to inet6-args-udp-to \
inet-args-udp-reply inet6-args-udp-reply \
+ inet-args-udp-reply-to inet6-args-udp-reply-to \
inet-args-rip-to inet6-args-rip-to \
inet-args-rip-reply inet6-args-rip-reply \
+ inet-args-rip-reply-to inet6-args-rip-reply-to \
inet-args-icmp-to inet6-args-icmp-to \
+ inet-args-icmp-reply-to inet6-args-icmp-reply-to \
+ inet-args-icmp-reply-reuse inet6-args-icmp-reply-reuse \
inet-reuse-tcp inet6-reuse-tcp \
inet-reuse-udp inet6-reuse-udp \
inet-reuse-rip inet6-reuse-rip
diff --git a/regress/sys/net/pf_divert/README b/regress/sys/net/pf_divert/README
new file mode 100644
index 00000000000..ffa90c0a0b5
--- /dev/null
+++ b/regress/sys/net/pf_divert/README
@@ -0,0 +1,48 @@
+Run pf divert-to and divert-reply regression test. The framework
+runs both a client and a server process. One process is started
+on the local and the other one on the remote machine. The kernel's
+pf of the remote machine gets tested. The remote machine's pf.conf
+must contain an anchor named "regress" where the test places its
+divert rules automatically. All tests are done with IPv4 and IPv6.
+
+The protocols TCP, UDP, Raw IP, ICMP get tested. TCP uses a listen
+and a connected stream socket, the others use bound and possibly
+connected datagram sockets. Over the TCP connection messages are
+sent on both directions. The datagram sockets deal with single
+packets. The remote machine can be reached over a non existing
+address which is diverted to the stack.
+
+The args-...-to tests install an incoming divert-to pf rule on the
+remote machine and run a server there. The server binds to the
+localhost address, for TCP it also listens and accepts. The client
+is started on the local machine and connects to the non existing
+address of the remote machine. For TCP the bidirectional connection,
+for the others a singe packet from the client has to reach the
+server.
+
+The args-...-reply tests install an outgoing divert-reply pf rule
+on the remote machine and start a client there. The client binds
+with bindany to the non existing address and connects to the local
+machine's address. The server is run on the local machine, for TCP
+it also listens and accepts. For TCP the bidirectional connection,
+for the others a singe packet from the client has to reach the
+server.
+
+The args-...-reply-to tests use the same setup as the args-...-reply
+tests. But addtitionally to the packet from the client to the
+server, the server sends a packet back which has to be received by
+the client. To figure out the client's address and port, the server
+receives with recvfrom and sends back with sendto. The args-icmp-reply-to
+test does not use a server as the kernel of the local machine
+automatically reflects the ICMP echo request packet with an reply.
+
+The args-icmp-reply-reuse test is similar to the args-icmp-reply-to
+test, but it sends two ICMP echo requests and expects two ICMP echo
+replies. All four packets use the same socket. The second echo
+has a different ID, so it cannot use the same pf state. Check that
+the second reply reaches the client. This can only work, if pf
+creates a second outgoing state although all packet use one socket.
+
+The reuse-... tests run the corresponding args-...-reply and
+args-...-to tests consecutively to check that the pf states to not
+interfere.
diff --git a/regress/sys/net/pf_divert/args-icmp-reply-reuse.pl b/regress/sys/net/pf_divert/args-icmp-reply-reuse.pl
new file mode 100644
index 00000000000..f8cd4553ee8
--- /dev/null
+++ b/regress/sys/net/pf_divert/args-icmp-reply-reuse.pl
@@ -0,0 +1,23 @@
+# test divert-reply with icmp and socket reuse
+
+use strict;
+use warnings;
+use Socket;
+
+our %args = (
+ socktype => Socket::SOCK_RAW,
+ protocol => sub { shift->{af} eq "inet" ? "icmp" : "icmp6" },
+ client => {
+ func => sub {
+ my $self = shift;
+ write_icmp_echo($self, $$);
+ read_icmp_echo($self, "reply");
+ write_icmp_echo($self, $$+1);
+ read_icmp_echo($self, "reply");
+ },
+ out => "ICMP6?",
+ in => "ICMP6? reply",
+ },
+ # no server as our kernel does the icmp reply automatically
+ divert => "reply",
+);
diff --git a/regress/sys/net/pf_divert/args-icmp-reply-to.pl b/regress/sys/net/pf_divert/args-icmp-reply-to.pl
new file mode 100644
index 00000000000..29667a153b1
--- /dev/null
+++ b/regress/sys/net/pf_divert/args-icmp-reply-to.pl
@@ -0,0 +1,21 @@
+# test divert-reply with icmp with out and in packet
+
+use strict;
+use warnings;
+use Socket;
+
+our %args = (
+ socktype => Socket::SOCK_RAW,
+ protocol => sub { shift->{af} eq "inet" ? "icmp" : "icmp6" },
+ client => {
+ func => sub {
+ my $self = shift;
+ write_icmp_echo($self);
+ read_icmp_echo($self, "reply");
+ },
+ out => "ICMP6?",
+ in => "ICMP6? reply",
+ },
+ # no server as our kernel does the icmp reply automatically
+ divert => "reply",
+);
diff --git a/regress/sys/net/pf_divert/args-icmp-to.pl b/regress/sys/net/pf_divert/args-icmp-to.pl
index 172dea9322a..45d3a74ae17 100644
--- a/regress/sys/net/pf_divert/args-icmp-to.pl
+++ b/regress/sys/net/pf_divert/args-icmp-to.pl
@@ -5,9 +5,9 @@ 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",
+ socktype => Socket::SOCK_RAW,
+ protocol => sub { shift->{af} eq "inet" ? "icmp" : "icmp6" },
+ client => { func => \&write_icmp_echo, out => "ICMP6?", noin => 1, },
+ server => { func => \&read_icmp_echo, in => "ICMP6?", noout => 1, },
+ divert => "to",
);
diff --git a/regress/sys/net/pf_divert/args-rip-reply-to.pl b/regress/sys/net/pf_divert/args-rip-reply-to.pl
new file mode 100644
index 00000000000..b8e3a0aaaff
--- /dev/null
+++ b/regress/sys/net/pf_divert/args-rip-reply-to.pl
@@ -0,0 +1,27 @@
+# test divert-reply with raw ip with out and in packet
+
+use strict;
+use warnings;
+use Socket;
+
+our %args = (
+ socktype => Socket::SOCK_RAW,
+ protocol => 254,
+ client => {
+ func => sub {
+ my $self = shift;
+ write_datagram($self);
+ read_datagram($self);
+ },
+ },
+ server => {
+ func => sub {
+ my $self = shift;
+ read_datagram($self);
+ $self->{toaddr} = $self->{fromaddr};
+ $self->{toport} = $self->{fromport};
+ write_datagram($self);
+ },
+ },
+ divert => "reply",
+);
diff --git a/regress/sys/net/pf_divert/args-rip-reply.pl b/regress/sys/net/pf_divert/args-rip-reply.pl
index 1c71ecddb20..0744f48fe76 100644
--- a/regress/sys/net/pf_divert/args-rip-reply.pl
+++ b/regress/sys/net/pf_divert/args-rip-reply.pl
@@ -5,10 +5,9 @@ use warnings;
use Socket;
our %args = (
- socktype => Socket::SOCK_RAW,
- protocol => 254,
- skip => sub { shift->{af} eq "inet" ? 20 : 0 },
- client => { func => \&write_datagram, noin => 1, },
- server => { func => \&read_datagram, noout => 1, },
- divert => "reply",
+ socktype => Socket::SOCK_RAW,
+ protocol => 254,
+ client => { func => \&write_datagram, noin => 1, },
+ server => { func => \&read_datagram, noout => 1, },
+ divert => "reply",
);
diff --git a/regress/sys/net/pf_divert/args-rip-to.pl b/regress/sys/net/pf_divert/args-rip-to.pl
index 2fd414eb33c..19ba8fa6100 100644
--- a/regress/sys/net/pf_divert/args-rip-to.pl
+++ b/regress/sys/net/pf_divert/args-rip-to.pl
@@ -5,10 +5,9 @@ use warnings;
use Socket;
our %args = (
- socktype => Socket::SOCK_RAW,
- protocol => 254,
- skip => sub { shift->{af} eq "inet" ? 20 : 0 },
- client => { func => \&write_datagram, noin => 1, },
- server => { func => \&read_datagram, noout => 1, },
- divert => "to",
+ socktype => Socket::SOCK_RAW,
+ protocol => 254,
+ client => { func => \&write_datagram, noin => 1, },
+ server => { func => \&read_datagram, noout => 1, },
+ divert => "to",
);
diff --git a/regress/sys/net/pf_divert/args-tcp-reply.pl b/regress/sys/net/pf_divert/args-tcp-reply.pl
index 82d435632d9..8bf599cb01a 100644
--- a/regress/sys/net/pf_divert/args-tcp-reply.pl
+++ b/regress/sys/net/pf_divert/args-tcp-reply.pl
@@ -4,6 +4,8 @@ use strict;
use warnings;
our %args = (
- protocol => "tcp",
- divert => "reply",
+ protocol => "tcp",
+ client => { func => \&write_read_stream },
+ server => { func => \&write_read_stream },
+ divert => "reply",
);
diff --git a/regress/sys/net/pf_divert/args-tcp-to.pl b/regress/sys/net/pf_divert/args-tcp-to.pl
index 0e67e4c873e..b99b0772760 100644
--- a/regress/sys/net/pf_divert/args-tcp-to.pl
+++ b/regress/sys/net/pf_divert/args-tcp-to.pl
@@ -4,6 +4,8 @@ use strict;
use warnings;
our %args = (
- protocol => "tcp",
- divert => "to",
+ protocol => "tcp",
+ client => { func => \&write_read_stream },
+ server => { func => \&write_read_stream },
+ divert => "to",
);
diff --git a/regress/sys/net/pf_divert/args-udp-reply-to.pl b/regress/sys/net/pf_divert/args-udp-reply-to.pl
new file mode 100644
index 00000000000..c77088c9557
--- /dev/null
+++ b/regress/sys/net/pf_divert/args-udp-reply-to.pl
@@ -0,0 +1,26 @@
+# test divert-reply with udp with out and in packet
+
+use strict;
+use warnings;
+use Socket;
+
+our %args = (
+ protocol => "udp",
+ client => {
+ func => sub {
+ my $self = shift;
+ write_datagram($self);
+ read_datagram($self);
+ },
+ },
+ server => {
+ func => sub {
+ my $self = shift;
+ read_datagram($self);
+ $self->{toaddr} = $self->{fromaddr};
+ $self->{toport} = $self->{fromport};
+ write_datagram($self);
+ },
+ },
+ divert => "reply",
+);
diff --git a/regress/sys/net/pf_divert/args-udp-reply.pl b/regress/sys/net/pf_divert/args-udp-reply.pl
index 7e2c5a77f37..e78d572cb17 100644
--- a/regress/sys/net/pf_divert/args-udp-reply.pl
+++ b/regress/sys/net/pf_divert/args-udp-reply.pl
@@ -4,8 +4,8 @@ use strict;
use warnings;
our %args = (
- protocol => "udp",
- client => { func => \&write_datagram, noin => 1, },
- server => { func => \&read_datagram, noout => 1, },
- divert => "reply",
+ protocol => "udp",
+ client => { func => \&write_datagram, noin => 1, },
+ server => { func => \&read_datagram, noout => 1, },
+ divert => "reply",
);
diff --git a/regress/sys/net/pf_divert/args-udp-to.pl b/regress/sys/net/pf_divert/args-udp-to.pl
index 673f7233705..2469dc42de5 100644
--- a/regress/sys/net/pf_divert/args-udp-to.pl
+++ b/regress/sys/net/pf_divert/args-udp-to.pl
@@ -4,8 +4,8 @@ use strict;
use warnings;
our %args = (
- protocol => "udp",
- client => { func => \&write_datagram, noin => 1, },
- server => { func => \&read_datagram, noout => 1, },
- divert => "to",
+ protocol => "udp",
+ client => { func => \&write_datagram, noin => 1, },
+ server => { func => \&read_datagram, noout => 1, },
+ divert => "to",
);
diff --git a/regress/sys/net/pf_divert/funcs.pl b/regress/sys/net/pf_divert/funcs.pl
index 91987d156ef..a47b7c4a409 100644
--- a/regress/sys/net/pf_divert/funcs.pl
+++ b/regress/sys/net/pf_divert/funcs.pl
@@ -1,6 +1,6 @@
-# $OpenBSD: funcs.pl,v 1.4 2013/06/05 04:34:27 bluhm Exp $
+# $OpenBSD: funcs.pl,v 1.5 2015/07/28 12:31:29 bluhm Exp $
-# Copyright (c) 2010-2013 Alexander Bluhm <bluhm@openbsd.org>
+# Copyright (c) 2010-2015 Alexander Bluhm <bluhm@openbsd.org>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
@@ -16,6 +16,8 @@
use strict;
use warnings;
+use Socket;
+use Socket6;
########################################################################
# Client and Server funcs
@@ -35,28 +37,65 @@ sub write_read_stream {
sub write_datagram {
my $self = shift;
+ my $dgram = shift;
+
+ my $out = $dgram || ref($self). "\n";
+ my $addr = $self->{toaddr};
+ my $port = $self->{toport};
+ if ($addr) {
+ my ($to, $netaddr);
+ if ($self->{af} eq "inet") {
+ $netaddr = inet_pton(AF_INET, $addr);
+ $to = pack_sockaddr_in($port, $netaddr);
+ } else {
+ $netaddr = inet_pton(AF_INET6, $addr);
+ $to = pack_sockaddr_in6($port, $netaddr);
+ }
+ $self->{toaddr} = $addr;
+ $self->{toport} = $port;
+ print STDERR "send to: $addr $port\n";
- my $out = ref($self). "\n";
- print $out;
- IO::Handle::flush(\*STDOUT);
- print STDERR ">>> $out";
+ send(STDIN, $out, 0, $to)
+ or die ref($self), " send to failed: $!";
+ } else {
+ send(STDIN, $out, 0)
+ or die ref($self), " send failed: $!";
+ }
+
+ unless ($dgram) {
+ print STDERR ">>> $out";
+ }
}
sub read_datagram {
my $self = shift;
- my $skip = $self->{skip};
- $skip = $skip->($self) if ref $skip eq 'CODE';
-
- my $in;
- if ($skip) {
- # Raw sockets include the IPv4 header.
- sysread(STDIN, $in, 70000);
- # Cut the header off.
- substr($in, 0, $skip, "");
+ my $dgram = shift;
+
+ my $from = recv(STDIN, my $in, 70000, 0)
+ or die ref($self), " recv from failed: $!";
+ # Raw sockets include the IPv4 header.
+ if ($self->{socktype} && $self->{socktype} == Socket::SOCK_RAW &&
+ $self->{af} eq "inet") {
+ substr($in, 0, 20, "");
+ }
+
+ my ($port, $netaddr, $addr);
+ if ($self->{af} eq "inet") {
+ ($port, $netaddr) = unpack_sockaddr_in($from);
+ $addr = inet_ntop(AF_INET, $netaddr);
} else {
- $in = <STDIN>;
+ ($port, $netaddr) = unpack_sockaddr_in6($from);
+ $addr = inet_ntop(AF_INET6, $netaddr);
+ }
+ $self->{fromaddr} = $addr;
+ $self->{fromport} = $port;
+ print STDERR "recv from: $addr $port\n";
+
+ if ($dgram) {
+ $$dgram = $in;
+ } else {
+ print STDERR "<<< $in";
}
- print STDERR "<<< $in";
}
sub in_cksum {
@@ -73,16 +112,19 @@ sub in_cksum {
use constant IPPROTO_ICMPV6 => 58;
use constant ICMP_ECHO => 8;
+use constant ICMP_ECHOREPLY => 0;
use constant ICMP6_ECHO_REQUEST => 128;
+use constant ICMP6_ECHO_REPLY => 129;
my $seq = 0;
sub write_icmp_echo {
my $self = shift;
+ my $pid = 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);
+ my $icmp = pack("CCnnn", $type, 0, 0, $pid, ++$seq);
if ($af eq "inet") {
substr($icmp, 2, 2, pack("n", in_cksum($icmp)));
} else {
@@ -95,24 +137,21 @@ sub write_icmp_echo {
substr($icmp, 2, 2, pack("n", in_cksum($phdr. $icmp)));
}
- print $icmp;
- IO::Handle::flush(\*STDOUT);
+ write_datagram($self, $icmp);
my $text = $af eq "inet" ? "ICMP" : "ICMP6";
print STDERR ">>> $text ", unpack("H*", $icmp), "\n";
}
sub read_icmp_echo {
my $self = shift;
+ my $reply = 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 $icmp;
+ read_datagram($self, \$icmp);
my $text = $af eq "inet" ? "ICMP" : "ICMP6";
+ $text .= " reply" if $reply;
my $phdr = "";
if ($af eq "inet6") {
# src, dst, plen, pad, next
@@ -127,7 +166,10 @@ sub read_icmp_echo {
$text = "BAD $text CHECKSUM";
} else {
my($type, $code, $cksum, $id, $seq) = unpack("CCnnn", $icmp);
- if ($type != ($af eq "inet" ? ICMP_ECHO : ICMP6_ECHO_REQUEST)) {
+ my $t = $reply ?
+ ($af eq "inet" ? ICMP_ECHOREPLY : ICMP6_ECHO_REPLY) :
+ ($af eq "inet" ? ICMP_ECHO : ICMP6_ECHO_REQUEST);
+ if ($type != $t) {
$text = "BAD $text TYPE";
} elsif ($code != 0) {
$text = "BAD $text CODE";
@@ -152,7 +194,7 @@ sub check_logs {
sub check_inout {
my ($c, $s, %args) = @_;
- if ($c && !$args{client}{nocheck}) {
+ if ($args{client} && !$args{client}{nocheck}) {
my $out = $args{client}{out} || "Client";
$c->loggrep(qr/^>>> $out/) or die "no client output"
unless $args{client}{noout};
@@ -160,7 +202,7 @@ sub check_inout {
$c->loggrep(qr/^<<< $in/) or die "no client input"
unless $args{client}{noin};
}
- if ($s && !$args{server}{nocheck}) {
+ if ($args{server} && !$args{server}{nocheck}) {
my $out = $args{server}{out} || "Server";
$s->loggrep(qr/^>>> $out/) or die "no server output"
unless $args{server}{noout};
diff --git a/regress/sys/net/pf_divert/remote.pl b/regress/sys/net/pf_divert/remote.pl
index 977e7c40388..2cddecd7b0d 100644
--- a/regress/sys/net/pf_divert/remote.pl
+++ b/regress/sys/net/pf_divert/remote.pl
@@ -1,7 +1,7 @@
#!/usr/bin/perl
-# $OpenBSD: remote.pl,v 1.5 2013/11/03 00:32:36 bluhm Exp $
+# $OpenBSD: remote.pl,v 1.6 2015/07/28 12:31:29 bluhm Exp $
-# Copyright (c) 2010-2013 Alexander Bluhm <bluhm@openbsd.org>
+# Copyright (c) 2010-2015 Alexander Bluhm <bluhm@openbsd.org>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
@@ -82,7 +82,6 @@ if (@ARGV == 5 && $mode eq "auto") {
}
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";
@@ -99,7 +98,6 @@ if ($mode eq "divert" xor $divert eq "reply") {
if ($local eq "server") {
$l = $s = Server->new(
- func => $func,
%args,
%{$args{server}},
logfile => $logfile,
@@ -111,7 +109,7 @@ if ($local eq "server") {
listenport => $serverport || $bindport,
srcaddr => $srcaddr,
dstaddr => $dstaddr,
- );
+ ) if $args{server};
}
if ($mode eq "auto") {
$r = Remote->new(
@@ -133,7 +131,6 @@ if ($mode eq "auto") {
}
if ($local eq "client") {
$l = $c = Client->new(
- func => $func,
%args,
%{$args{client}},
logfile => $logfile,
@@ -147,9 +144,9 @@ if ($local eq "client") {
bindport => $clientport || $bindport,
srcaddr => $srcaddr,
dstaddr => $dstaddr,
- );
+ ) if $args{client};
}
-$l->{log}->print("local command: $command\n");
+$l->{log}->print("local command: $command\n") if $l;
if ($mode eq "divert") {
open(my $log, '<', $l->{logfile})