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