http://www.perlmonks.org?node_id=179922

steves has asked for the wisdom of the Perl Monks concerning the following question:

I wrote a simple HTTP proxy server based on HTTP::Daemon. I'd like to extend it to include SSL support. My server follows the same basic model as the one in the docs for HTTP::Daemon.

I have SSL support (OpenSSL and Crypt::SSLeay) working for LWP https requests, so I'm familiar with it from that perspective. I'm not seeing how to enable it in HTTP::Daemon. I assume I have to do something special when I see a CONNECT request.

Has anyone done any work in this area that might help get me started? Thanks.

Replies are listed 'Best First'.
Re: HTTP::Daemon and SSL
by rob_au (Abbot) on Jul 07, 2002 at 07:23 UTC
    Okay, while I may not be able to give you a complete solution with tested code, I should be able to help you out, having worked on a similar project previously.

    The CONNECT method which you are receiving from HTTP clients is documented in RFC2616, as the means by which SSL connections are tunneled through HTTP connections. This method is sent by a HTTP client to a proxy server, followed by the destination host and destination port number - For example:

    CONNECT ssl.webserver.com:443 HTTP/1.0

    At this point, the HTTP proxy should initiate a connection to the designated port on the destination host and, if successful, return a 200 HTTP success code. The secure communication can then take place over the established connection.

    With regard to making all this happen in your code, there is a patch available for the HTTP::Daemon module within the IO::Socket::SSL module which changes the inheritance of HTTP::Daemon to make use of IO::Socket::SSL in place of IO::Socket. Also too, if you have no luck with this, there are a couple of other patches for HTTP::Daemon which I can seen that are designed to achieve your goal and can also post these if required.

    From IO-Socket-SSL-0.81\diffs\libwww-perl\HTTP_Daemon.pm.diff ...

    *** /usr/local/perl5.005_03/lib/site_perl/5.005/HTTP/Daemon.pm.orig + Wed Jun 9 19:41:53 1999 --- /usr/local/perl5.005_03/lib/site_perl/5.005/HTTP/Daemon.pm Wed +Jun 9 19:42:43 1999 *************** *** 63,69 **** $VERSION = sprintf("%d.%02d", q$Revision: 1.21 $ =~ /(\d+)\.(\d+)/); use IO::Socket (); ! @ISA=qw(IO::Socket::INET); $PROTO = "HTTP/1.1"; --- 63,71 ---- $VERSION = sprintf("%d.%02d", q$Revision: 1.21 $ =~ /(\d+)\.(\d+)/); use IO::Socket (); ! use IO::Socket::SSL; ! #@ISA=qw(IO::Socket::INET); ! @ISA=qw(IO::Socket::SSL); $PROTO = "HTTP/1.1"; *************** *** 156,162 **** use vars qw(@ISA $DEBUG); use IO::Socket (); ! @ISA=qw(IO::Socket::INET); *DEBUG = \$HTTP::Daemon::DEBUG; use HTTP::Request (); --- 158,165 ---- use vars qw(@ISA $DEBUG); use IO::Socket (); ! #@ISA=qw(IO::Socket::INET); ! @ISA=qw(IO::Socket::SSL); *DEBUG = \$HTTP::Daemon::DEBUG; use HTTP::Request ();

    Also see the demo file from the IO::Socket::SSL distribution, IO-Socket-SSL-0.81\demo\daemon.pl, which makes use of HTTP::Daemon in this fashion.

    Good luck!

     

      Hello. I've tried your hints by doing the changes of Daemon.pm and use my script but not with desired success. Has anyone perhaps sample-code for proxying client-requests with CONNECT-method to establish ssl and what additional changes have to do? I'll be very glad, if someone can post it here. Best regards, Andreas
      my $UA = LWP::UserAgent->new; $UA->agent("Mozilla/4.0"); $UA->protocols_allowed(['http','https']); my $SRV = HTTP::Daemon->new(LocalPort => 3128); while (my $conn = $SRV->accept) { while (my $request = $conn->get_request) { my $resp = $UA->simple_request($request); $conn->send_response($resp); } $conn->close; }
      Debugoutput in request to local webserver and https://www.nodeworks.com looks like:
      LWP::UserAgent::send_request: GET http://127.0.0.1/ LWP::UserAgent::_need_proxy: Not proxied LWP::UserAgent::send_request: http URLs are among LWP::UserAgent=HASH( +0x1fe594)'s allowed protocols (http https) LWP::Protocol::http::request: () LWP::Protocol::collect: read 639 bytes LWP::Protocol::collect: read 817 bytes LWP::UserAgent::send_request: GET http://127.0.0.1/apache_pb.gif LWP::UserAgent::_need_proxy: Not proxied LWP::UserAgent::send_request: http URLs are among LWP::UserAgent=HASH( +0x1fe594)'s allowed protocols (http https) LWP::Protocol::http::request: () LWP::UserAgent::send_request: CONNECT http://www.nodeworks.com:443 LWP::UserAgent::_need_proxy: Not proxied LWP::UserAgent::send_request: http URLs are among LWP::UserAgent=HASH( +0x1fe594)'s allowed protocols (http https) LWP::Protocol::http::request: () LWP::UserAgent::send_request: CONNECT http://www.nodeworks.com:443 LWP::UserAgent::_need_proxy: Not proxied LWP::UserAgent::send_request: http URLs are among LWP::UserAgent=HASH( +0x1fe594)'s allowed protocols (http https) LWP::Protocol::http::request: ()
