1#!/usr/local/bin/perl
2# simple HTTPS proxy with SSL bridging, uses Net::PcapWriter to
3# to log unencrypted traffic
4
5my $listen = '127.0.0.1:8443';      # where to listen
6my $connect = 'www.google.com:443'; # where to connect
7
8use strict;
9use warnings;
10use IO::Socket::SSL;
11use IO::Socket::SSL::Intercept;
12use IO::Socket::SSL::Utils;
13
14my ($proxy_cert,$proxy_key) = CERT_create(
15    CA => 1,
16    subject => { commonName => 'foobar' }
17);
18
19
20my $mitm = IO::Socket::SSL::Intercept->new(
21    proxy_cert => $proxy_cert,
22    proxy_key  => $proxy_key,
23);
24
25my $listener = IO::Socket::INET->new(
26    LocalAddr => $listen,
27    Listen => 10,
28    Reuse => 1,
29) or die "failed to create listener: $!";
30
31while (1) {
32    # get connection from client
33    my $toc = $listener->accept or next;
34
35    # create new connection to server
36    my $tos = IO::Socket::SSL->new(
37	PeerAddr => $connect,
38	SSL_verify_mode => 1,
39	SSL_ca_path => '/etc/ssl/certs',
40    ) or die "ssl connect to $connect failed: $!,$SSL_ERROR";
41
42    # clone cert from server
43    my ($cert,$key) = $mitm->clone_cert( $tos->peer_certificate );
44
45    # and upgrade connection to client to SSL with cloned cert
46    IO::Socket::SSL->start_SSL($toc,
47	SSL_server => 1,
48	SSL_cert => $cert,
49	SSL_key => $key,
50    ) or die "failed to ssl upgrade: $SSL_ERROR";
51
52    # transfer data
53    my $readmask = '';
54    vec($readmask,fileno($tos),1) = 1;
55    vec($readmask,fileno($toc),1) = 1;
56    while (1) {
57	select( my $can_read = $readmask,undef,undef,undef ) >0 or die $!;
58	# try to read the maximum frame size of SSL to avoid issues
59	# with pending data
60	if ( vec($can_read,fileno($tos),1)) {
61	    sysread($tos,my $buf,16384) or last;
62	    print $toc $buf;
63	}
64	if ( vec($can_read,fileno($toc),1)) {
65	    sysread($toc,my $buf,16384) or last;
66	    print $tos $buf;
67	}
68    }
69}
70
71
72