1 # Written by Matt Caswell for the OpenSSL project.
2 # ====================================================================
3 # Copyright (c) 1998-2015 The OpenSSL Project. All rights reserved.
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions
9 # 1. Redistributions of source code must retain the above copyright
10 # notice, this list of conditions and the following disclaimer.
12 # 2. Redistributions in binary form must reproduce the above copyright
13 # notice, this list of conditions and the following disclaimer in
14 # the documentation and/or other materials provided with the
17 # 3. All advertising materials mentioning features or use of this
18 # software must display the following acknowledgment:
19 # "This product includes software developed by the OpenSSL Project
20 # for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
22 # 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
23 # endorse or promote products derived from this software without
24 # prior written permission. For written permission, please contact
25 # openssl-core@openssl.org.
27 # 5. Products derived from this software may not be called "OpenSSL"
28 # nor may "OpenSSL" appear in their names without prior written
29 # permission of the OpenSSL Project.
31 # 6. Redistributions of any form whatsoever must retain the following
33 # "This product includes software developed by the OpenSSL Project
34 # for use in the OpenSSL Toolkit (http://www.openssl.org/)"
36 # THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
37 # EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
39 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
40 # ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
42 # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
43 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
45 # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
46 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
47 # OF THE POSSIBILITY OF SUCH DAMAGE.
48 # ====================================================================
50 # This product includes cryptographic software written by Eric Young
51 # (eay@cryptsoft.com). This product includes software written by Tim
52 # Hudson (tjh@cryptsoft.com).
56 package TLSProxy::Proxy;
62 use TLSProxy::Message;
63 use TLSProxy::ClientHello;
64 use TLSProxy::ServerHello;
65 use TLSProxy::ServerKeyExchange;
77 proxy_addr => "localhost",
79 server_addr => "localhost",
87 cipherc => "AES128-SHA",
94 message_rec_list => []
97 return bless $self, $class;
104 $self->{cipherc} = "AES128-SHA";
105 $self->{ciphers} = "";
107 $self->{record_list} = [];
108 $self->{message_list} = [];
109 $self->{message_rec_list} = [];
111 TLSProxy::Message->clear();
112 TLSProxy::Record->clear();
130 open(STDOUT, ">", File::Spec->devnull())
131 or die "Failed to redirect stdout";
132 open(STDERR, ">&STDOUT");
133 my $execcmd = $self->execute." s_server -testmode -accept "
134 .($self->server_port)
135 ." -cert ".$self->cert." -naccept 1";
136 if ($self->ciphers ne "") {
137 $execcmd .= " -cipher ".$self->ciphers;
145 $oldstdout = select(File::Spec->devnull());
148 # Create the Proxy socket
149 my $proxy_sock = new IO::Socket::INET(
150 LocalHost => $self->proxy_addr,
151 LocalPort => $self->proxy_port,
158 print "Proxy started on port ".$self->proxy_port."\n";
160 die "Failed creating proxy socket\n";
163 if ($self->execute) {
166 open(STDOUT, ">", File::Spec->devnull())
167 or die "Failed to redirect stdout";
168 open(STDERR, ">&STDOUT");
169 my $execcmd = $self->execute
170 ." s_client -testmode -connect "
171 .($self->proxy_addr).":".($self->proxy_port);
172 if ($self->cipherc ne "") {
173 $execcmd .= " -cipher ".$self->cipherc;
179 # Wait for incoming connection from client
180 my $client_sock = $proxy_sock->accept()
181 or die "Failed accepting incoming connection\n";
183 print "Connection opened\n";
185 # Now connect to the server
188 #We loop over this a few times because sometimes s_server can take a while
191 $server_sock = new IO::Socket::INET(
192 PeerAddr => $self->server_addr,
193 PeerPort => $self->server_port,
200 #Sleep for a short while
201 select(undef, undef, undef, 0.1);
203 die "Failed to start up server\n";
206 } while (!$server_sock);
208 my $sel = IO::Select->new($server_sock, $client_sock);
210 my @handles = ($server_sock, $client_sock);
212 #Wait for either the server socket or the client socket to become readable
214 while(!(TLSProxy::Message->end) && (@ready = $sel->can_read)) {
215 foreach my $hand (@ready) {
216 if ($hand == $server_sock) {
217 $server_sock->sysread($indata, 16384) or goto END;
218 $indata = $self->process_packet(1, $indata);
219 $client_sock->syswrite($indata);
220 } elsif ($hand == $client_sock) {
221 $client_sock->sysread($indata, 16384) or goto END;
222 $indata = $self->process_packet(0, $indata);
223 $server_sock->syswrite($indata);
232 print "Connection closed\n";
234 $server_sock->close();
237 #Closing this also kills the child process
238 $client_sock->close();
241 $proxy_sock->close();
251 my ($self, $server, $packet) = @_;
258 print "Received server packet\n";
260 print "Received client packet\n";
263 print "Packet length = ".length($packet)."\n";
264 print "Processing flight ".$self->flight."\n";
266 #Return contains the list of record found in the packet followed by the
267 #list of messages in those records
268 my @ret = TLSProxy::Record->get_records($server, $self->flight, $packet);
269 push @{$self->record_list}, @{$ret[0]};
270 $self->{message_rec_list} = $ret[0];
271 push @{$self->{message_list}}, @{$ret[1]};
275 #Finished parsing. Call user provided filter here
276 $self->filter->($self);
278 #Reconstruct the packet
280 foreach my $record (@{$self->record_list}) {
281 #We only replay the records for the current flight
282 if ($record->flight != $self->flight) {
285 $packet .= $record->reconstruct_record();
288 $self->{flight} = $self->{flight} + 1;
290 print "Forwarded packet length = ".length($packet)."\n\n";
299 return $self->{execute};
304 return $self->{cert};
309 return $self->{debug};
314 return $self->{flight};
319 return $self->{record_list};
324 return $self->{message_list};
329 return $self->{success};
337 #Read/write accessors
342 $self->{proxy_addr} = shift;
344 return $self->{proxy_addr};
350 $self->{proxy_port} = shift;
352 return $self->{proxy_port};
358 $self->{server_addr} = shift;
360 return $self->{server_addr};
366 $self->{server_port} = shift;
368 return $self->{server_port};
374 $self->{filter} = shift;
376 return $self->{filter};
382 $self->{cipherc} = shift;
384 return $self->{cipherc};
390 $self->{ciphers} = shift;
392 return $self->{ciphers};