Hello fellow monks.
I am currently working on a proxy server, which opens and maintains an
SSL connection, accepts normal TCP connections, and then proxies
information in both directions in a protocol-independant way (though
it is limited to text line oriented and not binary protocols).
The technique I'm using for proxying is similar to a recipe in the
Perl Cookbook: chapter 17.10. This recipe uses forking to build a
bidirectional TCP client. When a connection is accepted, the process
forks. The parent does a blocking read on the connecting socket, and
blocking writes to the SSL socket. The child does a blocking read on
the SSL socket and blocking writes to the connecting socket. To quote
the cookbook, "To accomplish the same thing using just one process is
remarkably more difficult."
Here is a (pseudo) code sample which demonstrates the technique for a
single-connection proxy:
my $asock = new IO::Socket::INET (...,
Listen => 5); # accepting socket
my $sslsock = new IO::Socket::SSL(...,
PeerAddr => ...,); # SSL socket
while (1) {
my $csock = $psock->accept(); # Accept $csock, connecting socket
if (my $p = fork()) {
my $line;
$sslsock->print($line) while (defined($line = <$csock>));
# Now the connecting socket disconnected
kill 1, $p;
wait ();
} else {
my $line;
$csock->print($line) while (defined($line = <$sslsock>));
# Lost SSL connection... this may cause our parent to block
# forever, but this is just for demonstration of the Real prob
+lem...
exit;
}
}
I open one SSL socket, and keep it open for use with multiple
connecting sockets. This cuts down on the overhead of establishing
SSL connections, and is really the whole point of using this proxy
server in the first place. So rebuilding the SSL socket for every
connection isn't really an option :)
The technique above works, if $sslsock is an IO::Socket::INET instead
of an IO::Socket::SSL. It also works for the first connection, using
an SSL socket for the outgoing socket. But after the child process
exits (or is killed by its parent), something deep within the SSL
object is broken, and the $sslsock stops working correctly. This is
not a problem with IO::Socket::SSL, but with Net::SSLeay or something
deeper in the C libraries- I rewrote the server using Net::SSLeay
instead of IO::Socket::SSL and the same problem exists there.
So, after all this explanation, my questions are:
- Does anyone have any ideas on how exactly the SSL connection is
broken when the child dies?
- Is there a way to fix it or prevent it from breaking in the first
place?
- In the latest IO::Socket::SSL I see support for an OpenSSL module
instead of Net::SSLeay. Where is this module? Not in CPAN, it seems.
- Got any better ideas that Do work?
-
One technique to try to avoid breaking the SSL socket would use shared
memory to store the connecting socket, fork our child process before a
connection is accepted, and then keep it around forever instead of
letting it die. Once the child process stops blocking on the SSL
socket and has a line to write, it checks shared memory to get the
current connecting socket. It then proxies to this socket, or to a
log if no connecting socket is available. Since I have little
experience with using shared memory, does this sound feasible? Will
it actually solve the SSL socket problem, or is the cause of the SSL
issue still enough to break this?
-
Another solution is to try the "remarkably more difficult" technique
of doing this in one process. It seems to me that there should be a
really easy Perlish way to connect the SSL and connecting sockets
together with some sort of pipe fitting, and then just return control
back to my Perl program when one of the sockets drops its connection.
Does such a beast exist?
- If none of those are viable solutions, does anyone have any
pointers to references which describe the gory details of the
"remarkably more difficult" technique? I believe this entails using a
select() and nonblocking reads and writes to make sure that you're
only doing a read when there's data to read, and then buffering that
data until a socket is ready to accept a write. I'll also need to
deal with partial reads, etc. Sounds like a big pain that I'd like to
avoid, but if it's necessary I'll do it.
(Version notes: FreeBSD 4.1.1-stable, Perl 5.6.0, Net::SSLeay 1.12, IO::Socket::SSL 0.80, OpenSSL 0.96b)
Thanks in advance for any help you can give me on this!
Alan
Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
Read Where should I post X? if you're not absolutely sure you're posting in the right place.
Please read these before you post! —
Posts may use any of the Perl Monks Approved HTML tags:
- a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
| |
For: |
|
Use: |
| & | | & |
| < | | < |
| > | | > |
| [ | | [ |
| ] | | ] |
Link using PerlMonks shortcuts! What shortcuts can I use for linking?
See Writeup Formatting Tips and other pages linked from there for more info.