Re: HTTP::Daemon and SSL
by rjray (Chaplain) on Jul 07, 2002 at 07:34 UTC

    According to the manual page for HTTP::Daemon it uses a IO::Socket::INET object that gets blessed into the daemon class. I looked at the code, and aside from force-setting Listen and Proto arguments before handing off to the parent class' constructor, this is the case.

    According to the manual page for IO::Socket::SSL, it too is an almost straight sub-class of IO::Socket::INET. Thus, it should in theory be possible to create an object of the IO::Socket::SSL class, bless it into HTTP::Daemon manually, and use it as an ordinary daemon object. I say in theory because the SSL class manpage warns that it doesn't have the full set of methods provided for just yet, so if the HTTP::Daemon class happens to try to use one of the few that aren't available, chaos may well ensue. But it is certainly worth a try.

    I myself would be interested to hear about your results, as I've been meaning to try my RPC::XML::Server class out with SSL underneath.

    --rjray

      Well I made some progress based on these suggestions. What I did so far is this:

      • Copied HTTP::Daemon and modified it as rob_au suggested to make an SSL version;
      • Used that base to create an SSL proxy in addition to the existing HTTP proxy I already had. This was done by subclassing the proxy class I already had and overriding the creation of the daemon with the SSL version;
      • Created a server certificate. This is where most of the time went. Creation of server certificates was a bit new to me and not really clearly documented in the OpenSSL docs.

      At this point I had two proxy server classes: one for HTTP and one for SSL. I built two stub servers using those and fired them up. The results so far are that I can connect to the SSL proxy fine and it's able to see the HTTP traffic going back and forth if I send it the requests explicitly. But I can't get the server to be used as a true proxy by setting it in the browser. When I do that, OpenSSL complains when it sees the clear text CONNECT request, spitting out this proxy error with DEBUG on:

      error message: 'SSL_accept: 'error:1407609B:SSL routines:SSL23_GET_CLI +ENT_HELLO:https proxy request
      So it looks like OpenSSL wants some special set up for proxies I'm not seeing just yet ... either that or it explicitly prohibits them.
Re: HTTP::Daemon and SSL
by IlyaM (Parson) on Jul 07, 2002 at 16:32 UTC
    ++ rob_au and rjray.

    I'd like to add that if you don't mind using additional software then you can instantly turn any non-SSL service into SSL-enabled using stunnel. It is not a Perl solution but it is probably the simpliest.

    --
    Ilya Martynov (http://martynov.org/)