1#*************************************************************************** 2# _ _ ____ _ 3# Project ___| | | | _ \| | 4# / __| | | | |_) | | 5# | (__| |_| | _ <| |___ 6# \___|\___/|_| \_\_____| 7# 8# Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 9# 10# This software is licensed as described in the file COPYING, which 11# you should have received as part of this distribution. The terms 12# are also available at https://curl.se/docs/copyright.html. 13# 14# You may opt to use, copy, modify, merge, publish, distribute and/or sell 15# copies of the Software, and permit persons to whom the Software is 16# furnished to do so, under the terms of the COPYING file. 17# 18# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19# KIND, either express or implied. 20# 21# SPDX-License-Identifier: curl 22# 23########################################################################### 24 25# This module contains functions that are useful for managing the lifecycle of 26# test servers required when running tests. It is not intended for use within 27# those servers, but rather for starting and stopping them. 28 29package servers; 30 31use IO::Socket; 32use strict; 33use warnings; 34 35BEGIN { 36 use base qw(Exporter); 37 38 our @EXPORT = ( 39 # variables 40 qw( 41 $SOCKSIN 42 $err_unexpected 43 $debugprotocol 44 $stunnel 45 ), 46 47 # functions 48 qw( 49 initserverconfig 50 ) 51 ); 52 53 our @EXPORT_OK = ( 54 # functions 55 qw( 56 checkcmd 57 clearlocks 58 serverfortest 59 stopserver 60 stopservers 61 subvariables 62 localhttp 63 ), 64 65 # for debugging only 66 qw( 67 protoport 68 ) 69 ); 70} 71 72use serverhelp qw( 73 serverfactors 74 servername_id 75 servername_str 76 servername_canon 77 server_pidfilename 78 server_portfilename 79 server_logfilename 80 ); 81 82use sshhelp qw( 83 $hstpubmd5f 84 $hstpubsha256f 85 $sshexe 86 $sftpexe 87 $sftpconfig 88 $sshdlog 89 $sftplog 90 $sftpcmds 91 display_sshdconfig 92 display_sftpconfig 93 display_sshdlog 94 display_sftplog 95 find_sshd 96 find_ssh 97 find_sftp 98 find_httptlssrv 99 sshversioninfo 100 ); 101 102use pathhelp qw( 103 exe_ext 104 os_is_win 105 build_sys_abs_path 106 sys_native_abs_path 107 ); 108 109use processhelp; 110use globalconfig; 111use testutil qw( 112 logmsg 113 runclient 114 runclientoutput 115 ); 116 117 118my %serverpidfile; # all server pid file names, identified by server id 119my %serverportfile;# all server port file names, identified by server id 120my $sshdvernum; # for socks server, ssh daemon version number 121my $sshdverstr; # for socks server, ssh daemon version string 122my $sshderror; # for socks server, ssh daemon version error 123my %doesntrun; # servers that don't work, identified by pidfile 124my %PORT = (nolisten => 47); # port we use for a local non-listening service 125my $server_response_maxtime=13; 126my $httptlssrv = find_httptlssrv(); 127my %run; # running server 128my %runcert; # cert file currently in use by an ssl running server 129my $CLIENTIP="127.0.0.1"; # address which curl uses for incoming connections 130my $CLIENT6IP="[::1]"; # address which curl uses for incoming connections 131my $posix_pwd = build_sys_abs_path($pwd); # current working directory in POSIX format 132my $h2cver = "h2c"; # this version is decided by the nghttp2 lib being used 133my $portrange = 999; # space from which to choose a random port 134 # don't increase without making sure generated port 135 # numbers will always be valid (<=65535) 136my $HOSTIP="127.0.0.1"; # address on which the test server listens 137my $HOST6IP="[::1]"; # address on which the test server listens 138my $HTTPUNIXPATH; # HTTP server Unix domain socket path 139my $SOCKSUNIXPATH; # socks server Unix domain socket path 140my $SSHSRVMD5 = "[uninitialized]"; # MD5 of ssh server public key 141my $SSHSRVSHA256 = "[uninitialized]"; # SHA256 of ssh server public key 142my $USER; # name of the current user 143my $sshdid; # for socks server, ssh daemon version id 144my $ftpchecktime=1; # time it took to verify our test FTP server 145 146# Variables shared with runtests.pl 147our $SOCKSIN="socksd-request.log"; # what curl sent to the SOCKS proxy 148our $err_unexpected; # error instead of warning on server unexpectedly alive 149our $debugprotocol; # nonzero for verbose server logs 150our $stunnel; # path to stunnel command 151 152 153####################################################################### 154# Check for a command in the PATH of the test server. 155# 156sub checkcmd { 157 my ($cmd, @extrapaths)=@_; 158 my @paths; 159 if ($^O eq 'MSWin32' || $^O eq 'dos' || $^O eq 'os2') { 160 # PATH separator is different 161 @paths=(split(';', $ENV{'PATH'}), @extrapaths); 162 } 163 else { 164 @paths=(split(':', $ENV{'PATH'}), "/usr/sbin", "/usr/local/sbin", 165 "/sbin", "/usr/bin", "/usr/local/bin", @extrapaths); 166 } 167 for(@paths) { 168 if( -x "$_/$cmd" . exe_ext('SYS') && ! -d "$_/$cmd" . exe_ext('SYS')) { 169 # executable bit but not a directory! 170 return "$_/$cmd"; 171 } 172 } 173 return ""; 174} 175 176####################################################################### 177# Create a server socket on a random (unused) port, then close it and 178# return the port number 179# 180sub getfreeport { 181 my ($ipnum) = @_; 182 my $server = IO::Socket->new(LocalPort => 0, 183 Domain => $ipnum == 6 ? AF_INET6 : AF_INET, 184 Type => SOCK_STREAM, 185 Reuse => 1, 186 Listen => 10 ) 187 or die "Couldn't create tcp server socket: $@\n"; 188 189 return $server->sockport(); 190} 191 192use File::Temp qw/ tempfile/; 193 194####################################################################### 195# Initialize configuration variables 196sub initserverconfig { 197 my ($fh, $socks) = tempfile("curl-socksd-XXXXXXXX", TMPDIR => 1); 198 close($fh); 199 unlink($socks); 200 my ($f2, $http) = tempfile("curl-http-XXXXXXXX", TMPDIR => 1); 201 close($f2); 202 unlink($http); 203 $SOCKSUNIXPATH = $socks; # SOCKS Unix domain socket 204 $HTTPUNIXPATH = $http; # HTTP Unix domain socket 205 $stunnel = checkcmd("stunnel4") || checkcmd("tstunnel") || checkcmd("stunnel"); 206 207 # get the name of the current user 208 $USER = $ENV{USER}; # Linux 209 if (!$USER) { 210 $USER = $ENV{USERNAME}; # Windows 211 if (!$USER) { 212 $USER = $ENV{LOGNAME}; # Some Unix (I think) 213 } 214 } 215 init_serverpidfile_hash(); 216} 217 218####################################################################### 219# Load serverpidfile and serverportfile hashes with file names for all 220# possible servers. 221# 222sub init_serverpidfile_hash { 223 for my $proto (('ftp', 'gopher', 'http', 'imap', 'pop3', 'smtp', 'http/2', 'http/3')) { 224 for my $ssl (('', 's')) { 225 for my $ipvnum ((4, 6)) { 226 for my $idnum ((1, 2, 3)) { 227 my $serv = servername_id("$proto$ssl", $ipvnum, $idnum); 228 my $pidf = server_pidfilename("$LOGDIR/$PIDDIR", "$proto$ssl", 229 $ipvnum, $idnum); 230 $serverpidfile{$serv} = $pidf; 231 my $portf = server_portfilename("$LOGDIR/$PIDDIR", "$proto$ssl", 232 $ipvnum, $idnum); 233 $serverportfile{$serv} = $portf; 234 } 235 } 236 } 237 } 238 for my $proto (('tftp', 'sftp', 'socks', 'ssh', 'rtsp', 'httptls', 239 'dict', 'smb', 'smbs', 'telnet', 'mqtt')) { 240 for my $ipvnum ((4, 6)) { 241 for my $idnum ((1, 2)) { 242 my $serv = servername_id($proto, $ipvnum, $idnum); 243 my $pidf = server_pidfilename("$LOGDIR/$PIDDIR", $proto, $ipvnum, 244 $idnum); 245 $serverpidfile{$serv} = $pidf; 246 my $portf = server_portfilename("$LOGDIR/$PIDDIR", $proto, $ipvnum, 247 $idnum); 248 $serverportfile{$serv} = $portf; 249 } 250 } 251 } 252 for my $proto (('http', 'imap', 'pop3', 'smtp', 'http/2', 'http/3')) { 253 for my $ssl (('', 's')) { 254 my $serv = servername_id("$proto$ssl", "unix", 1); 255 my $pidf = server_pidfilename("$LOGDIR/$PIDDIR", "$proto$ssl", 256 "unix", 1); 257 $serverpidfile{$serv} = $pidf; 258 my $portf = server_portfilename("$LOGDIR/$PIDDIR", "$proto$ssl", 259 "unix", 1); 260 $serverportfile{$serv} = $portf; 261 } 262 } 263} 264 265 266####################################################################### 267# Kill the processes that still have lock files in a directory 268# 269sub clearlocks { 270 my $dir = $_[0]; 271 my $done = 0; 272 273 if(os_is_win()) { 274 $dir = sys_native_abs_path($dir); 275 # Must use backslashes for handle64 to find a match 276 if ($^O eq 'MSWin32') { 277 $dir =~ s/\//\\/g; 278 } 279 else { 280 $dir =~ s/\//\\\\/g; 281 } 282 my $handle = "handle"; 283 if($ENV{"PROCESSOR_ARCHITECTURE"} =~ /64$/) { 284 $handle = "handle64"; 285 } 286 if(checkcmd($handle)) { 287 # https://learn.microsoft.com/sysinternals/downloads/handle#usage 288 my $cmd = "$handle $dir -accepteula -nobanner"; 289 logmsg "clearlocks: Executing query: '$cmd'\n"; 290 my @handles = `$cmd`; 291 for my $tryhandle (@handles) { 292 # Skip the "No matching handles found." warning when returned 293 if($tryhandle =~ /^(\S+)\s+pid:\s+(\d+)\s+type:\s+(\w+)\s+([0-9A-F]+):\s+(.+)\r\r/) { 294 logmsg "clearlocks: Found $3 lock of '$5' ($4) by $1 ($2)\n"; 295 # Ignore stunnel since we cannot do anything about its locks 296 if("$3" eq "File" && "$1" ne "tstunnel.exe") { 297 logmsg "clearlocks: Killing IMAGENAME eq $1 and PID eq $2\n"; 298 # https://ss64.com/nt/taskkill.html 299 my $cmd = "taskkill.exe -f -t -fi \"IMAGENAME eq $1\" -fi \"PID eq $2\" >nul 2>&1"; 300 logmsg "clearlocks: Executing kill: '$cmd'\n"; 301 system($cmd); 302 $done = 1; 303 } 304 } 305 } 306 } 307 else { 308 logmsg "Warning: 'handle' tool not found.\n"; 309 } 310 } 311 return $done; 312} 313 314####################################################################### 315# Check if a given child process has just died. Reaps it if so. 316# 317sub checkdied { 318 my $pid = $_[0]; 319 if((not defined $pid) || $pid <= 0) { 320 return 0; 321 } 322 use POSIX ":sys_wait_h"; 323 my $rc = pidwait($pid, &WNOHANG); 324 return ($rc == $pid)?1:0; 325} 326 327 328############################################################################## 329# This function makes sure the right set of server is running for the 330# specified test case. This is a useful design when we run single tests as not 331# all servers need to run then! 332# 333# Returns: a string, blank if everything is fine or a reason why it failed, and 334# an integer: 335# 0 for success 336# 1 for an error starting the server 337# 2 for not the first time getting an error starting the server 338# 3 for a failure to stop a server in order to restart it 339# 4 for an unsupported server type 340# 341sub serverfortest { 342 my (@what)=@_; 343 344 for(my $i = scalar(@what) - 1; $i >= 0; $i--) { 345 my $srvrline = $what[$i]; 346 chomp $srvrline if($srvrline); 347 if($srvrline =~ /^(\S+)((\s*)(.*))/) { 348 my $server = "${1}"; 349 my $lnrest = "${2}"; 350 my $tlsext; 351 if($server =~ /^(httptls)(\+)(ext|srp)(\d*)(-ipv6|)$/) { 352 $server = "${1}${4}${5}"; 353 $tlsext = uc("TLS-${3}"); 354 } 355 if(! grep /^\Q$server\E$/, @protocols) { 356 if(substr($server,0,5) ne "socks") { 357 if($tlsext) { 358 return ("curl lacks $tlsext support", 4); 359 } 360 else { 361 return ("curl lacks $server server support", 4); 362 } 363 } 364 } 365 $what[$i] = "$server$lnrest" if($tlsext); 366 } 367 } 368 369 return &startservers(@what); 370} 371 372 373####################################################################### 374# Start a new thread/process and run the given command line in there. 375# Return the pids (yes plural) of the new child process to the parent. 376# 377sub startnew { 378 my ($cmd, $pidfile, $timeout, $fakepidfile)=@_; 379 380 logmsg "startnew: $cmd\n" if ($verbose); 381 382 my $child = fork(); 383 384 if(not defined $child) { 385 logmsg "startnew: fork() failure detected\n"; 386 return (-1,-1); 387 } 388 389 if(0 == $child) { 390 # Here we are the child. Run the given command. 391 392 # Flush output. 393 $| = 1; 394 395 # Put an "exec" in front of the command so that the child process 396 # keeps this child's process ID. 397 exec("exec $cmd") || die "Can't exec() $cmd: $!"; 398 399 # exec() should never return back here to this process. We protect 400 # ourselves by calling die() just in case something goes really bad. 401 die "error: exec() has returned"; 402 } 403 404 # Ugly hack but ssh client and gnutls-serv don't support pid files 405 if ($fakepidfile) { 406 if(open(my $out, ">", "$pidfile")) { 407 print $out $child . "\n"; 408 close($out) || die "Failure writing pidfile"; 409 logmsg "startnew: $pidfile faked with pid=$child\n" if($verbose); 410 } 411 else { 412 logmsg "startnew: failed to write fake $pidfile with pid=$child\n"; 413 } 414 # could/should do a while connect fails sleep a bit and loop 415 portable_sleep($timeout); 416 if (checkdied($child)) { 417 logmsg "startnew: child process has failed to start\n" if($verbose); 418 return (-1,-1); 419 } 420 } 421 422 my $pid2 = 0; 423 my $count = $timeout; 424 while($count--) { 425 $pid2 = pidfromfile($pidfile); 426 if(($pid2 > 0) && pidexists($pid2)) { 427 # if $pid2 is valid, then make sure this pid is alive, as 428 # otherwise it is just likely to be the _previous_ pidfile or 429 # similar! 430 last; 431 } 432 if (checkdied($child)) { 433 logmsg "startnew: child process has died, server might start up\n" 434 if($verbose); 435 # We can't just abort waiting for the server with a 436 # return (-1,-1); 437 # because the server might have forked and could still start 438 # up normally. Instead, just reduce the amount of time we remain 439 # waiting. 440 $count >>= 2; 441 } 442 sleep(1); 443 } 444 445 # Return two PIDs, the one for the child process we spawned and the one 446 # reported by the server itself (in case it forked again on its own). 447 # Both (potentially) need to be killed at the end of the test. 448 return ($child, $pid2); 449} 450 451 452####################################################################### 453# Return the port to use for the given protocol. 454# 455sub protoport { 456 my ($proto) = @_; 457 return $PORT{$proto} || "[not running]"; 458} 459 460 461####################################################################### 462# Stop a test server along with pids which aren't in the %run hash yet. 463# This also stops all servers which are relative to the given one. 464# 465sub stopserver { 466 my ($server, $pidlist) = @_; 467 my $ipvnum = 4; 468 469 # 470 # kill sockfilter processes for pingpong relative server 471 # 472 if($server =~ /^(ftp|imap|pop3|smtp)s?(\d*)(-ipv6|)$/) { 473 my $proto = $1; 474 my $idnum = ($2 && ($2 > 1)) ? $2 : 1; 475 $ipvnum = ($3 && ($3 =~ /6$/)) ? 6 : 4; 476 killsockfilters("$LOGDIR/$PIDDIR", $proto, $ipvnum, $idnum, $verbose); 477 } 478 # 479 # All servers relative to the given one must be stopped also 480 # 481 my @killservers; 482 if($server =~ /^(ftp|http|imap|pop3|smtp)s((\d*)(-ipv6|-unix|))$/) { 483 # given a stunnel based ssl server, also kill non-ssl underlying one 484 push @killservers, "${1}${2}"; 485 } 486 elsif($server =~ /^(ftp|http|imap|pop3|smtp)((\d*)(-ipv6|-unix|))$/) { 487 # given a non-ssl server, also kill stunnel based ssl piggybacking one 488 push @killservers, "${1}s${2}"; 489 } 490 elsif($server =~ /^(socks)((\d*)(-ipv6|))$/) { 491 # given a socks server, also kill ssh underlying one 492 push @killservers, "ssh${2}"; 493 } 494 elsif($server =~ /^(ssh)((\d*)(-ipv6|))$/) { 495 # given a ssh server, also kill socks piggybacking one 496 push @killservers, "socks${2}"; 497 } 498 if($server eq "http" or $server eq "https") { 499 # since the http2+3 server is a proxy that needs to know about the 500 # dynamic http port it too needs to get restarted when the http server 501 # is killed 502 push @killservers, "http/2"; 503 push @killservers, "http/3"; 504 } 505 push @killservers, $server; 506 # 507 # kill given pids and server relative ones clearing them in %run hash 508 # 509 foreach my $server (@killservers) { 510 if($run{$server}) { 511 # we must prepend a space since $pidlist may already contain a pid 512 $pidlist .= " $run{$server}"; 513 $run{$server} = 0; 514 } 515 $runcert{$server} = 0 if($runcert{$server}); 516 } 517 killpid($verbose, $pidlist); 518 # 519 # cleanup server pid files 520 # 521 my $result = 0; 522 foreach my $server (@killservers) { 523 my $pidfile = $serverpidfile{$server}; 524 unlink($pidfile) if(-f $pidfile); 525 } 526 # 527 # cleanup server lock files 528 # 529 foreach my $server (@killservers) { 530 # servers seem to produce (some of) these lock files 531 my @lockfiles = ( 532 "$LOGDIR/$LOCKDIR/$server.lock", 533 "$LOGDIR/$LOCKDIR/$server-IPv$ipvnum.lock", 534 "$LOGDIR/$LOCKDIR/sws-".uc($server)."-IPv$ipvnum.lock" 535 ); 536 foreach my $lockfile (@lockfiles) { 537 if(-f $lockfile) { 538 unlink($lockfile); 539 logmsg "RUN: kill $server, cleaned up $lockfile\n" if ($verbose); 540 } 541 } 542 } 543 544 return $result; 545} 546 547 548####################################################################### 549# Return flags to let curl use an external HTTP proxy 550# 551sub getexternalproxyflags { 552 return " --proxy $proxy_address "; 553} 554 555####################################################################### 556# Verify that the server that runs on $ip, $port is our server. This also 557# implies that we can speak with it, as there might be occasions when the 558# server runs fine but we cannot talk to it ("Failed to connect to ::1: Can't 559# assign requested address") 560# 561sub verifyhttp { 562 my ($proto, $ipvnum, $idnum, $ip, $port_or_path, $do_http3) = @_; 563 my $server = servername_id($proto, $ipvnum, $idnum); 564 my $bonus=""; 565 # $port_or_path contains a path for Unix sockets, sws ignores the port 566 my $port = ($ipvnum eq "unix") ? 80 : $port_or_path; 567 my $infix = ($do_http3) ? "_h3" : ""; 568 569 my $verifyout = "$LOGDIR/". 570 servername_canon($proto, $ipvnum, $idnum) .$infix .'_verify.out'; 571 unlink($verifyout) if(-f $verifyout); 572 573 my $verifylog = "$LOGDIR/". 574 servername_canon($proto, $ipvnum, $idnum) .$infix .'_verify.log'; 575 unlink($verifylog) if(-f $verifylog); 576 577 if($proto eq "gopher") { 578 # gopher is funny 579 $bonus="1/"; 580 } 581 582 my $flags = "--max-time $server_response_maxtime "; 583 $flags .= "--output $verifyout "; 584 $flags .= "--silent "; 585 $flags .= "--verbose "; 586 $flags .= "--globoff "; 587 $flags .= "--unix-socket '$port_or_path' " if $ipvnum eq "unix"; 588 $flags .= "--insecure " if($proto eq 'https'); 589 if($proxy_address) { 590 $flags .= getexternalproxyflags(); 591 } 592 $flags .= "--http3-only " if($do_http3); 593 $flags .= "\"$proto://$ip:$port/${bonus}verifiedserver\""; 594 595 my $cmd = "$VCURL $flags 2>$verifylog"; 596 597 # verify if our/any server is running on this port 598 logmsg "RUN: $cmd\n" if($verbose); 599 my $res = runclient($cmd); 600 601 $res >>= 8; # rotate the result 602 if($res & 128) { 603 logmsg "RUN: curl command died with a coredump\n"; 604 return -1; 605 } 606 607 if($res && $verbose) { 608 logmsg "RUN: curl command returned $res\n"; 609 if(open(my $file, "<", "$verifylog")) { 610 while(my $string = <$file>) { 611 logmsg "RUN: $string" if($string !~ /^([ \t]*)$/); 612 } 613 close($file); 614 } 615 } 616 617 my $data; 618 if(open(my $file, "<", "$verifyout")) { 619 while(my $string = <$file>) { 620 $data = $string; 621 last; # only want first line 622 } 623 close($file); 624 } 625 626 my $pid = 0; 627 if($data && ($data =~ /WE ROOLZ: (\d+)/)) { 628 $pid = 0+$1; 629 } 630 elsif($res == 6) { 631 # curl: (6) Couldn't resolve host '::1' 632 logmsg "RUN: failed to resolve host ($proto://$ip:$port/verifiedserver)\n"; 633 return -1; 634 } 635 elsif($data || ($res && ($res != 7))) { 636 logmsg "RUN: Unknown server on our $server port: $port ($res)\n"; 637 return -1; 638 } 639 return $pid; 640} 641 642####################################################################### 643# Verify that the server that runs on $ip, $port is our server. This also 644# implies that we can speak with it, as there might be occasions when the 645# server runs fine but we cannot talk to it ("Failed to connect to ::1: Can't 646# assign requested address") 647# 648sub verifyftp { 649 my ($proto, $ipvnum, $idnum, $ip, $port) = @_; 650 my $server = servername_id($proto, $ipvnum, $idnum); 651 my $time=time(); 652 my $extra=""; 653 654 my $verifylog = "$LOGDIR/". 655 servername_canon($proto, $ipvnum, $idnum) .'_verify.log'; 656 unlink($verifylog) if(-f $verifylog); 657 658 if($proto eq "ftps") { 659 $extra .= "--insecure --ftp-ssl-control "; 660 } 661 662 my $flags = "--max-time $server_response_maxtime "; 663 $flags .= "--silent "; 664 $flags .= "--verbose "; 665 $flags .= "--globoff "; 666 $flags .= $extra; 667 if($proxy_address) { 668 $flags .= getexternalproxyflags(); 669 } 670 $flags .= "\"$proto://$ip:$port/verifiedserver\""; 671 672 my $cmd = "$VCURL $flags 2>$verifylog"; 673 674 # check if this is our server running on this port: 675 logmsg "RUN: $cmd\n" if($verbose); 676 my @data = runclientoutput($cmd); 677 678 my $res = $? >> 8; # rotate the result 679 if($res & 128) { 680 logmsg "RUN: curl command died with a coredump\n"; 681 return -1; 682 } 683 684 my $pid = 0; 685 foreach my $line (@data) { 686 if($line =~ /WE ROOLZ: (\d+)/) { 687 # this is our test server with a known pid! 688 $pid = 0+$1; 689 last; 690 } 691 } 692 if($pid <= 0 && @data && $data[0]) { 693 # this is not a known server 694 logmsg "RUN: Unknown server on our $server port: $port\n"; 695 return 0; 696 } 697 # we can/should use the time it took to verify the FTP server as a measure 698 # on how fast/slow this host/FTP is. 699 my $took = int(0.5+time()-$time); 700 701 if($verbose) { 702 logmsg "RUN: Verifying our test $server server took $took seconds\n"; 703 } 704 $ftpchecktime = $took>=1?$took:1; # make sure it never is below 1 705 706 return $pid; 707} 708 709####################################################################### 710# Verify that the server that runs on $ip, $port is our server. This also 711# implies that we can speak with it, as there might be occasions when the 712# server runs fine but we cannot talk to it ("Failed to connect to ::1: Can't 713# assign requested address") 714# 715sub verifyrtsp { 716 my ($proto, $ipvnum, $idnum, $ip, $port) = @_; 717 my $server = servername_id($proto, $ipvnum, $idnum); 718 719 my $verifyout = "$LOGDIR/". 720 servername_canon($proto, $ipvnum, $idnum) .'_verify.out'; 721 unlink($verifyout) if(-f $verifyout); 722 723 my $verifylog = "$LOGDIR/". 724 servername_canon($proto, $ipvnum, $idnum) .'_verify.log'; 725 unlink($verifylog) if(-f $verifylog); 726 727 my $flags = "--max-time $server_response_maxtime "; 728 $flags .= "--output $verifyout "; 729 $flags .= "--silent "; 730 $flags .= "--verbose "; 731 $flags .= "--globoff "; 732 if($proxy_address) { 733 $flags .= getexternalproxyflags(); 734 } 735 # currently verification is done using http 736 $flags .= "\"http://$ip:$port/verifiedserver\""; 737 738 my $cmd = "$VCURL $flags 2>$verifylog"; 739 740 # verify if our/any server is running on this port 741 logmsg "RUN: $cmd\n" if($verbose); 742 my $res = runclient($cmd); 743 744 $res >>= 8; # rotate the result 745 if($res & 128) { 746 logmsg "RUN: curl command died with a coredump\n"; 747 return -1; 748 } 749 750 if($res && $verbose) { 751 logmsg "RUN: curl command returned $res\n"; 752 if(open(my $file, "<", "$verifylog")) { 753 while(my $string = <$file>) { 754 logmsg "RUN: $string" if($string !~ /^[ \t]*$/); 755 } 756 close($file); 757 } 758 } 759 760 my $data; 761 if(open(my $file, "<", "$verifyout")) { 762 while(my $string = <$file>) { 763 $data = $string; 764 last; # only want first line 765 } 766 close($file); 767 } 768 769 my $pid = 0; 770 if($data && ($data =~ /RTSP_SERVER WE ROOLZ: (\d+)/)) { 771 $pid = 0+$1; 772 } 773 elsif($res == 6) { 774 # curl: (6) Couldn't resolve host '::1' 775 logmsg "RUN: failed to resolve host ($proto://$ip:$port/verifiedserver)\n"; 776 return -1; 777 } 778 elsif($data || ($res != 7)) { 779 logmsg "RUN: Unknown server on our $server port: $port\n"; 780 return -1; 781 } 782 return $pid; 783} 784 785####################################################################### 786# Verify that the ssh server has written out its pidfile, recovering 787# the pid from the file and returning it if a process with that pid is 788# actually alive, or a negative value if the process is dead. 789# 790sub verifyssh { 791 my ($proto, $ipvnum, $idnum, $ip, $port) = @_; 792 my $pidfile = server_pidfilename("$LOGDIR/$PIDDIR", $proto, $ipvnum, 793 $idnum); 794 my $pid = processexists($pidfile); 795 if($pid < 0) { 796 logmsg "RUN: SSH server has died after starting up\n"; 797 } 798 return $pid; 799} 800 801####################################################################### 802# Verify that we can connect to the sftp server, properly authenticate 803# with generated config and key files and run a simple remote pwd. 804# 805sub verifysftp { 806 my ($proto, $ipvnum, $idnum, $ip, $port) = @_; 807 my $server = servername_id($proto, $ipvnum, $idnum); 808 my $verified = 0; 809 # Find out sftp client canonical file name 810 my $sftp = find_sftp(); 811 if(!$sftp) { 812 logmsg "RUN: SFTP server cannot find $sftpexe\n"; 813 return -1; 814 } 815 # Find out ssh client canonical file name 816 my $ssh = find_ssh(); 817 if(!$ssh) { 818 logmsg "RUN: SFTP server cannot find $sshexe\n"; 819 return -1; 820 } 821 # Connect to sftp server, authenticate and run a remote pwd 822 # command using our generated configuration and key files 823 my $cmd = "\"$sftp\" -b $LOGDIR/$PIDDIR/$sftpcmds -F $LOGDIR/$PIDDIR/$sftpconfig -S \"$ssh\" $ip > $sftplog 2>&1"; 824 my $res = runclient($cmd); 825 # Search for pwd command response in log file 826 if(open(my $sftplogfile, "<", "$sftplog")) { 827 while(<$sftplogfile>) { 828 if(/^Remote working directory: /) { 829 $verified = 1; 830 last; 831 } 832 } 833 close($sftplogfile); 834 } 835 return $verified; 836} 837 838####################################################################### 839# Verify that the non-stunnel HTTP TLS extensions capable server that runs 840# on $ip, $port is our server. This also implies that we can speak with it, 841# as there might be occasions when the server runs fine but we cannot talk 842# to it ("Failed to connect to ::1: Can't assign requested address") 843# 844sub verifyhttptls { 845 my ($proto, $ipvnum, $idnum, $ip, $port) = @_; 846 my $server = servername_id($proto, $ipvnum, $idnum); 847 my $pidfile = server_pidfilename("$LOGDIR/$PIDDIR", $proto, $ipvnum, 848 $idnum); 849 850 my $verifyout = "$LOGDIR/". 851 servername_canon($proto, $ipvnum, $idnum) .'_verify.out'; 852 unlink($verifyout) if(-f $verifyout); 853 854 my $verifylog = "$LOGDIR/". 855 servername_canon($proto, $ipvnum, $idnum) .'_verify.log'; 856 unlink($verifylog) if(-f $verifylog); 857 858 my $flags = "--max-time $server_response_maxtime "; 859 $flags .= "--output $verifyout "; 860 $flags .= "--verbose "; 861 $flags .= "--globoff "; 862 $flags .= "--insecure "; 863 $flags .= "--tlsauthtype SRP "; 864 $flags .= "--tlsuser jsmith "; 865 $flags .= "--tlspassword abc "; 866 if($proxy_address) { 867 $flags .= getexternalproxyflags(); 868 } 869 $flags .= "\"https://$ip:$port/verifiedserver\""; 870 871 my $cmd = "$VCURL $flags 2>$verifylog"; 872 873 # verify if our/any server is running on this port 874 logmsg "RUN: $cmd\n" if($verbose); 875 my $res = runclient($cmd); 876 877 $res >>= 8; # rotate the result 878 if($res & 128) { 879 logmsg "RUN: curl command died with a coredump\n"; 880 return -1; 881 } 882 883 if($res && $verbose) { 884 logmsg "RUN: curl command returned $res\n"; 885 if(open(my $file, "<", "$verifylog")) { 886 while(my $string = <$file>) { 887 logmsg "RUN: $string" if($string !~ /^([ \t]*)$/); 888 } 889 close($file); 890 } 891 } 892 893 my $data; 894 if(open(my $file, "<", "$verifyout")) { 895 while(my $string = <$file>) { 896 $data .= $string; 897 } 898 close($file); 899 } 900 901 my $pid = 0; 902 if($data && ($data =~ /(GNUTLS|GnuTLS)/) && ($pid = processexists($pidfile))) { 903 if($pid < 0) { 904 logmsg "RUN: $server server has died after starting up\n"; 905 } 906 return $pid; 907 } 908 elsif($res == 6) { 909 # curl: (6) Couldn't resolve host '::1' 910 logmsg "RUN: failed to resolve host (https://$ip:$port/verifiedserver)\n"; 911 return -1; 912 } 913 elsif($data || ($res && ($res != 7))) { 914 logmsg "RUN: Unknown server on our $server port: $port ($res)\n"; 915 return -1; 916 } 917 return $pid; 918} 919 920####################################################################### 921# STUB for verifying mqtt 922# 923sub verifymqtt { 924 my ($proto, $ipvnum, $idnum, $ip, $port) = @_; 925 my $pidfile = server_pidfilename("$LOGDIR/$PIDDIR", $proto, $ipvnum, 926 $idnum); 927 my $pid = processexists($pidfile); 928 if($pid < 0) { 929 logmsg "RUN: MQTT server has died after starting up\n"; 930 } 931 return $pid; 932} 933 934####################################################################### 935# STUB for verifying socks 936# 937sub verifysocks { 938 my ($proto, $ipvnum, $idnum, $ip, $port) = @_; 939 my $pidfile = server_pidfilename("$LOGDIR/$PIDDIR", $proto, $ipvnum, 940 $idnum); 941 my $pid = processexists($pidfile); 942 if($pid < 0) { 943 logmsg "RUN: SOCKS server has died after starting up\n"; 944 } 945 return $pid; 946} 947 948####################################################################### 949# Verify that the server that runs on $ip, $port is our server. This also 950# implies that we can speak with it, as there might be occasions when the 951# server runs fine but we cannot talk to it ("Failed to connect to ::1: Can't 952# assign requested address") 953# 954sub verifysmb { 955 my ($proto, $ipvnum, $idnum, $ip, $port) = @_; 956 my $server = servername_id($proto, $ipvnum, $idnum); 957 my $time=time(); 958 my $extra=""; 959 960 my $verifylog = "$LOGDIR/". 961 servername_canon($proto, $ipvnum, $idnum) .'_verify.log'; 962 unlink($verifylog) if(-f $verifylog); 963 964 my $flags = "--max-time $server_response_maxtime "; 965 $flags .= "--silent "; 966 $flags .= "--verbose "; 967 $flags .= "--globoff "; 968 $flags .= "-u 'curltest:curltest' "; 969 $flags .= $extra; 970 $flags .= "\"$proto://$ip:$port/SERVER/verifiedserver\""; 971 972 my $cmd = "$VCURL $flags 2>$verifylog"; 973 974 # check if this is our server running on this port: 975 logmsg "RUN: $cmd\n" if($verbose); 976 my @data = runclientoutput($cmd); 977 978 my $res = $? >> 8; # rotate the result 979 if($res & 128) { 980 logmsg "RUN: curl command died with a coredump\n"; 981 return -1; 982 } 983 984 my $pid = 0; 985 foreach my $line (@data) { 986 if($line =~ /WE ROOLZ: (\d+)/) { 987 # this is our test server with a known pid! 988 $pid = 0+$1; 989 last; 990 } 991 } 992 if($pid <= 0 && @data && $data[0]) { 993 # this is not a known server 994 logmsg "RUN: Unknown server on our $server port: $port\n"; 995 return 0; 996 } 997 # we can/should use the time it took to verify the server as a measure 998 # on how fast/slow this host is. 999 my $took = int(0.5+time()-$time); 1000 1001 if($verbose) { 1002 logmsg "RUN: Verifying our test $server server took $took seconds\n"; 1003 } 1004 1005 return $pid; 1006} 1007 1008####################################################################### 1009# Verify that the server that runs on $ip, $port is our server. This also 1010# implies that we can speak with it, as there might be occasions when the 1011# server runs fine but we cannot talk to it ("Failed to connect to ::1: Can't 1012# assign requested address") 1013# 1014sub verifytelnet { 1015 my ($proto, $ipvnum, $idnum, $ip, $port) = @_; 1016 my $server = servername_id($proto, $ipvnum, $idnum); 1017 my $time=time(); 1018 my $extra=""; 1019 1020 my $verifylog = "$LOGDIR/". 1021 servername_canon($proto, $ipvnum, $idnum) .'_verify.log'; 1022 unlink($verifylog) if(-f $verifylog); 1023 1024 my $flags = "--max-time $server_response_maxtime "; 1025 $flags .= "--silent "; 1026 $flags .= "--verbose "; 1027 $flags .= "--globoff "; 1028 $flags .= "--upload-file - "; 1029 $flags .= $extra; 1030 $flags .= "\"$proto://$ip:$port\""; 1031 1032 my $cmd = "echo 'verifiedserver' | $VCURL $flags 2>$verifylog"; 1033 1034 # check if this is our server running on this port: 1035 logmsg "RUN: $cmd\n" if($verbose); 1036 my @data = runclientoutput($cmd); 1037 1038 my $res = $? >> 8; # rotate the result 1039 if($res & 128) { 1040 logmsg "RUN: curl command died with a coredump\n"; 1041 return -1; 1042 } 1043 1044 my $pid = 0; 1045 foreach my $line (@data) { 1046 if($line =~ /WE ROOLZ: (\d+)/) { 1047 # this is our test server with a known pid! 1048 $pid = 0+$1; 1049 last; 1050 } 1051 } 1052 if($pid <= 0 && @data && $data[0]) { 1053 # this is not a known server 1054 logmsg "RUN: Unknown server on our $server port: $port\n"; 1055 return 0; 1056 } 1057 # we can/should use the time it took to verify the server as a measure 1058 # on how fast/slow this host is. 1059 my $took = int(0.5+time()-$time); 1060 1061 if($verbose) { 1062 logmsg "RUN: Verifying our test $server server took $took seconds\n"; 1063 } 1064 1065 return $pid; 1066} 1067 1068####################################################################### 1069# Verify that the server that runs on $ip, $port is our server. 1070# Retry over several seconds before giving up. The ssh server in 1071# particular can take a long time to start if it needs to generate 1072# keys on a slow or loaded host. 1073# 1074# Just for convenience, test harness uses 'https' and 'httptls' literals 1075# as values for 'proto' variable in order to differentiate different 1076# servers. 'https' literal is used for stunnel based https test servers, 1077# and 'httptls' is used for non-stunnel https test servers. 1078# 1079 1080my %protofunc = ('http' => \&verifyhttp, 1081 'https' => \&verifyhttp, 1082 'rtsp' => \&verifyrtsp, 1083 'ftp' => \&verifyftp, 1084 'pop3' => \&verifyftp, 1085 'imap' => \&verifyftp, 1086 'smtp' => \&verifyftp, 1087 'ftps' => \&verifyftp, 1088 'pop3s' => \&verifyftp, 1089 'imaps' => \&verifyftp, 1090 'mqtt' => \&verifymqtt, 1091 'smtps' => \&verifyftp, 1092 'tftp' => \&verifyftp, 1093 'ssh' => \&verifyssh, 1094 'socks' => \&verifysocks, 1095 'socks5unix' => \&verifysocks, 1096 'gopher' => \&verifyhttp, 1097 'httptls' => \&verifyhttptls, 1098 'dict' => \&verifyftp, 1099 'smb' => \&verifysmb, 1100 'telnet' => \&verifytelnet); 1101 1102sub verifyserver { 1103 my ($proto, $ipvnum, $idnum, $ip, $port) = @_; 1104 1105 my $count = 30; # try for this many seconds 1106 my $pid; 1107 1108 while($count--) { 1109 my $fun = $protofunc{$proto}; 1110 1111 $pid = &$fun($proto, $ipvnum, $idnum, $ip, $port); 1112 1113 if($pid > 0) { 1114 last; 1115 } 1116 elsif($pid < 0) { 1117 # a real failure, stop trying and bail out 1118 return 0; 1119 } 1120 sleep(1); 1121 } 1122 return $pid; 1123} 1124 1125####################################################################### 1126# Single shot server responsiveness test. This should only be used 1127# to verify that a server present in %run hash is still functional 1128# 1129sub responsiveserver { 1130 my ($proto, $ipvnum, $idnum, $ip, $port, $do_http3) = @_; 1131 my $prev_verbose = $verbose; 1132 1133 $verbose = 0; 1134 my $fun = $protofunc{$proto}; 1135 my $pid = &$fun($proto, $ipvnum, $idnum, $ip, $port, $do_http3); 1136 $verbose = $prev_verbose; 1137 1138 if($pid > 0) { 1139 return 1; # responsive 1140 } 1141 1142 my $srvrname = servername_str($proto, $ipvnum, $idnum); 1143 logmsg " server precheck FAILED (unresponsive $srvrname server)\n"; 1144 return 0; 1145} 1146 1147 1148####################################################################### 1149# start the http server 1150# 1151sub runhttpserver { 1152 my ($proto, $verb, $alt, $port_or_path) = @_; 1153 my $ip = $HOSTIP; 1154 my $ipvnum = 4; 1155 my $idnum = 1; 1156 my $exe = "$perl $srcdir/http-server.pl"; 1157 my $verbose_flag = "--verbose "; 1158 my $keepalive_secs = 30; # forwarded to sws, was 5 by default which 1159 # led to pukes in CI jobs 1160 1161 if($alt eq "ipv6") { 1162 # if IPv6, use a different setup 1163 $ipvnum = 6; 1164 $ip = $HOST6IP; 1165 } 1166 elsif($alt eq "proxy") { 1167 # basically the same, but another ID 1168 $idnum = 2; 1169 } 1170 elsif($alt eq "unix") { 1171 # IP (protocol) is mutually exclusive with Unix sockets 1172 $ipvnum = "unix"; 1173 } 1174 1175 my $server = servername_id($proto, $ipvnum, $idnum); 1176 1177 my $pidfile = $serverpidfile{$server}; 1178 1179 # don't retry if the server doesn't work 1180 if ($doesntrun{$pidfile}) { 1181 return (2, 0, 0, 0); 1182 } 1183 1184 my $pid = processexists($pidfile); 1185 if($pid > 0) { 1186 stopserver($server, "$pid"); 1187 } 1188 unlink($pidfile) if(-f $pidfile); 1189 1190 my $srvrname = servername_str($proto, $ipvnum, $idnum); 1191 my $portfile = $serverportfile{$server}; 1192 1193 my $logfile = server_logfilename($LOGDIR, $proto, $ipvnum, $idnum); 1194 1195 my $flags = ""; 1196 $flags .= "--gopher " if($proto eq "gopher"); 1197 $flags .= "--connect $HOSTIP " if($alt eq "proxy"); 1198 $flags .= "--keepalive $keepalive_secs "; 1199 $flags .= $verbose_flag if($debugprotocol); 1200 $flags .= "--pidfile \"$pidfile\" --logfile \"$logfile\" "; 1201 $flags .= "--logdir \"$LOGDIR\" "; 1202 $flags .= "--portfile $portfile "; 1203 $flags .= "--config $LOGDIR/$SERVERCMD "; 1204 $flags .= "--id $idnum " if($idnum > 1); 1205 if($ipvnum eq "unix") { 1206 $flags .= "--unix-socket '$port_or_path' "; 1207 } else { 1208 $flags .= "--ipv$ipvnum --port 0 "; 1209 } 1210 $flags .= "--srcdir \"$srcdir\""; 1211 1212 my $cmd = "$exe $flags"; 1213 my ($httppid, $pid2) = startnew($cmd, $pidfile, 15, 0); 1214 1215 if($httppid <= 0 || !pidexists($httppid)) { 1216 # it is NOT alive 1217 logmsg "RUN: failed to start the $srvrname server\n"; 1218 stopserver($server, "$pid2"); 1219 $doesntrun{$pidfile} = 1; 1220 return (1, 0, 0, 0); 1221 } 1222 1223 # where is it? 1224 my $port = 0; 1225 if(!$port_or_path) { 1226 $port = $port_or_path = pidfromfile($portfile); 1227 } 1228 1229 # Server is up. Verify that we can speak to it. 1230 my $pid3 = verifyserver($proto, $ipvnum, $idnum, $ip, $port_or_path); 1231 if(!$pid3) { 1232 logmsg "RUN: $srvrname server failed verification\n"; 1233 # failed to talk to it properly. Kill the server and return failure 1234 stopserver($server, "$httppid $pid2"); 1235 $doesntrun{$pidfile} = 1; 1236 return (1, 0, 0, 0); 1237 } 1238 $pid2 = $pid3; 1239 1240 if($verb) { 1241 logmsg "RUN: $srvrname server is on PID $httppid port $port_or_path\n"; 1242 } 1243 1244 return (0, $httppid, $pid2, $port); 1245} 1246 1247 1248####################################################################### 1249# start the http2 server 1250# 1251sub runhttp2server { 1252 my ($verb) = @_; 1253 my $proto="http/2"; 1254 my $ipvnum = 4; 1255 my $idnum = 0; 1256 my $exe = "$perl $srcdir/http2-server.pl"; 1257 my $verbose_flag = "--verbose "; 1258 1259 my $server = servername_id($proto, $ipvnum, $idnum); 1260 1261 my $pidfile = $serverpidfile{$server}; 1262 1263 # don't retry if the server doesn't work 1264 if ($doesntrun{$pidfile}) { 1265 return (2, 0, 0, 0, 0); 1266 } 1267 1268 my $pid = processexists($pidfile); 1269 if($pid > 0) { 1270 stopserver($server, "$pid"); 1271 } 1272 unlink($pidfile) if(-f $pidfile); 1273 1274 my $srvrname = servername_str($proto, $ipvnum, $idnum); 1275 my $logfile = server_logfilename($LOGDIR, $proto, $ipvnum, $idnum); 1276 1277 my $flags = ""; 1278 $flags .= "--nghttpx \"$ENV{'NGHTTPX'}\" "; 1279 $flags .= "--pidfile \"$pidfile\" --logfile \"$logfile\" "; 1280 $flags .= "--logdir \"$LOGDIR\" "; 1281 $flags .= "--connect $HOSTIP:" . protoport("http") . " "; 1282 $flags .= $verbose_flag if($debugprotocol); 1283 1284 my $port = getfreeport($ipvnum); 1285 my $port2 = getfreeport($ipvnum); 1286 my $aflags = "--port $port --port2 $port2 $flags"; 1287 my $cmd = "$exe $aflags"; 1288 my ($http2pid, $pid2) = startnew($cmd, $pidfile, 15, 0); 1289 1290 if($http2pid <= 0 || !pidexists($http2pid)) { 1291 # it is NOT alive 1292 stopserver($server, "$pid2"); 1293 $doesntrun{$pidfile} = 1; 1294 $http2pid = $pid2 = 0; 1295 logmsg "RUN: failed to start the $srvrname server\n"; 1296 return (3, 0, 0, 0, 0); 1297 } 1298 $doesntrun{$pidfile} = 0; 1299 1300 if($verb) { 1301 logmsg "RUN: $srvrname server PID $http2pid ". 1302 "http-port $port https-port $port2 ". 1303 "backend $HOSTIP:" . protoport("http") . "\n"; 1304 } 1305 1306 return (0+!$http2pid, $http2pid, $pid2, $port, $port2); 1307} 1308 1309####################################################################### 1310# start the http3 server 1311# 1312sub runhttp3server { 1313 my ($verb, $cert) = @_; 1314 my $proto="http/3"; 1315 my $ipvnum = 4; 1316 my $idnum = 0; 1317 my $exe = "$perl $srcdir/http3-server.pl"; 1318 my $verbose_flag = "--verbose "; 1319 1320 my $server = servername_id($proto, $ipvnum, $idnum); 1321 1322 my $pidfile = $serverpidfile{$server}; 1323 1324 # don't retry if the server doesn't work 1325 if ($doesntrun{$pidfile}) { 1326 return (2, 0, 0, 0); 1327 } 1328 1329 my $pid = processexists($pidfile); 1330 if($pid > 0) { 1331 stopserver($server, "$pid"); 1332 } 1333 unlink($pidfile) if(-f $pidfile); 1334 1335 my $srvrname = servername_str($proto, $ipvnum, $idnum); 1336 my $logfile = server_logfilename($LOGDIR, $proto, $ipvnum, $idnum); 1337 1338 my $flags = ""; 1339 $flags .= "--nghttpx \"$ENV{'NGHTTPX'}\" "; 1340 $flags .= "--pidfile \"$pidfile\" --logfile \"$logfile\" "; 1341 $flags .= "--logdir \"$LOGDIR\" "; 1342 $flags .= "--connect $HOSTIP:" . protoport("http") . " "; 1343 $flags .= "--cert \"$cert\" " if($cert); 1344 $flags .= $verbose_flag if($debugprotocol); 1345 1346 my $port = getfreeport($ipvnum); 1347 my $aflags = "--port $port $flags"; 1348 my $cmd = "$exe $aflags"; 1349 my ($http3pid, $pid3) = startnew($cmd, $pidfile, 15, 0); 1350 1351 if($http3pid <= 0 || !pidexists($http3pid)) { 1352 # it is NOT alive 1353 stopserver($server, "$pid3"); 1354 $doesntrun{$pidfile} = 1; 1355 $http3pid = $pid3 = 0; 1356 logmsg "RUN: failed to start the $srvrname server\n"; 1357 return (3, 0, 0, 0); 1358 } 1359 $doesntrun{$pidfile} = 0; 1360 1361 if($verb) { 1362 logmsg "RUN: $srvrname server PID $http3pid port $port\n"; 1363 } 1364 1365 return (0+!$http3pid, $http3pid, $pid3, $port); 1366} 1367 1368####################################################################### 1369# start the https stunnel based server 1370# 1371sub runhttpsserver { 1372 my ($verb, $proto, $proxy, $certfile) = @_; 1373 my $ip = $HOSTIP; 1374 my $ipvnum = 4; 1375 my $idnum = 1; 1376 1377 if($proxy eq "proxy") { 1378 # the https-proxy runs as https2 1379 $idnum = 2; 1380 } 1381 1382 if(!$stunnel) { 1383 return (4, 0, 0, 0); 1384 } 1385 1386 my $server = servername_id($proto, $ipvnum, $idnum); 1387 1388 my $pidfile = $serverpidfile{$server}; 1389 1390 # don't retry if the server doesn't work 1391 if ($doesntrun{$pidfile}) { 1392 return (2, 0, 0, 0); 1393 } 1394 1395 my $pid = processexists($pidfile); 1396 if($pid > 0) { 1397 stopserver($server, "$pid"); 1398 } 1399 unlink($pidfile) if(-f $pidfile); 1400 1401 my $srvrname = servername_str($proto, $ipvnum, $idnum); 1402 $certfile = 'stunnel.pem' unless($certfile); 1403 my $logfile = server_logfilename($LOGDIR, $proto, $ipvnum, $idnum); 1404 1405 my $flags = ""; 1406 $flags .= "--verbose " if($debugprotocol); 1407 $flags .= "--pidfile \"$pidfile\" --logfile \"$logfile\" "; 1408 $flags .= "--logdir \"$LOGDIR\" "; 1409 $flags .= "--id $idnum " if($idnum > 1); 1410 $flags .= "--ipv$ipvnum --proto $proto "; 1411 $flags .= "--certfile \"$certfile\" " if($certfile ne 'stunnel.pem'); 1412 $flags .= "--stunnel \"$stunnel\" --srcdir \"$srcdir\" "; 1413 if($proto eq "gophers") { 1414 $flags .= "--connect " . protoport("gopher"); 1415 } 1416 elsif(!$proxy) { 1417 $flags .= "--connect " . protoport("http"); 1418 } 1419 else { 1420 # for HTTPS-proxy we connect to the HTTP proxy 1421 $flags .= "--connect " . protoport("httpproxy"); 1422 } 1423 1424 my $port = getfreeport($ipvnum); 1425 my $options = "$flags --accept $port"; 1426 my $cmd = "$perl $srcdir/secureserver.pl $options"; 1427 my ($httpspid, $pid2) = startnew($cmd, $pidfile, 15, 0); 1428 1429 if($httpspid <= 0 || !pidexists($httpspid)) { 1430 # it is NOT alive 1431 # don't call stopserver since that will also kill the dependent 1432 # server that has already been started properly 1433 $doesntrun{$pidfile} = 1; 1434 $httpspid = $pid2 = 0; 1435 logmsg "RUN: failed to start the $srvrname server\n"; 1436 return (3, 0, 0, 0); 1437 } 1438 1439 $doesntrun{$pidfile} = 0; 1440 # we have a server! 1441 if($verb) { 1442 logmsg "RUN: $srvrname server is PID $httpspid port $port\n"; 1443 } 1444 1445 $runcert{$server} = $certfile; 1446 1447 return (0+!$httpspid, $httpspid, $pid2, $port); 1448} 1449 1450####################################################################### 1451# start the non-stunnel HTTP TLS extensions capable server 1452# 1453sub runhttptlsserver { 1454 my ($verb, $ipv6) = @_; 1455 my $proto = "httptls"; 1456 my $ip = ($ipv6 && ($ipv6 =~ /6$/)) ? "$HOST6IP" : "$HOSTIP"; 1457 my $ipvnum = ($ipv6 && ($ipv6 =~ /6$/)) ? 6 : 4; 1458 my $idnum = 1; 1459 1460 if(!$httptlssrv) { 1461 return (4, 0, 0); 1462 } 1463 1464 my $server = servername_id($proto, $ipvnum, $idnum); 1465 1466 my $pidfile = $serverpidfile{$server}; 1467 1468 # don't retry if the server doesn't work 1469 if ($doesntrun{$pidfile}) { 1470 return (2, 0, 0, 0); 1471 } 1472 1473 my $pid = processexists($pidfile); 1474 if($pid > 0) { 1475 stopserver($server, "$pid"); 1476 } 1477 unlink($pidfile) if(-f $pidfile); 1478 1479 my $srvrname = servername_str($proto, $ipvnum, $idnum); 1480 my $logfile = server_logfilename($LOGDIR, $proto, $ipvnum, $idnum); 1481 1482 my $flags = ""; 1483 $flags .= "--http "; 1484 $flags .= "--debug 1 " if($debugprotocol); 1485 $flags .= "--priority NORMAL:+SRP "; 1486 $flags .= "--srppasswd $srcdir/certs/srp-verifier-db "; 1487 $flags .= "--srppasswdconf $srcdir/certs/srp-verifier-conf"; 1488 1489 my $port = getfreeport($ipvnum); 1490 my $allflags = "--port $port $flags"; 1491 my $cmd = "$httptlssrv $allflags > $logfile 2>&1"; 1492 my ($httptlspid, $pid2) = startnew($cmd, $pidfile, 10, 1); 1493 1494 if($httptlspid <= 0 || !pidexists($httptlspid)) { 1495 # it is NOT alive 1496 stopserver($server, "$pid2"); 1497 $doesntrun{$pidfile} = 1; 1498 $httptlspid = $pid2 = 0; 1499 logmsg "RUN: failed to start the $srvrname server\n"; 1500 return (3, 0, 0, 0); 1501 } 1502 $doesntrun{$pidfile} = 0; 1503 1504 if($verb) { 1505 logmsg "RUN: $srvrname server PID $httptlspid port $port\n"; 1506 } 1507 return (0+!$httptlspid, $httptlspid, $pid2, $port); 1508} 1509 1510####################################################################### 1511# start the pingpong server (FTP, POP3, IMAP, SMTP) 1512# 1513sub runpingpongserver { 1514 my ($proto, $id, $verb, $ipv6) = @_; 1515 1516 # Check the requested server 1517 if($proto !~ /^(?:ftp|imap|pop3|smtp)$/) { 1518 logmsg "Unsupported protocol $proto!!\n"; 1519 return (4, 0, 0); 1520 } 1521 1522 my $ip = ($ipv6 && ($ipv6 =~ /6$/)) ? "$HOST6IP" : "$HOSTIP"; 1523 my $ipvnum = ($ipv6 && ($ipv6 =~ /6$/)) ? 6 : 4; 1524 my $idnum = ($id && ($id =~ /^(\d+)$/) && ($id > 1)) ? $id : 1; 1525 1526 my $server = servername_id($proto, $ipvnum, $idnum); 1527 1528 my $pidfile = $serverpidfile{$server}; 1529 my $portfile = $serverportfile{$server}; 1530 1531 # don't retry if the server doesn't work 1532 if ($doesntrun{$pidfile}) { 1533 return (2, 0, 0); 1534 } 1535 1536 my $pid = processexists($pidfile); 1537 if($pid > 0) { 1538 stopserver($server, "$pid"); 1539 } 1540 unlink($pidfile) if(-f $pidfile); 1541 1542 my $srvrname = servername_str($proto, $ipvnum, $idnum); 1543 my $logfile = server_logfilename($LOGDIR, $proto, $ipvnum, $idnum); 1544 1545 my $flags = ""; 1546 $flags .= "--verbose " if($debugprotocol); 1547 $flags .= "--pidfile \"$pidfile\" --logfile \"$logfile\" "; 1548 $flags .= "--logdir \"$LOGDIR\" "; 1549 $flags .= "--portfile \"$portfile\" "; 1550 $flags .= "--srcdir \"$srcdir\" --proto $proto "; 1551 $flags .= "--id $idnum " if($idnum > 1); 1552 $flags .= "--ipv$ipvnum --port 0 --addr \"$ip\""; 1553 1554 my $cmd = "$perl $srcdir/ftpserver.pl $flags"; 1555 my ($ftppid, $pid2) = startnew($cmd, $pidfile, 15, 0); 1556 1557 if($ftppid <= 0 || !pidexists($ftppid)) { 1558 # it is NOT alive 1559 logmsg "RUN: failed to start the $srvrname server\n"; 1560 stopserver($server, "$pid2"); 1561 $doesntrun{$pidfile} = 1; 1562 return (1, 0, 0); 1563 } 1564 1565 # where is it? 1566 my $port = pidfromfile($portfile); 1567 1568 logmsg "PINGPONG runs on port $port ($portfile)\n" if($verb); 1569 1570 # Server is up. Verify that we can speak to it. 1571 my $pid3 = verifyserver($proto, $ipvnum, $idnum, $ip, $port); 1572 if(!$pid3) { 1573 logmsg "RUN: $srvrname server failed verification\n"; 1574 # failed to talk to it properly. Kill the server and return failure 1575 stopserver($server, "$ftppid $pid2"); 1576 $doesntrun{$pidfile} = 1; 1577 return (1, 0, 0); 1578 } 1579 $pid2 = $pid3; 1580 1581 logmsg "RUN: $srvrname server is PID $ftppid port $port\n" if($verb); 1582 1583 # Assign the correct port variable! 1584 $PORT{$proto . ($ipvnum == 6? '6': '')} = $port; 1585 1586 return (0, $pid2, $ftppid); 1587} 1588 1589####################################################################### 1590# start the ftps/imaps/pop3s/smtps server (or rather, tunnel) 1591# 1592sub runsecureserver { 1593 my ($verb, $ipv6, $certfile, $proto, $clearport) = @_; 1594 my $ip = ($ipv6 && ($ipv6 =~ /6$/)) ? "$HOST6IP" : "$HOSTIP"; 1595 my $ipvnum = ($ipv6 && ($ipv6 =~ /6$/)) ? 6 : 4; 1596 my $idnum = 1; 1597 1598 if(!$stunnel) { 1599 return (4, 0, 0, 0); 1600 } 1601 1602 my $server = servername_id($proto, $ipvnum, $idnum); 1603 1604 my $pidfile = $serverpidfile{$server}; 1605 1606 # don't retry if the server doesn't work 1607 if ($doesntrun{$pidfile}) { 1608 return (2, 0, 0, 0); 1609 } 1610 1611 my $pid = processexists($pidfile); 1612 if($pid > 0) { 1613 stopserver($server, "$pid"); 1614 } 1615 unlink($pidfile) if(-f $pidfile); 1616 1617 my $srvrname = servername_str($proto, $ipvnum, $idnum); 1618 $certfile = 'stunnel.pem' unless($certfile); 1619 my $logfile = server_logfilename($LOGDIR, $proto, $ipvnum, $idnum); 1620 1621 my $flags = ""; 1622 $flags .= "--verbose " if($debugprotocol); 1623 $flags .= "--pidfile \"$pidfile\" --logfile \"$logfile\" "; 1624 $flags .= "--logdir \"$LOGDIR\" "; 1625 $flags .= "--id $idnum " if($idnum > 1); 1626 $flags .= "--ipv$ipvnum --proto $proto "; 1627 $flags .= "--certfile \"$certfile\" " if($certfile ne 'stunnel.pem'); 1628 $flags .= "--stunnel \"$stunnel\" --srcdir \"$srcdir\" "; 1629 $flags .= "--connect $clearport"; 1630 1631 my $port = getfreeport($ipvnum); 1632 my $options = "$flags --accept $port"; 1633 1634 my $cmd = "$perl $srcdir/secureserver.pl $options"; 1635 my ($protospid, $pid2) = startnew($cmd, $pidfile, 15, 0); 1636 1637 if($protospid <= 0 || !pidexists($protospid)) { 1638 # it is NOT alive 1639 # don't call stopserver since that will also kill the dependent 1640 # server that has already been started properly 1641 $doesntrun{$pidfile} = 1; 1642 $protospid = $pid2 = 0; 1643 logmsg "RUN: failed to start the $srvrname server\n"; 1644 return (3, 0, 0, 0); 1645 } 1646 1647 $doesntrun{$pidfile} = 0; 1648 $runcert{$server} = $certfile; 1649 1650 if($verb) { 1651 logmsg "RUN: $srvrname server is PID $protospid port $port\n"; 1652 } 1653 1654 return (0+!$protospid, $protospid, $pid2, $port); 1655} 1656 1657####################################################################### 1658# start the tftp server 1659# 1660sub runtftpserver { 1661 my ($id, $verb, $ipv6) = @_; 1662 my $ip = $HOSTIP; 1663 my $proto = 'tftp'; 1664 my $ipvnum = 4; 1665 my $idnum = ($id && ($id =~ /^(\d+)$/) && ($id > 1)) ? $id : 1; 1666 1667 if($ipv6) { 1668 # if IPv6, use a different setup 1669 $ipvnum = 6; 1670 $ip = $HOST6IP; 1671 } 1672 1673 my $server = servername_id($proto, $ipvnum, $idnum); 1674 1675 my $pidfile = $serverpidfile{$server}; 1676 1677 # don't retry if the server doesn't work 1678 if ($doesntrun{$pidfile}) { 1679 return (2, 0, 0, 0); 1680 } 1681 1682 my $pid = processexists($pidfile); 1683 if($pid > 0) { 1684 stopserver($server, "$pid"); 1685 } 1686 unlink($pidfile) if(-f $pidfile); 1687 1688 my $srvrname = servername_str($proto, $ipvnum, $idnum); 1689 my $portfile = $serverportfile{$server}; 1690 my $logfile = server_logfilename($LOGDIR, $proto, $ipvnum, $idnum); 1691 1692 my $flags = ""; 1693 $flags .= "--verbose " if($debugprotocol); 1694 $flags .= "--pidfile \"$pidfile\" "; 1695 $flags .= "--portfile \"$portfile\" "; 1696 $flags .= "--logfile \"$logfile\" "; 1697 $flags .= "--logdir \"$LOGDIR\" "; 1698 $flags .= "--id $idnum " if($idnum > 1); 1699 $flags .= "--ipv$ipvnum --port 0 --srcdir \"$srcdir\""; 1700 1701 my $cmd = "$perl $srcdir/tftpserver.pl $flags"; 1702 my ($tftppid, $pid2) = startnew($cmd, $pidfile, 15, 0); 1703 1704 if($tftppid <= 0 || !pidexists($tftppid)) { 1705 # it is NOT alive 1706 logmsg "RUN: failed to start the $srvrname server\n"; 1707 stopserver($server, "$pid2"); 1708 $doesntrun{$pidfile} = 1; 1709 return (1, 0, 0, 0); 1710 } 1711 1712 my $port = pidfromfile($portfile); 1713 1714 # Server is up. Verify that we can speak to it. 1715 my $pid3 = verifyserver($proto, $ipvnum, $idnum, $ip, $port); 1716 if(!$pid3) { 1717 logmsg "RUN: $srvrname server failed verification\n"; 1718 # failed to talk to it properly. Kill the server and return failure 1719 stopserver($server, "$tftppid $pid2"); 1720 $doesntrun{$pidfile} = 1; 1721 return (1, 0, 0, 0); 1722 } 1723 $pid2 = $pid3; 1724 1725 if($verb) { 1726 logmsg "RUN: $srvrname server on PID $tftppid port $port\n"; 1727 } 1728 1729 return (0, $pid2, $tftppid, $port); 1730} 1731 1732 1733####################################################################### 1734# start the rtsp server 1735# 1736sub runrtspserver { 1737 my ($verb, $ipv6) = @_; 1738 my $ip = $HOSTIP; 1739 my $proto = 'rtsp'; 1740 my $ipvnum = 4; 1741 my $idnum = 1; 1742 1743 if($ipv6) { 1744 # if IPv6, use a different setup 1745 $ipvnum = 6; 1746 $ip = $HOST6IP; 1747 } 1748 1749 my $server = servername_id($proto, $ipvnum, $idnum); 1750 1751 my $pidfile = $serverpidfile{$server}; 1752 my $portfile = $serverportfile{$server}; 1753 1754 # don't retry if the server doesn't work 1755 if ($doesntrun{$pidfile}) { 1756 return (2, 0, 0, 0); 1757 } 1758 1759 my $pid = processexists($pidfile); 1760 if($pid > 0) { 1761 stopserver($server, "$pid"); 1762 } 1763 unlink($pidfile) if(-f $pidfile); 1764 1765 my $srvrname = servername_str($proto, $ipvnum, $idnum); 1766 my $logfile = server_logfilename($LOGDIR, $proto, $ipvnum, $idnum); 1767 1768 my $flags = ""; 1769 $flags .= "--verbose " if($debugprotocol); 1770 $flags .= "--pidfile \"$pidfile\" "; 1771 $flags .= "--portfile \"$portfile\" "; 1772 $flags .= "--logfile \"$logfile\" "; 1773 $flags .= "--logdir \"$LOGDIR\" "; 1774 $flags .= "--id $idnum " if($idnum > 1); 1775 $flags .= "--ipv$ipvnum --port 0 --srcdir \"$srcdir\""; 1776 1777 my $cmd = "$perl $srcdir/rtspserver.pl $flags"; 1778 my ($rtsppid, $pid2) = startnew($cmd, $pidfile, 15, 0); 1779 1780 if($rtsppid <= 0 || !pidexists($rtsppid)) { 1781 # it is NOT alive 1782 logmsg "RUN: failed to start the $srvrname server\n"; 1783 stopserver($server, "$pid2"); 1784 $doesntrun{$pidfile} = 1; 1785 return (1, 0, 0, 0); 1786 } 1787 1788 my $port = pidfromfile($portfile); 1789 1790 # Server is up. Verify that we can speak to it. 1791 my $pid3 = verifyserver($proto, $ipvnum, $idnum, $ip, $port); 1792 if(!$pid3) { 1793 logmsg "RUN: $srvrname server failed verification\n"; 1794 # failed to talk to it properly. Kill the server and return failure 1795 stopserver($server, "$rtsppid $pid2"); 1796 $doesntrun{$pidfile} = 1; 1797 return (1, 0, 0, 0); 1798 } 1799 $pid2 = $pid3; 1800 1801 if($verb) { 1802 logmsg "RUN: $srvrname server PID $rtsppid port $port\n"; 1803 } 1804 1805 return (0, $rtsppid, $pid2, $port); 1806} 1807 1808 1809####################################################################### 1810# Start the ssh (scp/sftp) server 1811# 1812sub runsshserver { 1813 my ($id, $verb, $ipv6) = @_; 1814 my $ip=$HOSTIP; 1815 my $proto = 'ssh'; 1816 my $ipvnum = 4; 1817 my $idnum = ($id && ($id =~ /^(\d+)$/) && ($id > 1)) ? $id : 1; 1818 1819 if(!$USER) { 1820 logmsg "Can't start ssh server due to lack of USER name\n"; 1821 return (4, 0, 0, 0); 1822 } 1823 1824 my $server = servername_id($proto, $ipvnum, $idnum); 1825 1826 my $pidfile = $serverpidfile{$server}; 1827 1828 # don't retry if the server doesn't work 1829 if ($doesntrun{$pidfile}) { 1830 return (2, 0, 0, 0); 1831 } 1832 1833 my $sshd = find_sshd(); 1834 if($sshd) { 1835 ($sshdid,$sshdvernum,$sshdverstr,$sshderror) = sshversioninfo($sshd); 1836 logmsg $sshderror if($sshderror); 1837 } 1838 1839 my $pid = processexists($pidfile); 1840 if($pid > 0) { 1841 stopserver($server, "$pid"); 1842 } 1843 unlink($pidfile) if(-f $pidfile); 1844 1845 my $srvrname = servername_str($proto, $ipvnum, $idnum); 1846 my $logfile = server_logfilename($LOGDIR, $proto, $ipvnum, $idnum); 1847 1848 my $flags = ""; 1849 $flags .= "--verbose " if($verb); 1850 $flags .= "--debugprotocol " if($debugprotocol); 1851 $flags .= "--pidfile \"$pidfile\" "; 1852 $flags .= "--logdir \"$LOGDIR\" "; 1853 $flags .= "--id $idnum " if($idnum > 1); 1854 $flags .= "--ipv$ipvnum --addr \"$ip\" "; 1855 $flags .= "--user \"$USER\""; 1856 1857 my @tports; 1858 my $port = getfreeport($ipvnum); 1859 1860 push @tports, $port; 1861 1862 my $options = "$flags --sshport $port"; 1863 1864 my $cmd = "$perl $srcdir/sshserver.pl $options"; 1865 my ($sshpid, $pid2) = startnew($cmd, $pidfile, 60, 0); 1866 1867 # on loaded systems sshserver start up can take longer than the 1868 # timeout passed to startnew, when this happens startnew completes 1869 # without being able to read the pidfile and consequently returns a 1870 # zero pid2 above. 1871 if($sshpid <= 0 || !pidexists($sshpid)) { 1872 # it is NOT alive 1873 stopserver($server, "$pid2"); 1874 $doesntrun{$pidfile} = 1; 1875 $sshpid = $pid2 = 0; 1876 logmsg "RUN: failed to start the $srvrname server on $port\n"; 1877 return (3, 0, 0, 0); 1878 } 1879 1880 # once it is known that the ssh server is alive, sftp server 1881 # verification is performed actually connecting to it, authenticating 1882 # and performing a very simple remote command. This verification is 1883 # tried only one time. 1884 1885 $sshdlog = server_logfilename($LOGDIR, 'ssh', $ipvnum, $idnum); 1886 $sftplog = server_logfilename($LOGDIR, 'sftp', $ipvnum, $idnum); 1887 1888 if(verifysftp('sftp', $ipvnum, $idnum, $ip, $port) < 1) { 1889 logmsg "RUN: SFTP server failed verification\n"; 1890 # failed to talk to it properly. Kill the server and return failure 1891 display_sftplog(); 1892 display_sftpconfig(); 1893 display_sshdlog(); 1894 display_sshdconfig(); 1895 stopserver($server, "$sshpid $pid2"); 1896 $doesntrun{$pidfile} = 1; 1897 $sshpid = $pid2 = 0; 1898 logmsg "RUN: failed to verify the $srvrname server on $port\n"; 1899 return (5, 0, 0, 0); 1900 } 1901 # we're happy, no need to loop anymore! 1902 $doesntrun{$pidfile} = 0; 1903 1904 my $hostfile; 1905 if(!open($hostfile, "<", "$LOGDIR/$PIDDIR/$hstpubmd5f") || 1906 (read($hostfile, $SSHSRVMD5, 32) != 32) || 1907 !close($hostfile) || 1908 ($SSHSRVMD5 !~ /^[a-f0-9]{32}$/i)) 1909 { 1910 my $msg = "Fatal: $srvrname pubkey md5 missing : \"$hstpubmd5f\" : $!"; 1911 logmsg "$msg\n"; 1912 stopservers($verb); 1913 die $msg; 1914 } 1915 1916 if(!open($hostfile, "<", "$LOGDIR/$PIDDIR/$hstpubsha256f") || 1917 (read($hostfile, $SSHSRVSHA256, 48) == 0) || 1918 !close($hostfile)) 1919 { 1920 my $msg = "Fatal: $srvrname pubkey sha256 missing : \"$hstpubsha256f\" : $!"; 1921 logmsg "$msg\n"; 1922 stopservers($verb); 1923 die $msg; 1924 } 1925 1926 logmsg "RUN: $srvrname on PID $pid2 port $port\n" if($verb); 1927 1928 return (0, $pid2, $sshpid, $port); 1929} 1930 1931####################################################################### 1932# Start the MQTT server 1933# 1934sub runmqttserver { 1935 my ($id, $verb, $ipv6) = @_; 1936 my $ip=$HOSTIP; 1937 my $proto = 'mqtt'; 1938 my $port = protoport($proto); 1939 my $ipvnum = 4; 1940 my $idnum = ($id && ($id =~ /^(\d+)$/) && ($id > 1)) ? $id : 1; 1941 1942 my $server = servername_id($proto, $ipvnum, $idnum); 1943 my $pidfile = $serverpidfile{$server}; 1944 my $portfile = $serverportfile{$server}; 1945 1946 # don't retry if the server doesn't work 1947 if ($doesntrun{$pidfile}) { 1948 return (2, 0, 0); 1949 } 1950 1951 my $pid = processexists($pidfile); 1952 if($pid > 0) { 1953 stopserver($server, "$pid"); 1954 } 1955 unlink($pidfile) if(-f $pidfile); 1956 1957 my $srvrname = servername_str($proto, $ipvnum, $idnum); 1958 my $logfile = server_logfilename($LOGDIR, $proto, $ipvnum, $idnum); 1959 1960 # start our MQTT server - on a random port! 1961 my $cmd="server/mqttd".exe_ext('SRV'). 1962 " --port 0 ". 1963 " --pidfile $pidfile". 1964 " --portfile $portfile". 1965 " --config $LOGDIR/$SERVERCMD". 1966 " --logfile $logfile". 1967 " --logdir $LOGDIR"; 1968 my ($sockspid, $pid2) = startnew($cmd, $pidfile, 30, 0); 1969 1970 if($sockspid <= 0 || !pidexists($sockspid)) { 1971 # it is NOT alive 1972 logmsg "RUN: failed to start the $srvrname server\n"; 1973 stopserver($server, "$pid2"); 1974 $doesntrun{$pidfile} = 1; 1975 return (1, 0, 0); 1976 } 1977 1978 my $mqttport = pidfromfile($portfile); 1979 1980 if($verb) { 1981 logmsg "RUN: $srvrname server is now running PID $pid2 on PORT $mqttport\n"; 1982 } 1983 1984 return (0, $pid2, $sockspid, $mqttport); 1985} 1986 1987####################################################################### 1988# Start the socks server 1989# 1990sub runsocksserver { 1991 my ($id, $verb, $ipv6, $is_unix) = @_; 1992 my $ip=$HOSTIP; 1993 my $proto = 'socks'; 1994 my $ipvnum = 4; 1995 my $idnum = ($id && ($id =~ /^(\d+)$/) && ($id > 1)) ? $id : 1; 1996 1997 my $server = servername_id($proto, $ipvnum, $idnum); 1998 1999 my $pidfile = $serverpidfile{$server}; 2000 2001 # don't retry if the server doesn't work 2002 if ($doesntrun{$pidfile}) { 2003 return (2, 0, 0, 0); 2004 } 2005 2006 my $pid = processexists($pidfile); 2007 if($pid > 0) { 2008 stopserver($server, "$pid"); 2009 } 2010 unlink($pidfile) if(-f $pidfile); 2011 2012 my $srvrname = servername_str($proto, $ipvnum, $idnum); 2013 my $portfile = $serverportfile{$server}; 2014 my $logfile = server_logfilename($LOGDIR, $proto, $ipvnum, $idnum); 2015 2016 # start our socks server, get commands from the FTP cmd file 2017 my $cmd=""; 2018 if($is_unix) { 2019 $cmd="server/socksd".exe_ext('SRV'). 2020 " --pidfile $pidfile". 2021 " --reqfile $LOGDIR/$SOCKSIN". 2022 " --logfile $logfile". 2023 " --unix-socket $SOCKSUNIXPATH". 2024 " --backend $HOSTIP". 2025 " --config $LOGDIR/$SERVERCMD"; 2026 } else { 2027 $cmd="server/socksd".exe_ext('SRV'). 2028 " --port 0 ". 2029 " --pidfile $pidfile". 2030 " --portfile $portfile". 2031 " --reqfile $LOGDIR/$SOCKSIN". 2032 " --logfile $logfile". 2033 " --backend $HOSTIP". 2034 " --config $LOGDIR/$SERVERCMD"; 2035 } 2036 my ($sockspid, $pid2) = startnew($cmd, $pidfile, 30, 0); 2037 2038 if($sockspid <= 0 || !pidexists($sockspid)) { 2039 # it is NOT alive 2040 logmsg "RUN: failed to start the $srvrname server\n"; 2041 stopserver($server, "$pid2"); 2042 $doesntrun{$pidfile} = 1; 2043 return (1, 0, 0, 0); 2044 } 2045 2046 my $port = pidfromfile($portfile); 2047 2048 if($verb) { 2049 logmsg "RUN: $srvrname server is now running PID $pid2\n"; 2050 } 2051 2052 return (0, $pid2, $sockspid, $port); 2053} 2054 2055####################################################################### 2056# start the dict server 2057# 2058sub rundictserver { 2059 my ($verb, $alt) = @_; 2060 my $proto = "dict"; 2061 my $ip = $HOSTIP; 2062 my $ipvnum = 4; 2063 my $idnum = 1; 2064 2065 if($alt eq "ipv6") { 2066 # No IPv6 2067 } 2068 2069 my $server = servername_id($proto, $ipvnum, $idnum); 2070 2071 my $pidfile = $serverpidfile{$server}; 2072 2073 # don't retry if the server doesn't work 2074 if ($doesntrun{$pidfile}) { 2075 return (2, 0, 0, 0); 2076 } 2077 2078 my $pid = processexists($pidfile); 2079 if($pid > 0) { 2080 stopserver($server, "$pid"); 2081 } 2082 unlink($pidfile) if(-f $pidfile); 2083 2084 my $srvrname = servername_str($proto, $ipvnum, $idnum); 2085 my $logfile = server_logfilename($LOGDIR, $proto, $ipvnum, $idnum); 2086 2087 my $flags = ""; 2088 $flags .= "--verbose 1 " if($debugprotocol); 2089 $flags .= "--pidfile \"$pidfile\" --logfile \"$logfile\" "; 2090 $flags .= "--id $idnum " if($idnum > 1); 2091 $flags .= "--srcdir \"$srcdir\" "; 2092 $flags .= "--host $HOSTIP"; 2093 2094 my $port = getfreeport($ipvnum); 2095 my $aflags = "--port $port $flags"; 2096 my $cmd = "$srcdir/dictserver.py $aflags"; 2097 my ($dictpid, $pid2) = startnew($cmd, $pidfile, 15, 0); 2098 2099 if($dictpid <= 0 || !pidexists($dictpid)) { 2100 # it is NOT alive 2101 stopserver($server, "$pid2"); 2102 $doesntrun{$pidfile} = 1; 2103 $dictpid = $pid2 = 0; 2104 logmsg "RUN: failed to start the $srvrname server\n"; 2105 return (3, 0, 0, 0); 2106 } 2107 $doesntrun{$pidfile} = 0; 2108 2109 if($verb) { 2110 logmsg "RUN: $srvrname server PID $dictpid port $port\n"; 2111 } 2112 2113 return (0+!$dictpid, $dictpid, $pid2, $port); 2114} 2115 2116####################################################################### 2117# start the SMB server 2118# 2119sub runsmbserver { 2120 my ($verb, $alt) = @_; 2121 my $proto = "smb"; 2122 my $ip = $HOSTIP; 2123 my $ipvnum = 4; 2124 my $idnum = 1; 2125 2126 if($alt eq "ipv6") { 2127 # No IPv6 2128 } 2129 2130 my $server = servername_id($proto, $ipvnum, $idnum); 2131 2132 my $pidfile = $serverpidfile{$server}; 2133 2134 # don't retry if the server doesn't work 2135 if ($doesntrun{$pidfile}) { 2136 return (2, 0, 0, 0); 2137 } 2138 2139 my $pid = processexists($pidfile); 2140 if($pid > 0) { 2141 stopserver($server, "$pid"); 2142 } 2143 unlink($pidfile) if(-f $pidfile); 2144 2145 my $srvrname = servername_str($proto, $ipvnum, $idnum); 2146 my $logfile = server_logfilename($LOGDIR, $proto, $ipvnum, $idnum); 2147 2148 my $flags = ""; 2149 $flags .= "--verbose 1 " if($debugprotocol); 2150 $flags .= "--pidfile \"$pidfile\" --logfile \"$logfile\" "; 2151 $flags .= "--id $idnum " if($idnum > 1); 2152 $flags .= "--srcdir \"$srcdir\" "; 2153 $flags .= "--host $HOSTIP"; 2154 2155 my $port = getfreeport($ipvnum); 2156 my $aflags = "--port $port $flags"; 2157 my $cmd = "$srcdir/smbserver.py $aflags"; 2158 my ($smbpid, $pid2) = startnew($cmd, $pidfile, 15, 0); 2159 2160 if($smbpid <= 0 || !pidexists($smbpid)) { 2161 # it is NOT alive 2162 stopserver($server, "$pid2"); 2163 $doesntrun{$pidfile} = 1; 2164 $smbpid = $pid2 = 0; 2165 logmsg "RUN: failed to start the $srvrname server\n"; 2166 return (3, 0, 0, 0); 2167 } 2168 $doesntrun{$pidfile} = 0; 2169 2170 if($verb) { 2171 logmsg "RUN: $srvrname server PID $smbpid port $port\n"; 2172 } 2173 2174 return (0+!$smbpid, $smbpid, $pid2, $port); 2175} 2176 2177####################################################################### 2178# start the telnet server 2179# 2180sub runnegtelnetserver { 2181 my ($verb, $alt) = @_; 2182 my $proto = "telnet"; 2183 my $ip = $HOSTIP; 2184 my $ipvnum = 4; 2185 my $idnum = 1; 2186 2187 if($alt eq "ipv6") { 2188 # No IPv6 2189 } 2190 2191 my $server = servername_id($proto, $ipvnum, $idnum); 2192 2193 my $pidfile = $serverpidfile{$server}; 2194 2195 # don't retry if the server doesn't work 2196 if ($doesntrun{$pidfile}) { 2197 return (2, 0, 0, 0); 2198 } 2199 2200 my $pid = processexists($pidfile); 2201 if($pid > 0) { 2202 stopserver($server, "$pid"); 2203 } 2204 unlink($pidfile) if(-f $pidfile); 2205 2206 my $srvrname = servername_str($proto, $ipvnum, $idnum); 2207 my $logfile = server_logfilename($LOGDIR, $proto, $ipvnum, $idnum); 2208 2209 my $flags = ""; 2210 $flags .= "--verbose 1 " if($debugprotocol); 2211 $flags .= "--pidfile \"$pidfile\" --logfile \"$logfile\" "; 2212 $flags .= "--id $idnum " if($idnum > 1); 2213 $flags .= "--srcdir \"$srcdir\""; 2214 2215 my $port = getfreeport($ipvnum); 2216 my $aflags = "--port $port $flags"; 2217 my $cmd = "$srcdir/negtelnetserver.py $aflags"; 2218 my ($ntelpid, $pid2) = startnew($cmd, $pidfile, 15, 0); 2219 2220 if($ntelpid <= 0 || !pidexists($ntelpid)) { 2221 # it is NOT alive 2222 stopserver($server, "$pid2"); 2223 $doesntrun{$pidfile} = 1; 2224 $ntelpid = $pid2 = 0; 2225 logmsg "RUN: failed to start the $srvrname server\n"; 2226 return (3, 0, 0, 0); 2227 } 2228 $doesntrun{$pidfile} = 0; 2229 2230 if($verb) { 2231 logmsg "RUN: $srvrname server PID $ntelpid port $port\n"; 2232 } 2233 2234 return (0+!$ntelpid, $ntelpid, $pid2, $port); 2235} 2236 2237 2238 2239 2240####################################################################### 2241# Single shot http and gopher server responsiveness test. This should only 2242# be used to verify that a server present in %run hash is still functional 2243# 2244sub responsive_http_server { 2245 my ($proto, $verb, $alt, $port_or_path, $do_http3) = @_; 2246 my $ip = $HOSTIP; 2247 my $ipvnum = 4; 2248 my $idnum = 1; 2249 2250 if($alt eq "ipv6") { 2251 # if IPv6, use a different setup 2252 $ipvnum = 6; 2253 $ip = $HOST6IP; 2254 } 2255 elsif($alt eq "proxy") { 2256 $idnum = 2; 2257 } 2258 elsif($alt eq "unix") { 2259 # IP (protocol) is mutually exclusive with Unix sockets 2260 $ipvnum = "unix"; 2261 } 2262 2263 return &responsiveserver($proto, $ipvnum, $idnum, $ip, $port_or_path, $do_http3); 2264} 2265 2266####################################################################### 2267# Single shot mqtt server responsiveness test. This should only 2268# be used to verify that a server present in %run hash is still functional 2269# 2270sub responsive_mqtt_server { 2271 my ($proto, $id, $verb, $ipv6) = @_; 2272 my $ip = ($ipv6 && ($ipv6 =~ /6$/)) ? "$HOST6IP" : "$HOSTIP"; 2273 my $ipvnum = ($ipv6 && ($ipv6 =~ /6$/)) ? 6 : 4; 2274 my $idnum = ($id && ($id =~ /^(\d+)$/) && ($id > 1)) ? $id : 1; 2275 2276 return &responsiveserver($proto, $ipvnum, $idnum, $ip); 2277} 2278 2279####################################################################### 2280# Single shot pingpong server responsiveness test. This should only be 2281# used to verify that a server present in %run hash is still functional 2282# 2283sub responsive_pingpong_server { 2284 my ($proto, $id, $verb, $ipv6) = @_; 2285 my $port; 2286 my $ip = ($ipv6 && ($ipv6 =~ /6$/)) ? "$HOST6IP" : "$HOSTIP"; 2287 my $ipvnum = ($ipv6 && ($ipv6 =~ /6$/)) ? 6 : 4; 2288 my $idnum = ($id && ($id =~ /^(\d+)$/) && ($id > 1)) ? $id : 1; 2289 my $protoip = $proto . ($ipvnum == 6? '6': ''); 2290 2291 if($proto =~ /^(?:ftp|imap|pop3|smtp)$/) { 2292 $port = protoport($protoip); 2293 } 2294 else { 2295 logmsg "Unsupported protocol $proto!!\n"; 2296 return 0; 2297 } 2298 2299 return &responsiveserver($proto, $ipvnum, $idnum, $ip, $port); 2300} 2301 2302####################################################################### 2303# Single shot rtsp server responsiveness test. This should only be 2304# used to verify that a server present in %run hash is still functional 2305# 2306sub responsive_rtsp_server { 2307 my ($verb, $ipv6) = @_; 2308 my $proto = 'rtsp'; 2309 my $port = protoport($proto); 2310 my $ip = $HOSTIP; 2311 my $ipvnum = 4; 2312 my $idnum = 1; 2313 2314 if($ipv6) { 2315 # if IPv6, use a different setup 2316 $ipvnum = 6; 2317 $port = protoport('rtsp6'); 2318 $ip = $HOST6IP; 2319 } 2320 2321 return &responsiveserver($proto, $ipvnum, $idnum, $ip, $port); 2322} 2323 2324####################################################################### 2325# Single shot tftp server responsiveness test. This should only be 2326# used to verify that a server present in %run hash is still functional 2327# 2328sub responsive_tftp_server { 2329 my ($id, $verb, $ipv6) = @_; 2330 my $proto = 'tftp'; 2331 my $port = protoport($proto); 2332 my $ip = $HOSTIP; 2333 my $ipvnum = 4; 2334 my $idnum = ($id && ($id =~ /^(\d+)$/) && ($id > 1)) ? $id : 1; 2335 2336 if($ipv6) { 2337 # if IPv6, use a different setup 2338 $ipvnum = 6; 2339 $port = protoport('tftp6'); 2340 $ip = $HOST6IP; 2341 } 2342 2343 return &responsiveserver($proto, $ipvnum, $idnum, $ip, $port); 2344} 2345 2346####################################################################### 2347# Single shot non-stunnel HTTP TLS extensions capable server 2348# responsiveness test. This should only be used to verify that a 2349# server present in %run hash is still functional 2350# 2351sub responsive_httptls_server { 2352 my ($verb, $ipv6) = @_; 2353 my $ipvnum = ($ipv6 && ($ipv6 =~ /6$/)) ? 6 : 4; 2354 my $proto = "httptls"; 2355 my $port = protoport($proto); 2356 my $ip = "$HOSTIP"; 2357 my $idnum = 1; 2358 2359 if ($ipvnum == 6) { 2360 $port = protoport("httptls6"); 2361 $ip = "$HOST6IP"; 2362 } 2363 2364 return &responsiveserver($proto, $ipvnum, $idnum, $ip, $port); 2365} 2366 2367####################################################################### 2368# startservers() starts all the named servers 2369# 2370# Returns: string with error reason or blank for success, and an integer: 2371# 0 for success 2372# 1 for an error starting the server 2373# 2 for not the first time getting an error starting the server 2374# 3 for a failure to stop a server in order to restart it 2375# 4 for an unsupported server type 2376# 2377sub startservers { 2378 my @what = @_; 2379 my ($pid, $pid2); 2380 my $serr; # error while starting a server (as of the return enumerations) 2381 for(@what) { 2382 my (@whatlist) = split(/\s+/,$_); 2383 my $what = lc($whatlist[0]); 2384 $what =~ s/[^a-z0-9\/-]//g; 2385 2386 my $certfile; 2387 if($what =~ /^(ftp|gopher|http|imap|pop3|smtp)s((\d*)(-ipv6|-unix|))$/) { 2388 $certfile = ($whatlist[1]) ? $whatlist[1] : 'stunnel.pem'; 2389 } 2390 2391 if(($what eq "pop3") || 2392 ($what eq "ftp") || 2393 ($what eq "imap") || 2394 ($what eq "smtp")) { 2395 if($run{$what} && 2396 !responsive_pingpong_server($what, "", $verbose)) { 2397 if(stopserver($what)) { 2398 return ("failed stopping unresponsive ".uc($what)." server", 3); 2399 } 2400 } 2401 if(!$run{$what}) { 2402 ($serr, $pid, $pid2) = runpingpongserver($what, "", $verbose); 2403 if($pid <= 0) { 2404 return ("failed starting ". uc($what) ." server", $serr); 2405 } 2406 logmsg sprintf("* pid $what => %d %d\n", $pid, $pid2) if($verbose); 2407 $run{$what}="$pid $pid2"; 2408 } 2409 } 2410 elsif($what eq "ftp-ipv6") { 2411 if($run{'ftp-ipv6'} && 2412 !responsive_pingpong_server("ftp", "", $verbose, "ipv6")) { 2413 if(stopserver('ftp-ipv6')) { 2414 return ("failed stopping unresponsive FTP-IPv6 server", 3); 2415 } 2416 } 2417 if(!$run{'ftp-ipv6'}) { 2418 ($serr, $pid, $pid2) = runpingpongserver("ftp", "", $verbose, "ipv6"); 2419 if($pid <= 0) { 2420 return ("failed starting FTP-IPv6 server", $serr); 2421 } 2422 logmsg sprintf("* pid ftp-ipv6 => %d %d\n", $pid, 2423 $pid2) if($verbose); 2424 $run{'ftp-ipv6'}="$pid $pid2"; 2425 } 2426 } 2427 elsif($what eq "gopher") { 2428 if($run{'gopher'} && 2429 !responsive_http_server("gopher", $verbose, 0, 2430 protoport("gopher"))) { 2431 if(stopserver('gopher')) { 2432 return ("failed stopping unresponsive GOPHER server", 3); 2433 } 2434 } 2435 if(!$run{'gopher'}) { 2436 ($serr, $pid, $pid2, $PORT{'gopher'}) = 2437 runhttpserver("gopher", $verbose, 0); 2438 if($pid <= 0) { 2439 return ("failed starting GOPHER server", $serr); 2440 } 2441 logmsg sprintf ("* pid gopher => %d %d\n", $pid, $pid2) 2442 if($verbose); 2443 $run{'gopher'}="$pid $pid2"; 2444 } 2445 } 2446 elsif($what eq "gopher-ipv6") { 2447 if($run{'gopher-ipv6'} && 2448 !responsive_http_server("gopher", $verbose, "ipv6", 2449 protoport("gopher"))) { 2450 if(stopserver('gopher-ipv6')) { 2451 return ("failed stopping unresponsive GOPHER-IPv6 server", 3); 2452 } 2453 } 2454 if(!$run{'gopher-ipv6'}) { 2455 ($serr, $pid, $pid2, $PORT{"gopher6"}) = 2456 runhttpserver("gopher", $verbose, "ipv6"); 2457 if($pid <= 0) { 2458 return ("failed starting GOPHER-IPv6 server", $serr); 2459 } 2460 logmsg sprintf("* pid gopher-ipv6 => %d %d\n", $pid, 2461 $pid2) if($verbose); 2462 $run{'gopher-ipv6'}="$pid $pid2"; 2463 } 2464 } 2465 elsif($what eq "http") { 2466 if($run{'http'} && 2467 !responsive_http_server("http", $verbose, 0, protoport('http'))) { 2468 logmsg "* restarting unresponsive HTTP server\n"; 2469 if(stopserver('http')) { 2470 return ("failed stopping unresponsive HTTP server", 3); 2471 } 2472 } 2473 if(!$run{'http'}) { 2474 ($serr, $pid, $pid2, $PORT{'http'}) = 2475 runhttpserver("http", $verbose, 0); 2476 if($pid <= 0) { 2477 return ("failed starting HTTP server", $serr); 2478 } 2479 logmsg sprintf ("* pid http => %d %d\n", $pid, $pid2) 2480 if($verbose); 2481 $run{'http'}="$pid $pid2"; 2482 } 2483 } 2484 elsif($what eq "http-proxy") { 2485 if($run{'http-proxy'} && 2486 !responsive_http_server("http", $verbose, "proxy", 2487 protoport("httpproxy"))) { 2488 if(stopserver('http-proxy')) { 2489 return ("failed stopping unresponsive HTTP-proxy server", 3); 2490 } 2491 } 2492 if(!$run{'http-proxy'}) { 2493 ($serr, $pid, $pid2, $PORT{"httpproxy"}) = 2494 runhttpserver("http", $verbose, "proxy"); 2495 if($pid <= 0) { 2496 return ("failed starting HTTP-proxy server", $serr); 2497 } 2498 logmsg sprintf ("* pid http-proxy => %d %d\n", $pid, $pid2) 2499 if($verbose); 2500 $run{'http-proxy'}="$pid $pid2"; 2501 } 2502 } 2503 elsif($what eq "http-ipv6") { 2504 if($run{'http-ipv6'} && 2505 !responsive_http_server("http", $verbose, "ipv6", 2506 protoport("http6"))) { 2507 if(stopserver('http-ipv6')) { 2508 return ("failed stopping unresponsive HTTP-IPv6 server", 3); 2509 } 2510 } 2511 if(!$run{'http-ipv6'}) { 2512 ($serr, $pid, $pid2, $PORT{"http6"}) = 2513 runhttpserver("http", $verbose, "ipv6"); 2514 if($pid <= 0) { 2515 return ("failed starting HTTP-IPv6 server", $serr); 2516 } 2517 logmsg sprintf("* pid http-ipv6 => %d %d\n", $pid, $pid2) 2518 if($verbose); 2519 $run{'http-ipv6'}="$pid $pid2"; 2520 } 2521 } 2522 elsif($what eq "rtsp") { 2523 if($run{'rtsp'} && 2524 !responsive_rtsp_server($verbose)) { 2525 if(stopserver('rtsp')) { 2526 return ("failed stopping unresponsive RTSP server", 3); 2527 } 2528 } 2529 if(!$run{'rtsp'}) { 2530 ($serr, $pid, $pid2, $PORT{'rtsp'}) = runrtspserver($verbose); 2531 if($pid <= 0) { 2532 return ("failed starting RTSP server", $serr); 2533 } 2534 logmsg sprintf("* pid rtsp => %d %d\n", $pid, $pid2) if($verbose); 2535 $run{'rtsp'}="$pid $pid2"; 2536 } 2537 } 2538 elsif($what eq "rtsp-ipv6") { 2539 if($run{'rtsp-ipv6'} && 2540 !responsive_rtsp_server($verbose, "ipv6")) { 2541 if(stopserver('rtsp-ipv6')) { 2542 return ("failed stopping unresponsive RTSP-IPv6 server", 3); 2543 } 2544 } 2545 if(!$run{'rtsp-ipv6'}) { 2546 ($serr, $pid, $pid2, $PORT{'rtsp6'}) = runrtspserver($verbose, "ipv6"); 2547 if($pid <= 0) { 2548 return ("failed starting RTSP-IPv6 server", $serr); 2549 } 2550 logmsg sprintf("* pid rtsp-ipv6 => %d %d\n", $pid, $pid2) 2551 if($verbose); 2552 $run{'rtsp-ipv6'}="$pid $pid2"; 2553 } 2554 } 2555 elsif($what =~ /^(ftp|imap|pop3|smtp)s$/) { 2556 my $cproto = $1; 2557 if(!$stunnel) { 2558 # we can't run ftps tests without stunnel 2559 return ("no stunnel", 4); 2560 } 2561 if($runcert{$what} && ($runcert{$what} ne $certfile)) { 2562 # stop server when running and using a different cert 2563 if(stopserver($what)) { 2564 return ("failed stopping $what server with different cert", 3); 2565 } 2566 } 2567 if($run{$cproto} && 2568 !responsive_pingpong_server($cproto, "", $verbose)) { 2569 if(stopserver($cproto)) { 2570 return ("failed stopping unresponsive $cproto server", 3); 2571 } 2572 } 2573 if(!$run{$cproto}) { 2574 ($serr, $pid, $pid2) = runpingpongserver($cproto, "", $verbose); 2575 if($pid <= 0) { 2576 return ("failed starting $cproto server", $serr); 2577 } 2578 logmsg sprintf("* pid $cproto => %d %d\n", $pid, $pid2) if($verbose); 2579 $run{$cproto}="$pid $pid2"; 2580 } 2581 if(!$run{$what}) { 2582 ($serr, $pid, $pid2, $PORT{$what}) = 2583 runsecureserver($verbose, "", $certfile, $what, 2584 protoport($cproto)); 2585 if($pid <= 0) { 2586 return ("failed starting $what server (stunnel)", $serr); 2587 } 2588 logmsg sprintf("* pid $what => %d %d\n", $pid, $pid2) 2589 if($verbose); 2590 $run{$what}="$pid $pid2"; 2591 } 2592 } 2593 elsif($what eq "file") { 2594 # we support it but have no server! 2595 } 2596 elsif($what eq "https") { 2597 if(!$stunnel) { 2598 # we can't run https tests without stunnel 2599 return ("no stunnel", 4); 2600 } 2601 if($runcert{'https'} && ($runcert{'https'} ne $certfile)) { 2602 # stop server when running and using a different cert 2603 if(stopserver('https')) { 2604 return ("failed stopping HTTPS server with different cert", 3); 2605 } 2606 # also stop http server, we do not know which state it is in 2607 if($run{'http'} && stopserver('http')) { 2608 return ("failed stopping HTTP server", 3); 2609 } 2610 } 2611 if($run{'https'} && 2612 !responsive_http_server("https", $verbose, 0, 2613 protoport('https'))) { 2614 if(stopserver('https')) { 2615 return ("failed stopping unresponsive HTTPS server", 3); 2616 } 2617 # also stop http server, we do not know which state it is in 2618 if($run{'http'} && stopserver('http')) { 2619 return ("failed stopping unresponsive HTTP server", 3); 2620 } 2621 } 2622 # check a running http server if we not already checked https 2623 if($run{'http'} && !$run{'https'} && 2624 !responsive_http_server("http", $verbose, 0, 2625 protoport('http'))) { 2626 if(stopserver('http')) { 2627 return ("failed stopping unresponsive HTTP server", 3); 2628 } 2629 } 2630 if(!$run{'http'}) { 2631 ($serr, $pid, $pid2, $PORT{'http'}) = 2632 runhttpserver("http", $verbose, 0); 2633 if($pid <= 0) { 2634 return ("failed starting HTTP server", $serr); 2635 } 2636 logmsg sprintf("* pid http => %d %d\n", $pid, $pid2) if($verbose); 2637 $run{'http'}="$pid $pid2"; 2638 } 2639 if(!$run{'https'}) { 2640 ($serr, $pid, $pid2, $PORT{'https'}) = 2641 runhttpsserver($verbose, "https", "", $certfile); 2642 if($pid <= 0) { 2643 return ("failed starting HTTPS server (stunnel)", $serr); 2644 } 2645 logmsg sprintf("* pid https => %d %d\n", $pid, $pid2) 2646 if($verbose); 2647 $run{'https'}="$pid $pid2"; 2648 } 2649 } 2650 elsif($what eq "http/2") { 2651 # http/2 server proxies to a http server 2652 if($run{'http/2'} && 2653 !responsive_http_server("https", $verbose, 0, protoport('http2tls'))) { 2654 logmsg "* restarting unresponsive HTTP/2 server\n"; 2655 if(stopserver('http/2')) { 2656 return ("failed stopping unresponsive HTTP/2 server", 3); 2657 } 2658 # also stop http server, we do not know which state it is in 2659 if($run{'http'} && stopserver('http')) { 2660 return ("failed stopping HTTP server", 3); 2661 } 2662 } 2663 # check a running http server if we not already checked http/2 2664 if($run{'http'} && !$run{'http/2'} && 2665 !responsive_http_server("http", $verbose, 0, 2666 protoport('http'))) { 2667 if(stopserver('http')) { 2668 return ("failed stopping unresponsive HTTP server", 3); 2669 } 2670 } 2671 if(!$run{'http'}) { 2672 ($serr, $pid, $pid2, $PORT{'http'}) = 2673 runhttpserver("http", $verbose, 0); 2674 if($pid <= 0) { 2675 return ("failed starting HTTP server", $serr); 2676 } 2677 logmsg sprintf("* pid http => %d %d\n", $pid, $pid2) if($verbose); 2678 $run{'http'}="$pid $pid2"; 2679 } 2680 if(!$run{'http/2'}) { 2681 ($serr, $pid, $pid2, $PORT{"http2"}, $PORT{"http2tls"}) = 2682 runhttp2server($verbose); 2683 if($pid <= 0) { 2684 return ("failed starting HTTP/2 server", $serr); 2685 } 2686 logmsg sprintf ("* pid http/2 => %d %d\n", $pid, $pid2) 2687 if($verbose); 2688 $run{'http/2'}="$pid $pid2"; 2689 } 2690 } 2691 elsif($what eq "http/3") { 2692 # http/3 server proxies to a http server 2693 if($run{'http/3'} && 2694 !responsive_http_server("https", $verbose, 0, protoport('http3'), 1)) { 2695 logmsg "* restarting unresponsive HTTP/3 server\n"; 2696 if(stopserver('http/3')) { 2697 return ("failed stopping unresponsive HTTP/3 server", 3); 2698 } 2699 # also stop http server, we do not know which state it is in 2700 if($run{'http'} && stopserver('http')) { 2701 return ("failed stopping HTTP server", 3); 2702 } 2703 } 2704 # check a running http server if we not already checked http/3 2705 if($run{'http'} && !$run{'http/3'} && 2706 !responsive_http_server("http", $verbose, 0, 2707 protoport('http'))) { 2708 if(stopserver('http')) { 2709 return ("failed stopping unresponsive HTTP server", 3); 2710 } 2711 } 2712 if(!$run{'http'}) { 2713 ($serr, $pid, $pid2, $PORT{'http'}) = 2714 runhttpserver("http", $verbose, 0); 2715 if($pid <= 0) { 2716 return ("failed starting HTTP server", $serr); 2717 } 2718 logmsg sprintf("* pid http => %d %d\n", $pid, $pid2) if($verbose); 2719 $run{'http'}="$pid $pid2"; 2720 } 2721 if(!$run{'http/3'}) { 2722 ($serr, $pid, $pid2, $PORT{"http3"}) = runhttp3server($verbose); 2723 if($pid <= 0) { 2724 return ("failed starting HTTP/3 server", $serr); 2725 } 2726 logmsg sprintf ("* pid http/3 => %d %d\n", $pid, $pid2) 2727 if($verbose); 2728 $run{'http/3'}="$pid $pid2"; 2729 } 2730 } 2731 elsif($what eq "gophers") { 2732 if(!$stunnel) { 2733 # we can't run TLS tests without stunnel 2734 return ("no stunnel", 4); 2735 } 2736 if($runcert{'gophers'} && ($runcert{'gophers'} ne $certfile)) { 2737 # stop server when running and using a different cert 2738 if(stopserver('gophers')) { 2739 return ("failed stopping GOPHERS server with different cert", 3); 2740 } 2741 } 2742 if($run{'gopher'} && 2743 !responsive_http_server("gopher", $verbose, 0, 2744 protoport('gopher'))) { 2745 if(stopserver('gopher')) { 2746 return ("failed stopping unresponsive GOPHER server", 3); 2747 } 2748 } 2749 if(!$run{'gopher'}) { 2750 my $port; 2751 ($serr, $pid, $pid2, $port) = 2752 runhttpserver("gopher", $verbose, 0); 2753 $PORT{'gopher'} = $port; 2754 if($pid <= 0) { 2755 return ("failed starting GOPHER server", $serr); 2756 } 2757 logmsg sprintf("* pid gopher => %d %d\n", $pid, $pid2) if($verbose); 2758 logmsg "GOPHERPORT => $port\n" if($verbose); 2759 $run{'gopher'}="$pid $pid2"; 2760 } 2761 if(!$run{'gophers'}) { 2762 my $port; 2763 ($serr, $pid, $pid2, $port) = 2764 runhttpsserver($verbose, "gophers", "", $certfile); 2765 $PORT{'gophers'} = $port; 2766 if($pid <= 0) { 2767 return ("failed starting GOPHERS server (stunnel)", $serr); 2768 } 2769 logmsg sprintf("* pid gophers => %d %d\n", $pid, $pid2) 2770 if($verbose); 2771 logmsg "GOPHERSPORT => $port\n" if($verbose); 2772 $run{'gophers'}="$pid $pid2"; 2773 } 2774 } 2775 elsif($what eq "https-proxy") { 2776 if(!$stunnel) { 2777 # we can't run https-proxy tests without stunnel 2778 return ("no stunnel", 4); 2779 } 2780 if($runcert{'https-proxy'} && 2781 ($runcert{'https-proxy'} ne $certfile)) { 2782 # stop server when running and using a different cert 2783 if(stopserver('https-proxy')) { 2784 return ("failed stopping HTTPS-proxy with different cert", 3); 2785 } 2786 } 2787 2788 # we front the http-proxy with stunnel so we need to make sure the 2789 # proxy runs as well 2790 my ($f, $e) = startservers("http-proxy"); 2791 if($f) { 2792 return ($f, $e); 2793 } 2794 2795 if(!$run{'https-proxy'}) { 2796 ($serr, $pid, $pid2, $PORT{"httpsproxy"}) = 2797 runhttpsserver($verbose, "https", "proxy", $certfile); 2798 if($pid <= 0) { 2799 return ("failed starting HTTPS-proxy (stunnel)", $serr); 2800 } 2801 logmsg sprintf("* pid https-proxy => %d %d\n", $pid, $pid2) 2802 if($verbose); 2803 $run{'https-proxy'}="$pid $pid2"; 2804 } 2805 } 2806 elsif($what eq "httptls") { 2807 if(!$httptlssrv) { 2808 # for now, we can't run http TLS-EXT tests without gnutls-serv 2809 return ("no gnutls-serv (with SRP support)", 4); 2810 } 2811 if($run{'httptls'} && 2812 !responsive_httptls_server($verbose, "IPv4")) { 2813 if(stopserver('httptls')) { 2814 return ("failed stopping unresponsive HTTPTLS server", 3); 2815 } 2816 } 2817 if(!$run{'httptls'}) { 2818 ($serr, $pid, $pid2, $PORT{'httptls'}) = 2819 runhttptlsserver($verbose, "IPv4"); 2820 if($pid <= 0) { 2821 return ("failed starting HTTPTLS server (gnutls-serv)", $serr); 2822 } 2823 logmsg sprintf("* pid httptls => %d %d\n", $pid, $pid2) 2824 if($verbose); 2825 $run{'httptls'}="$pid $pid2"; 2826 } 2827 } 2828 elsif($what eq "httptls-ipv6") { 2829 if(!$httptlssrv) { 2830 # for now, we can't run http TLS-EXT tests without gnutls-serv 2831 return ("no gnutls-serv", 4); 2832 } 2833 if($run{'httptls-ipv6'} && 2834 !responsive_httptls_server($verbose, "ipv6")) { 2835 if(stopserver('httptls-ipv6')) { 2836 return ("failed stopping unresponsive HTTPTLS-IPv6 server", 3); 2837 } 2838 } 2839 if(!$run{'httptls-ipv6'}) { 2840 ($serr, $pid, $pid2, $PORT{"httptls6"}) = 2841 runhttptlsserver($verbose, "ipv6"); 2842 if($pid <= 0) { 2843 return ("failed starting HTTPTLS-IPv6 server (gnutls-serv)", $serr); 2844 } 2845 logmsg sprintf("* pid httptls-ipv6 => %d %d\n", $pid, $pid2) 2846 if($verbose); 2847 $run{'httptls-ipv6'}="$pid $pid2"; 2848 } 2849 } 2850 elsif($what eq "tftp") { 2851 if($run{'tftp'} && 2852 !responsive_tftp_server("", $verbose)) { 2853 if(stopserver('tftp')) { 2854 return ("failed stopping unresponsive TFTP server", 3); 2855 } 2856 } 2857 if(!$run{'tftp'}) { 2858 ($serr, $pid, $pid2, $PORT{'tftp'}) = 2859 runtftpserver("", $verbose); 2860 if($pid <= 0) { 2861 return ("failed starting TFTP server", $serr); 2862 } 2863 logmsg sprintf("* pid tftp => %d %d\n", $pid, $pid2) if($verbose); 2864 $run{'tftp'}="$pid $pid2"; 2865 } 2866 } 2867 elsif($what eq "tftp-ipv6") { 2868 if($run{'tftp-ipv6'} && 2869 !responsive_tftp_server("", $verbose, "ipv6")) { 2870 if(stopserver('tftp-ipv6')) { 2871 return ("failed stopping unresponsive TFTP-IPv6 server", 3); 2872 } 2873 } 2874 if(!$run{'tftp-ipv6'}) { 2875 ($serr, $pid, $pid2, $PORT{'tftp6'}) = 2876 runtftpserver("", $verbose, "ipv6"); 2877 if($pid <= 0) { 2878 return ("failed starting TFTP-IPv6 server", $serr); 2879 } 2880 logmsg sprintf("* pid tftp-ipv6 => %d %d\n", $pid, $pid2) if($verbose); 2881 $run{'tftp-ipv6'}="$pid $pid2"; 2882 } 2883 } 2884 elsif($what eq "sftp" || $what eq "scp") { 2885 if(!$run{'ssh'}) { 2886 ($serr, $pid, $pid2, $PORT{'ssh'}) = runsshserver("", $verbose); 2887 if($pid <= 0) { 2888 return ("failed starting SSH server", $serr); 2889 } 2890 logmsg sprintf("* pid ssh => %d %d\n", $pid, $pid2) if($verbose); 2891 $run{'ssh'}="$pid $pid2"; 2892 } 2893 } 2894 elsif($what eq "socks4" || $what eq "socks5" ) { 2895 if(!$run{'socks'}) { 2896 ($serr, $pid, $pid2, $PORT{"socks"}) = runsocksserver("", $verbose); 2897 if($pid <= 0) { 2898 return ("failed starting socks server", $serr); 2899 } 2900 logmsg sprintf("* pid socks => %d %d\n", $pid, $pid2) if($verbose); 2901 $run{'socks'}="$pid $pid2"; 2902 } 2903 } 2904 elsif($what eq "socks5unix") { 2905 if(!$run{'socks5unix'}) { 2906 ($serr, $pid, $pid2) = runsocksserver("2", $verbose, "", "unix"); 2907 if($pid <= 0) { 2908 return ("failed starting socks5unix server", $serr); 2909 } 2910 logmsg sprintf("* pid socks5unix => %d %d\n", $pid, $pid2) if($verbose); 2911 $run{'socks5unix'}="$pid $pid2"; 2912 } 2913 } 2914 elsif($what eq "mqtt" ) { 2915 if($run{'mqtt'} && 2916 !responsive_mqtt_server("mqtt", "", $verbose)) { 2917 if(stopserver('mqtt')) { 2918 return ("failed stopping unresponsive MQTT server", 3); 2919 } 2920 } 2921 if(!$run{'mqtt'}) { 2922 ($serr, $pid, $pid2, $PORT{"mqtt"}) = runmqttserver("", $verbose); 2923 if($pid <= 0) { 2924 return ("failed starting mqtt server", $serr); 2925 } 2926 logmsg sprintf("* pid mqtt => %d %d\n", $pid, $pid2) if($verbose); 2927 $run{'mqtt'}="$pid $pid2"; 2928 } 2929 } 2930 elsif($what eq "http-unix") { 2931 if($run{'http-unix'} && 2932 !responsive_http_server("http", $verbose, "unix", $HTTPUNIXPATH)) { 2933 if(stopserver('http-unix')) { 2934 return ("failed stopping unresponsive HTTP-unix server", 3); 2935 } 2936 } 2937 if(!$run{'http-unix'}) { 2938 my $unused; 2939 ($serr, $pid, $pid2, $unused) = 2940 runhttpserver("http", $verbose, "unix", $HTTPUNIXPATH); 2941 if($pid <= 0) { 2942 return ("failed starting HTTP-unix server", $serr); 2943 } 2944 logmsg sprintf("* pid http-unix => %d %d\n", $pid, $pid2) 2945 if($verbose); 2946 $run{'http-unix'}="$pid $pid2"; 2947 } 2948 } 2949 elsif($what eq "dict") { 2950 if(!$run{'dict'}) { 2951 ($serr, $pid, $pid2, $PORT{"dict"}) = rundictserver($verbose, ""); 2952 if($pid <= 0) { 2953 return ("failed starting DICT server", $serr); 2954 } 2955 logmsg sprintf ("* pid DICT => %d %d\n", $pid, $pid2) 2956 if($verbose); 2957 $run{'dict'}="$pid $pid2"; 2958 } 2959 } 2960 elsif($what eq "smb") { 2961 if(!$run{'smb'}) { 2962 ($serr, $pid, $pid2, $PORT{"smb"}) = runsmbserver($verbose, ""); 2963 if($pid <= 0) { 2964 return ("failed starting SMB server", $serr); 2965 } 2966 logmsg sprintf ("* pid SMB => %d %d\n", $pid, $pid2) 2967 if($verbose); 2968 $run{'smb'}="$pid $pid2"; 2969 } 2970 } 2971 elsif($what eq "telnet") { 2972 if(!$run{'telnet'}) { 2973 ($serr, $pid, $pid2, $PORT{"telnet"}) = 2974 runnegtelnetserver($verbose, ""); 2975 if($pid <= 0) { 2976 return ("failed starting neg TELNET server", $serr); 2977 } 2978 logmsg sprintf ("* pid neg TELNET => %d %d\n", $pid, $pid2) 2979 if($verbose); 2980 $run{'telnet'}="$pid $pid2"; 2981 } 2982 } 2983 elsif($what eq "none") { 2984 logmsg "* starts no server\n" if ($verbose); 2985 } 2986 else { 2987 warn "we don't support a server for $what"; 2988 return ("no server for $what", 4); 2989 } 2990 } 2991 return ("", 0); 2992} 2993 2994####################################################################### 2995# Stop all running test servers 2996# 2997sub stopservers { 2998 my $verb = $_[0]; 2999 # 3000 # kill sockfilter processes for all pingpong servers 3001 # 3002 killallsockfilters("$LOGDIR/$PIDDIR", $verb); 3003 # 3004 # kill all server pids from %run hash clearing them 3005 # 3006 my $pidlist; 3007 foreach my $server (keys %run) { 3008 if($run{$server}) { 3009 if($verb) { 3010 my $prev = 0; 3011 my $pids = $run{$server}; 3012 foreach my $pid (split(' ', $pids)) { 3013 if($pid != $prev) { 3014 logmsg sprintf("* kill pid for %s => %d\n", 3015 $server, $pid); 3016 $prev = $pid; 3017 } 3018 } 3019 } 3020 $pidlist .= "$run{$server} "; 3021 $run{$server} = 0; 3022 } 3023 $runcert{$server} = 0 if($runcert{$server}); 3024 } 3025 killpid($verb, $pidlist); 3026 # 3027 # cleanup all server pid files 3028 # 3029 my $result = 0; 3030 foreach my $server (keys %serverpidfile) { 3031 my $pidfile = $serverpidfile{$server}; 3032 my $pid = processexists($pidfile); 3033 if($pid > 0) { 3034 if($err_unexpected) { 3035 logmsg "ERROR: "; 3036 $result = -1; 3037 } 3038 else { 3039 logmsg "Warning: "; 3040 } 3041 logmsg "$server server unexpectedly alive\n"; 3042 killpid($verb, $pid); 3043 } 3044 unlink($pidfile) if(-f $pidfile); 3045 } 3046 3047 return $result; 3048} 3049 3050 3051####################################################################### 3052# substitute the variable stuff into either a joined up file or 3053# a command, in either case passed by reference 3054# 3055sub subvariables { 3056 my ($thing, $testnum, $prefix) = @_; 3057 my $port; 3058 3059 if(!$prefix) { 3060 $prefix = "%"; 3061 } 3062 3063 # test server ports 3064 # Substitutes variables like %HTTPPORT and %SMTP6PORT with the server ports 3065 foreach my $proto ('DICT', 3066 'FTP', 'FTP6', 'FTPS', 3067 'GOPHER', 'GOPHER6', 'GOPHERS', 3068 'HTTP', 'HTTP6', 'HTTPS', 3069 'HTTPSPROXY', 'HTTPTLS', 'HTTPTLS6', 3070 'HTTP2', 'HTTP2TLS', 3071 'HTTP3', 3072 'IMAP', 'IMAP6', 'IMAPS', 3073 'MQTT', 3074 'NOLISTEN', 3075 'POP3', 'POP36', 'POP3S', 3076 'RTSP', 'RTSP6', 3077 'SMB', 'SMBS', 3078 'SMTP', 'SMTP6', 'SMTPS', 3079 'SOCKS', 3080 'SSH', 3081 'TELNET', 3082 'TFTP', 'TFTP6') { 3083 $port = protoport(lc $proto); 3084 $$thing =~ s/${prefix}(?:$proto)PORT/$port/g; 3085 } 3086 # Special case: for PROXYPORT substitution, use httpproxy. 3087 $port = protoport('httpproxy'); 3088 $$thing =~ s/${prefix}PROXYPORT/$port/g; 3089 3090 # server Unix domain socket paths 3091 $$thing =~ s/${prefix}HTTPUNIXPATH/$HTTPUNIXPATH/g; 3092 $$thing =~ s/${prefix}SOCKSUNIXPATH/$SOCKSUNIXPATH/g; 3093 3094 # client IP addresses 3095 my $nb = $CLIENT6IP; 3096 $nb =~ s/^\[(.*)\]/$1/; # trim off the brackets 3097 3098 $$thing =~ s/${prefix}CLIENT6IP-NB/$nb/g; 3099 $$thing =~ s/${prefix}CLIENT6IP/$CLIENT6IP/g; 3100 $$thing =~ s/${prefix}CLIENTIP/$CLIENTIP/g; 3101 3102 # server IP addresses 3103 $$thing =~ s/${prefix}HOST6IP/$HOST6IP/g; 3104 $$thing =~ s/${prefix}HOSTIP/$HOSTIP/g; 3105 3106 # misc 3107 $$thing =~ s/${prefix}PERL/$perlcmd/g; 3108 $$thing =~ s/${prefix}CURL/$CURL/g; 3109 $$thing =~ s/${prefix}LOGDIR/$LOGDIR/g; 3110 $$thing =~ s/${prefix}PWD/$pwd/g; 3111 $$thing =~ s/${prefix}POSIX_PWD/$posix_pwd/g; 3112 $$thing =~ s/${prefix}VERSION/$CURLVERSION/g; 3113 $$thing =~ s/${prefix}VERNUM/$CURLVERNUM/g; 3114 $$thing =~ s/${prefix}DATE/$DATE/g; 3115 $$thing =~ s/${prefix}TESTNUMBER/$testnum/g; 3116 3117 # POSIX/MSYS/Cygwin curl needs: file://localhost/d/path/to 3118 # Windows native curl needs: file://localhost/D:/path/to 3119 my $file_pwd = $pwd; 3120 if($file_pwd !~ /^\//) { 3121 $file_pwd = "/$file_pwd"; 3122 } 3123 my $ssh_pwd = $posix_pwd; 3124 # this only works after the SSH server has been started 3125 # TODO: call sshversioninfo early and store $sshdid so this substitution 3126 # always works 3127 if ($sshdid && $sshdid =~ /OpenSSH-Windows/) { 3128 $ssh_pwd = $file_pwd; 3129 } 3130 3131 $$thing =~ s/${prefix}FILE_PWD/$file_pwd/g; 3132 $$thing =~ s/${prefix}SSH_PWD/$ssh_pwd/g; 3133 $$thing =~ s/${prefix}SRCDIR/$srcdir/g; 3134 $$thing =~ s/${prefix}USER/$USER/g; 3135 $$thing =~ s/${prefix}DEV_NULL/$dev_null/g; 3136 3137 $$thing =~ s/${prefix}SSHSRVMD5/$SSHSRVMD5/g; 3138 $$thing =~ s/${prefix}SSHSRVSHA256/$SSHSRVSHA256/g; 3139 3140 # The purpose of FTPTIME2 is to provide times that can be 3141 # used for time-out tests and that would work on most hosts as these 3142 # adjust for the startup/check time for this particular host. We needed to 3143 # do this to make the test suite run better on very slow hosts. 3144 my $ftp2 = $ftpchecktime * 8; 3145 3146 $$thing =~ s/${prefix}FTPTIME2/$ftp2/g; 3147 3148 # HTTP2 3149 $$thing =~ s/${prefix}H2CVER/$h2cver/g; 3150} 3151 3152sub localhttp { 3153 return $HOSTIP eq "127.0.0.1"; 3154} 3155 31561; 3157