Proxy.pm 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863
  1. # Copyright 2016-2025 The OpenSSL Project Authors. All Rights Reserved.
  2. #
  3. # Licensed under the Apache License 2.0 (the "License"). You may not use
  4. # this file except in compliance with the License. You can obtain a copy
  5. # in the file LICENSE in the source distribution or at
  6. # https://www.openssl.org/source/license.html
  7. use strict;
  8. use POSIX ":sys_wait_h";
  9. package TLSProxy::Proxy;
  10. use File::Spec;
  11. use IO::Socket;
  12. use IO::Select;
  13. use TLSProxy::Record;
  14. use TLSProxy::Message;
  15. use TLSProxy::ClientHello;
  16. use TLSProxy::ServerHello;
  17. use TLSProxy::HelloVerifyRequest;
  18. use TLSProxy::EncryptedExtensions;
  19. use TLSProxy::Certificate;
  20. use TLSProxy::CertificateRequest;
  21. use TLSProxy::CertificateVerify;
  22. use TLSProxy::ServerKeyExchange;
  23. use TLSProxy::NewSessionTicket;
  24. use TLSProxy::NextProto;
  25. my $have_IPv6;
  26. my $useINET6;
  27. my $IP_factory;
  28. BEGIN
  29. {
  30. # IO::Socket::IP is on the core module list, IO::Socket::INET6 isn't.
  31. # However, IO::Socket::INET6 is older and is said to be more widely
  32. # deployed for the moment, and may have less bugs, so we try the latter
  33. # first, then fall back on the core modules. Worst case scenario, we
  34. # fall back to IO::Socket::INET, only supports IPv4.
  35. eval {
  36. require IO::Socket::INET6;
  37. my $s = IO::Socket::INET6->new(
  38. LocalAddr => "::1",
  39. LocalPort => 0,
  40. Listen=>1,
  41. );
  42. $s or die "\n";
  43. $s->close();
  44. };
  45. if ($@ eq "") {
  46. $IP_factory = sub { IO::Socket::INET6->new(Domain => AF_INET6, @_); };
  47. $have_IPv6 = 1;
  48. $useINET6 = 1;
  49. } else {
  50. eval {
  51. require IO::Socket::IP;
  52. my $s = IO::Socket::IP->new(
  53. LocalAddr => "::1",
  54. LocalPort => 0,
  55. Listen=>1,
  56. );
  57. $s or die "\n";
  58. $s->close();
  59. };
  60. if ($@ eq "") {
  61. $IP_factory = sub { IO::Socket::IP->new(@_); };
  62. $have_IPv6 = 1;
  63. $useINET6 = 0;
  64. } else {
  65. $IP_factory = sub { IO::Socket::INET->new(@_); };
  66. $have_IPv6 = 0;
  67. $useINET6 = 0;
  68. }
  69. }
  70. }
  71. my $is_tls13 = 0;
  72. my $ciphersuite = undef;
  73. sub new {
  74. my $class = shift;
  75. my ($filter,
  76. $execute,
  77. $cert,
  78. $debug) = @_;
  79. return init($class, $filter, $execute, $cert, $debug, 0);
  80. }
  81. sub new_dtls {
  82. my $class = shift;
  83. my ($filter,
  84. $execute,
  85. $cert,
  86. $debug) = @_;
  87. return init($class, $filter, $execute, $cert, $debug, 1);
  88. }
  89. sub init
  90. {
  91. my $useSockInet = 0;
  92. eval {
  93. require IO::Socket::IP;
  94. my $s = IO::Socket::IP->new(
  95. LocalAddr => "::1",
  96. LocalPort => 0,
  97. Listen=>1,
  98. );
  99. $s or die "\n";
  100. $s->close();
  101. };
  102. if ($@ eq "") {
  103. require IO::Socket::IP;
  104. } else {
  105. $useSockInet = 1;
  106. }
  107. my $class = shift;
  108. my ($filter,
  109. $execute,
  110. $cert,
  111. $debug,
  112. $isdtls) = @_;
  113. my $test_client_port;
  114. # Sometimes, our random selection of client ports gets unlucky
  115. # And we randomly select a port thats already in use. This causes
  116. # this test to fail, so lets harden ourselves against that by doing
  117. # a test bind to the randomly selected port, and only continue once we
  118. # find a port thats available.
  119. my $test_client_addr = $have_IPv6 ? "[::1]" : "127.0.0.1";
  120. my $found_port = 0;
  121. for (my $i = 0; $i <= 10; $i++) {
  122. $test_client_port = 49152 + int(rand(65535 - 49152));
  123. my $test_sock;
  124. if ($useINET6 == 0) {
  125. if ($useSockInet == 0) {
  126. $test_sock = IO::Socket::IP->new(LocalPort => $test_client_port,
  127. LocalAddr => $test_client_addr);
  128. } else {
  129. $test_sock = IO::Socket::INET->new(LocalAddr => $test_client_addr,
  130. LocalPort => $test_client_port);
  131. }
  132. } else {
  133. $test_sock = IO::Socket::INET6->new(LocalAddr => $test_client_addr,
  134. LocalPort => $test_client_port,
  135. Domain => AF_INET6);
  136. }
  137. if ($test_sock) {
  138. $found_port = 1;
  139. $test_sock->close();
  140. print "Found available client port ${test_client_port}\n";
  141. last;
  142. }
  143. print "Port ${test_client_port} in use - $@\n";
  144. }
  145. if ($found_port == 0) {
  146. die "Unable to find usable port for TLSProxy";
  147. }
  148. my $self = {
  149. #Public read/write
  150. proxy_addr => $test_client_addr,
  151. client_addr => $test_client_addr,
  152. filter => $filter,
  153. serverflags => "",
  154. clientflags => "",
  155. serverconnects => 1,
  156. reneg => 0,
  157. sessionfile => undef,
  158. #Public read
  159. isdtls => $isdtls,
  160. proxy_port => 0,
  161. client_port => $test_client_port,
  162. server_port => 0,
  163. serverpid => 0,
  164. clientpid => 0,
  165. execute => $execute,
  166. cert => $cert,
  167. debug => $debug,
  168. cipherc => "",
  169. ciphersuitesc => "",
  170. ciphers => "AES128-SHA",
  171. ciphersuitess => "TLS_AES_128_GCM_SHA256",
  172. flight => -1,
  173. direction => -1,
  174. partial => ["", ""],
  175. record_list => [],
  176. message_list => [],
  177. };
  178. return bless $self, $class;
  179. }
  180. sub DESTROY
  181. {
  182. my $self = shift;
  183. $self->{proxy_sock}->close() if $self->{proxy_sock};
  184. }
  185. sub clearClient
  186. {
  187. my $self = shift;
  188. $self->{cipherc} = "";
  189. $self->{ciphersuitec} = "";
  190. $self->{flight} = -1;
  191. $self->{direction} = -1;
  192. $self->{partial} = ["", ""];
  193. $self->{record_list} = [];
  194. $self->{message_list} = [];
  195. $self->{clientflags} = "";
  196. $self->{sessionfile} = undef;
  197. $self->{clientpid} = 0;
  198. $is_tls13 = 0;
  199. $ciphersuite = undef;
  200. TLSProxy::Message->clear();
  201. TLSProxy::Record->clear();
  202. }
  203. sub clear
  204. {
  205. my $self = shift;
  206. $self->clearClient;
  207. $self->{ciphers} = "AES128-SHA";
  208. $self->{ciphersuitess} = "TLS_AES_128_GCM_SHA256";
  209. $self->{serverflags} = "";
  210. $self->{serverconnects} = 1;
  211. $self->{serverpid} = 0;
  212. $self->{reneg} = 0;
  213. }
  214. sub restart
  215. {
  216. my $self = shift;
  217. $self->clear;
  218. $self->start;
  219. }
  220. sub clientrestart
  221. {
  222. my $self = shift;
  223. $self->clear;
  224. $self->clientstart;
  225. }
  226. sub connect_to_server
  227. {
  228. my $self = shift;
  229. my $servaddr = $self->{server_addr};
  230. $servaddr =~ s/[\[\]]//g; # Remove [ and ]
  231. my $sock = $IP_factory->(PeerAddr => $servaddr,
  232. PeerPort => $self->{server_port},
  233. Proto => $self->{isdtls} ? 'udp' : 'tcp');
  234. if (!defined($sock)) {
  235. my $err = $!;
  236. kill(3, $self->{real_serverpid});
  237. die "unable to connect: $err\n";
  238. }
  239. $self->{server_sock} = $sock;
  240. }
  241. sub start
  242. {
  243. my ($self) = shift;
  244. my $pid;
  245. # Create the Proxy socket
  246. my $proxaddr = $self->{proxy_addr};
  247. $proxaddr =~ s/[\[\]]//g; # Remove [ and ]
  248. my $clientaddr = $self->{client_addr};
  249. $clientaddr =~ s/[\[\]]//g; # Remove [ and ]
  250. my @proxyargs;
  251. if ($self->{isdtls}) {
  252. @proxyargs = (
  253. LocalHost => $proxaddr,
  254. LocalPort => 0,
  255. PeerHost => $clientaddr,
  256. PeerPort => $self->{client_port},
  257. Proto => "udp",
  258. );
  259. } else {
  260. @proxyargs = (
  261. LocalHost => $proxaddr,
  262. LocalPort => 0,
  263. Proto => "tcp",
  264. Listen => SOMAXCONN,
  265. );
  266. }
  267. if (my $sock = $IP_factory->(@proxyargs)) {
  268. $self->{proxy_sock} = $sock;
  269. $self->{proxy_port} = $sock->sockport();
  270. $self->{proxy_addr} = $sock->sockhost();
  271. $self->{proxy_addr} =~ s/(.*:.*)/[$1]/;
  272. print "Proxy started on port ",
  273. "$self->{proxy_addr}:$self->{proxy_port}\n";
  274. # use same address for s_server
  275. $self->{server_addr} = $self->{proxy_addr};
  276. } else {
  277. warn "Failed creating proxy socket (".$proxaddr.",0): $!\n";
  278. }
  279. if ($self->{proxy_sock} == 0) {
  280. return 0;
  281. }
  282. my $execcmd = $self->execute
  283. ." s_server -no_comp -engine ossltest -state"
  284. #In TLSv1.3 we issue two session tickets. The default session id
  285. #callback gets confused because the ossltest engine causes the same
  286. #session id to be created twice due to the changed random number
  287. #generation. Using "-ext_cache" replaces the default callback with a
  288. #different one that doesn't get confused.
  289. ." -ext_cache"
  290. ." -accept $self->{server_addr}:0"
  291. ." -cert ".$self->cert." -cert2 ".$self->cert
  292. ." -naccept ".$self->serverconnects;
  293. if ($self->{isdtls}) {
  294. $execcmd .= " -dtls -max_protocol DTLSv1.2"
  295. # TLSProxy does not support message fragmentation. So
  296. # set a high mtu and fingers crossed.
  297. ." -mtu 1500";
  298. } else {
  299. $execcmd .= " -rev -max_protocol TLSv1.3";
  300. }
  301. if ($self->ciphers ne "") {
  302. $execcmd .= " -cipher ".$self->ciphers;
  303. }
  304. if ($self->ciphersuitess ne "") {
  305. $execcmd .= " -ciphersuites ".$self->ciphersuitess;
  306. }
  307. if ($self->serverflags ne "") {
  308. $execcmd .= " ".$self->serverflags;
  309. }
  310. if ($self->debug) {
  311. print STDERR "Server command: $execcmd\n";
  312. }
  313. open(my $savedin, "<&STDIN");
  314. # Temporarily replace STDIN so that sink process can inherit it...
  315. open(STDIN, "$^X -e 'sleep(10)' |") if $self->{isdtls};
  316. $pid = open(STDIN, "$execcmd 2>&1 |") or die "Failed to $execcmd: $!\n";
  317. $self->{real_serverpid} = $pid;
  318. # Process the output from s_server until we find the ACCEPT line, which
  319. # tells us what the accepting address and port are.
  320. while (<>) {
  321. print;
  322. s/\R$//; # Better chomp
  323. next unless (/^ACCEPT\s.*:(\d+)$/);
  324. $self->{server_port} = $1;
  325. last;
  326. }
  327. if ($self->{server_port} == 0) {
  328. # This actually means that s_server exited, because otherwise
  329. # we would still searching for ACCEPT...
  330. waitpid($pid, 0);
  331. die "no ACCEPT detected in '$execcmd' output: $?\n";
  332. }
  333. # Just make sure everything else is simply printed [as separate lines].
  334. # The sub process simply inherits our STD* and will keep consuming
  335. # server's output and printing it as long as there is anything there,
  336. # out of our way.
  337. my $error;
  338. $pid = undef;
  339. if (eval { require Win32::Process; 1; }) {
  340. if (Win32::Process::Create(my $h, $^X, "perl -ne print", 0, 0, ".")) {
  341. $pid = $h->GetProcessID();
  342. $self->{proc_handle} = $h; # hold handle till next round [or exit]
  343. } else {
  344. $error = Win32::FormatMessage(Win32::GetLastError());
  345. }
  346. } else {
  347. if (defined($pid = fork)) {
  348. $pid or exec("$^X -ne print") or exit($!);
  349. } else {
  350. $error = $!;
  351. }
  352. }
  353. # Change back to original stdin
  354. open(STDIN, "<&", $savedin);
  355. close($savedin);
  356. if (!defined($pid)) {
  357. kill(3, $self->{real_serverpid});
  358. die "Failed to capture s_server's output: $error\n";
  359. }
  360. $self->{serverpid} = $pid;
  361. print STDERR "Server responds on ",
  362. "$self->{server_addr}:$self->{server_port}\n";
  363. # Connect right away...
  364. $self->connect_to_server();
  365. return $self->clientstart;
  366. }
  367. sub clientstart
  368. {
  369. my ($self) = shift;
  370. my $succes = 1;
  371. if ($self->execute) {
  372. my $pid;
  373. my $execcmd = $self->execute
  374. ." s_client -engine ossltest"
  375. ." -connect $self->{proxy_addr}:$self->{proxy_port}";
  376. if ($self->{isdtls}) {
  377. $execcmd .= " -dtls -max_protocol DTLSv1.2"
  378. # TLSProxy does not support message fragmentation. So
  379. # set a high mtu and fingers crossed.
  380. ." -mtu 1500"
  381. # UDP has no "accept" for sockets which means we need to
  382. # know were to send data back to.
  383. ." -bind $self->{client_addr}:$self->{client_port}";
  384. } else {
  385. $execcmd .= " -max_protocol TLSv1.3";
  386. }
  387. if ($self->cipherc ne "") {
  388. $execcmd .= " -cipher ".$self->cipherc;
  389. }
  390. if ($self->ciphersuitesc ne "") {
  391. $execcmd .= " -ciphersuites ".$self->ciphersuitesc;
  392. }
  393. if ($self->clientflags ne "") {
  394. $execcmd .= " ".$self->clientflags;
  395. }
  396. if ($self->clientflags !~ m/-(no)?servername/) {
  397. $execcmd .= " -servername localhost";
  398. }
  399. if (defined $self->sessionfile) {
  400. $execcmd .= " -ign_eof";
  401. }
  402. if ($self->debug) {
  403. print STDERR "Client command: $execcmd\n";
  404. }
  405. open(my $savedout, ">&STDOUT");
  406. # If we open pipe with new descriptor, attempt to close it,
  407. # explicitly or implicitly, would incur waitpid and effectively
  408. # dead-lock...
  409. if (!($pid = open(STDOUT, "| $execcmd"))) {
  410. my $err = $!;
  411. kill(3, $self->{real_serverpid});
  412. die "Failed to $execcmd: $err\n";
  413. }
  414. $self->{clientpid} = $pid;
  415. # queue [magic] input
  416. print $self->reneg ? "R" : "test";
  417. # this closes client's stdin without waiting for its pid
  418. open(STDOUT, ">&", $savedout);
  419. close($savedout);
  420. }
  421. # Wait for incoming connection from client
  422. my $fdset = IO::Select->new($self->{proxy_sock});
  423. if (!$fdset->can_read(60)) {
  424. kill(3, $self->{real_serverpid});
  425. die "s_client didn't try to connect\n";
  426. }
  427. my $client_sock;
  428. if($self->{isdtls}) {
  429. $client_sock = $self->{proxy_sock}
  430. } elsif (!($client_sock = $self->{proxy_sock}->accept())) {
  431. warn "Failed accepting incoming connection: $!\n";
  432. return 0;
  433. }
  434. print "Connection opened\n";
  435. my $server_sock = $self->{server_sock};
  436. my $indata;
  437. #Wait for either the server socket or the client socket to become readable
  438. $fdset = IO::Select->new($server_sock, $client_sock);
  439. my @ready;
  440. my $ctr = 0;
  441. local $SIG{PIPE} = "IGNORE";
  442. $self->{saw_session_ticket} = undef;
  443. while($fdset->count && $ctr < 10) {
  444. if (defined($self->{sessionfile})) {
  445. # s_client got -ign_eof and won't be exiting voluntarily, so we
  446. # look for data *and* session ticket...
  447. last if TLSProxy::Message->success()
  448. && $self->{saw_session_ticket};
  449. }
  450. if (!(@ready = $fdset->can_read(1))) {
  451. last if TLSProxy::Message->success()
  452. && $self->{saw_session_ticket};
  453. $ctr++;
  454. next;
  455. }
  456. foreach my $hand (@ready) {
  457. if ($hand == $server_sock) {
  458. if ($server_sock->sysread($indata, 16384)) {
  459. if ($indata = $self->process_packet(1, $indata)) {
  460. $client_sock->syswrite($indata) or goto END;
  461. }
  462. $ctr = 0;
  463. } else {
  464. $fdset->remove($server_sock);
  465. $client_sock->shutdown(SHUT_WR);
  466. }
  467. } elsif ($hand == $client_sock) {
  468. if ($client_sock->sysread($indata, 16384)) {
  469. if ($indata = $self->process_packet(0, $indata)) {
  470. $server_sock->syswrite($indata) or goto END;
  471. }
  472. $ctr = 0;
  473. } else {
  474. $fdset->remove($client_sock);
  475. $server_sock->shutdown(SHUT_WR);
  476. }
  477. } else {
  478. kill(3, $self->{real_serverpid});
  479. die "Unexpected handle";
  480. }
  481. }
  482. }
  483. if ($ctr >= 10) {
  484. kill(3, $self->{real_serverpid});
  485. print "No progress made\n";
  486. $succes = 0;
  487. }
  488. END:
  489. print "Connection closed\n";
  490. if($server_sock) {
  491. $server_sock->close();
  492. $self->{server_sock} = undef;
  493. }
  494. if($client_sock) {
  495. #Closing this also kills the child process
  496. $client_sock->close();
  497. }
  498. my $pid;
  499. if (--$self->{serverconnects} == 0) {
  500. $pid = $self->{serverpid};
  501. print "Waiting for 'perl -ne print' process to close: $pid...\n";
  502. $pid = waitpid($pid, 0);
  503. if ($pid > 0) {
  504. die "exit code $? from 'perl -ne print' process\n" if $? != 0;
  505. } elsif ($pid == 0) {
  506. kill(3, $self->{real_serverpid});
  507. die "lost control over $self->{serverpid}?";
  508. }
  509. $pid = $self->{real_serverpid};
  510. print "Waiting for s_server process to close: $pid...\n";
  511. # it's done already, just collect the exit code [and reap]...
  512. waitpid($pid, 0);
  513. die "exit code $? from s_server process\n" if $? != 0;
  514. } else {
  515. # It's a bit counter-intuitive spot to make next connection to
  516. # the s_server. Rationale is that established connection works
  517. # as synchronization point, in sense that this way we know that
  518. # s_server is actually done with current session...
  519. $self->connect_to_server();
  520. }
  521. $pid = $self->{clientpid};
  522. print "Waiting for s_client process to close: $pid...\n";
  523. waitpid($pid, 0);
  524. return $succes;
  525. }
  526. sub process_packet
  527. {
  528. my ($self, $server, $packet) = @_;
  529. my $len_real;
  530. my $decrypt_len;
  531. my $data;
  532. my $recnum;
  533. if ($server) {
  534. print "Received server packet\n";
  535. } else {
  536. print "Received client packet\n";
  537. }
  538. if ($self->{direction} != $server) {
  539. $self->{flight} = $self->{flight} + 1;
  540. $self->{direction} = $server;
  541. }
  542. print "Packet length = ".length($packet)."\n";
  543. print "Processing flight ".$self->flight."\n";
  544. #Return contains the list of record found in the packet followed by the
  545. #list of messages in those records and any partial message
  546. my @ret = TLSProxy::Record->get_records($server, $self->flight,
  547. $self->{partial}[$server].$packet,
  548. $self->{isdtls});
  549. $self->{partial}[$server] = $ret[2];
  550. push @{$self->{record_list}}, @{$ret[0]};
  551. push @{$self->{message_list}}, @{$ret[1]};
  552. print "\n";
  553. if (scalar(@{$ret[0]}) == 0 or length($ret[2]) != 0) {
  554. return "";
  555. }
  556. #Finished parsing. Call user provided filter here
  557. if (defined $self->filter) {
  558. $self->filter->($self);
  559. }
  560. #Take a note on NewSessionTicket
  561. foreach my $message (reverse @{$self->{message_list}}) {
  562. if ($message->{mt} == TLSProxy::Message::MT_NEW_SESSION_TICKET) {
  563. $self->{saw_session_ticket} = 1;
  564. last;
  565. }
  566. }
  567. #Reconstruct the packet
  568. $packet = "";
  569. foreach my $record (@{$self->record_list}) {
  570. $packet .= $record->reconstruct_record($server);
  571. }
  572. print "Forwarded packet length = ".length($packet)."\n\n";
  573. return $packet;
  574. }
  575. #Read accessors
  576. sub execute
  577. {
  578. my $self = shift;
  579. return $self->{execute};
  580. }
  581. sub cert
  582. {
  583. my $self = shift;
  584. return $self->{cert};
  585. }
  586. sub debug
  587. {
  588. my $self = shift;
  589. return $self->{debug};
  590. }
  591. sub flight
  592. {
  593. my $self = shift;
  594. return $self->{flight};
  595. }
  596. sub record_list
  597. {
  598. my $self = shift;
  599. return $self->{record_list};
  600. }
  601. sub success
  602. {
  603. my $self = shift;
  604. return $self->{success};
  605. }
  606. sub end
  607. {
  608. my $self = shift;
  609. return $self->{end};
  610. }
  611. sub supports_IPv6
  612. {
  613. my $self = shift;
  614. return $have_IPv6;
  615. }
  616. sub proxy_addr
  617. {
  618. my $self = shift;
  619. return $self->{proxy_addr};
  620. }
  621. sub proxy_port
  622. {
  623. my $self = shift;
  624. return $self->{proxy_port};
  625. }
  626. sub server_addr
  627. {
  628. my $self = shift;
  629. return $self->{server_addr};
  630. }
  631. sub server_port
  632. {
  633. my $self = shift;
  634. return $self->{server_port};
  635. }
  636. sub serverpid
  637. {
  638. my $self = shift;
  639. return $self->{serverpid};
  640. }
  641. sub clientpid
  642. {
  643. my $self = shift;
  644. return $self->{clientpid};
  645. }
  646. #Read/write accessors
  647. sub filter
  648. {
  649. my $self = shift;
  650. if (@_) {
  651. $self->{filter} = shift;
  652. }
  653. return $self->{filter};
  654. }
  655. sub cipherc
  656. {
  657. my $self = shift;
  658. if (@_) {
  659. $self->{cipherc} = shift;
  660. }
  661. return $self->{cipherc};
  662. }
  663. sub ciphersuitesc
  664. {
  665. my $self = shift;
  666. if (@_) {
  667. $self->{ciphersuitesc} = shift;
  668. }
  669. return $self->{ciphersuitesc};
  670. }
  671. sub ciphers
  672. {
  673. my $self = shift;
  674. if (@_) {
  675. $self->{ciphers} = shift;
  676. }
  677. return $self->{ciphers};
  678. }
  679. sub ciphersuitess
  680. {
  681. my $self = shift;
  682. if (@_) {
  683. $self->{ciphersuitess} = shift;
  684. }
  685. return $self->{ciphersuitess};
  686. }
  687. sub serverflags
  688. {
  689. my $self = shift;
  690. if (@_) {
  691. $self->{serverflags} = shift;
  692. }
  693. return $self->{serverflags};
  694. }
  695. sub clientflags
  696. {
  697. my $self = shift;
  698. if (@_) {
  699. $self->{clientflags} = shift;
  700. }
  701. return $self->{clientflags};
  702. }
  703. sub serverconnects
  704. {
  705. my $self = shift;
  706. if (@_) {
  707. $self->{serverconnects} = shift;
  708. }
  709. return $self->{serverconnects};
  710. }
  711. # This is a bit ugly because the caller is responsible for keeping the records
  712. # in sync with the updated message list; simply updating the message list isn't
  713. # sufficient to get the proxy to forward the new message.
  714. # But it does the trick for the one test (test_sslsessiontick) that needs it.
  715. sub message_list
  716. {
  717. my $self = shift;
  718. if (@_) {
  719. $self->{message_list} = shift;
  720. }
  721. return $self->{message_list};
  722. }
  723. sub fill_known_data
  724. {
  725. my $length = shift;
  726. my $ret = "";
  727. for (my $i = 0; $i < $length; $i++) {
  728. $ret .= chr($i);
  729. }
  730. return $ret;
  731. }
  732. sub is_tls13
  733. {
  734. my $class = shift;
  735. if (@_) {
  736. $is_tls13 = shift;
  737. }
  738. return $is_tls13;
  739. }
  740. sub reneg
  741. {
  742. my $self = shift;
  743. if (@_) {
  744. $self->{reneg} = shift;
  745. }
  746. return $self->{reneg};
  747. }
  748. #Setting a sessionfile means that the client will not close until the given
  749. #file exists. This is useful in TLSv1.3 where otherwise s_client will close
  750. #immediately at the end of the handshake, but before the session has been
  751. #received from the server. A side effect of this is that s_client never sends
  752. #a close_notify, so instead we consider success to be when it sends application
  753. #data over the connection.
  754. sub sessionfile
  755. {
  756. my $self = shift;
  757. if (@_) {
  758. $self->{sessionfile} = shift;
  759. TLSProxy::Message->successondata(1);
  760. }
  761. return $self->{sessionfile};
  762. }
  763. sub ciphersuite
  764. {
  765. my $class = shift;
  766. if (@_) {
  767. $ciphersuite = shift;
  768. }
  769. return $ciphersuite;
  770. }
  771. sub isdtls
  772. {
  773. my $self = shift;
  774. return $self->{isdtls}; #read-only
  775. }
  776. 1;