diff options
author | Alexander Bluhm <bluhm@cvs.openbsd.org> | 2013-06-05 04:34:28 +0000 |
---|---|---|
committer | Alexander Bluhm <bluhm@cvs.openbsd.org> | 2013-06-05 04:34:28 +0000 |
commit | 2e3d70900192e0ccffe93bb48352ee65789ebdd9 (patch) | |
tree | f4970ed15b28542600c0fc0c68cda0ac7a4338e1 /regress | |
parent | 3a2030f8d5c86b6fd26391f0992713849284d68b (diff) |
Add tests for ICMP and ICMP6 divert-to.
Diffstat (limited to 'regress')
-rw-r--r-- | regress/sys/net/pf_divert/Client.pm | 19 | ||||
-rw-r--r-- | regress/sys/net/pf_divert/Server.pm | 11 | ||||
-rw-r--r-- | regress/sys/net/pf_divert/args-icmp-to.pl | 13 | ||||
-rw-r--r-- | regress/sys/net/pf_divert/funcs.pl | 92 | ||||
-rw-r--r-- | regress/sys/net/pf_divert/remote.pl | 47 |
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 $! ? |