1# $OpenBSD: Relayd.pm,v 1.20 2024/10/28 19:57:02 tb Exp $ 2 3# Copyright (c) 2010-2015 Alexander Bluhm <bluhm@openbsd.org> 4# 5# Permission to use, copy, modify, and distribute this software for any 6# purpose with or without fee is hereby granted, provided that the above 7# copyright notice and this permission notice appear in all copies. 8# 9# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 17use strict; 18use warnings; 19 20package Relayd; 21use parent 'Proc'; 22use Carp; 23use Cwd; 24use Sys::Hostname; 25use File::Basename; 26 27sub new { 28 my $class = shift; 29 my %args = @_; 30 $args{logfile} ||= "relayd.log"; 31 $args{up} ||= $args{dryrun} || "relay_launch: "; 32 $args{down} ||= $args{dryrun} ? "relayd.conf:" : "parent terminating"; 33 $args{func} = sub { Carp::confess "$class func may not be called" }; 34 $args{conffile} ||= "relayd.conf"; 35 $args{forward} 36 or croak "$class forward not given"; 37 my $self = Proc::new($class, %args); 38 ref($self->{protocol}) eq 'ARRAY' 39 or $self->{protocol} = [ split("\n", $self->{protocol} || "") ]; 40 ref($self->{relay}) eq 'ARRAY' 41 or $self->{relay} = [ split("\n", $self->{relay} || "") ]; 42 $self->{listenaddr} 43 or croak "$class listen addr not given"; 44 $self->{listenport} 45 or croak "$class listen port not given"; 46 $self->{connectaddr} 47 or croak "$class connect addr not given"; 48 $self->{connectport} 49 or croak "$class connect port not given"; 50 51 my $test = basename($self->{testfile} || ""); 52 # tls does not allow a too long session id, so truncate it 53 substr($test, 25, length($test) - 25, "") if length($test) > 25; 54 open(my $fh, '>', $self->{conffile}) 55 or die ref($self), " conf file $self->{conffile} create failed: $!"; 56 print $fh "log state changes\n"; 57 print $fh "log host checks\n"; 58 print $fh "log connection\n"; 59 print $fh "prefork 1\n"; # only crashes of first child are observed 60 print $fh "table <table-$test> { $self->{connectaddr} }\n" 61 if defined($self->{table}); 62 63 # substitute variables in config file 64 my $curdir = dirname($0) || "."; 65 my $objdir = getcwd(); 66 my $hostname = hostname(); 67 (my $host = $hostname) =~ s/\..*//; 68 my $connectport = $self->{connectport}; 69 my $connectaddr = $self->{connectaddr}; 70 my $listenaddr = $self->{listenaddr}; 71 my $listenport = $self->{listenport}; 72 73 my @protocol = @{$self->{protocol}}; 74 my $proto = shift @protocol; 75 $proto = defined($proto) ? "$proto " : ""; 76 unshift @protocol, 77 $self->{forward} eq "splice" ? "tcp splice" : 78 $self->{forward} eq "copy" ? "tcp no splice" : 79 die ref($self), " invalid forward $self->{forward}" 80 unless grep { /splice/ } @protocol; 81 push @protocol, "tcp nodelay"; 82 print $fh "${proto}protocol proto-$test {"; 83 if ($self->{inspectssl}) { 84 $self->{listenssl} = $self->{forwardssl} = 1; 85 print $fh "\n\ttls ca cert ca.crt"; 86 print $fh "\n\ttls ca key ca.key password ''"; 87 } 88 if ($self->{verifyclient}) { 89 print $fh "\n\ttls client ca client-ca.crt"; 90 } 91 # substitute variables in config file 92 foreach (@protocol) { 93 s/(\$[a-z]+)/$1/eeg; 94 } 95 print $fh map { "\n\t$_" } @protocol; 96 print $fh "\n}\n"; 97 98 my @relay = @{$self->{relay}}; 99 print $fh "relay relay-$test {"; 100 print $fh "\n\tprotocol proto-$test" 101 unless grep { /^protocol / } @relay; 102 my $tls = $self->{listenssl} ? " tls" : ""; 103 print $fh "\n\tlisten on $self->{listenaddr} ". 104 "port $self->{listenport}$tls" unless grep { /^listen / } @relay; 105 my $withtls = $self->{forwardssl} ? " with tls" : ""; 106 print $fh "\n\tforward$withtls to $self->{connectaddr} ". 107 "port $self->{connectport}" unless grep { /^forward / } @relay; 108 # substitute variables in config file 109 foreach (@relay) { 110 s/(\$[a-z]+)/$1/eeg; 111 } 112 print $fh map { "\n\t$_" } @relay; 113 print $fh "\n}\n"; 114 115 return $self; 116} 117 118sub child { 119 my $self = shift; 120 my @sudo = $ENV{SUDO} ? split(' ', $ENV{SUDO}) : (); 121 my @ktrace = $ENV{KTRACE} ? ($ENV{KTRACE}, "-i") : (); 122 my $relayd = $ENV{RELAYD} ? $ENV{RELAYD} : "relayd"; 123 my @cmd = (@sudo, @ktrace, $relayd, "-dvv", "-f", $self->{conffile}); 124 print STDERR "execute: @cmd\n"; 125 exec @cmd; 126 die ref($self), " exec '@cmd' failed: $!"; 127} 128 1291; 130