Answer Browser Request with IO::Socket::SSL - perl

Question formulated in the end, first detailed description of the problem and what I have tested already
I'm writing some code to showcase some basic principles to others. The code will never be productive and simplification is intended.
My goal (appart from others) is to write a simple application which uses a Web-Certificat to encrypt its network traffic.
The starting point is an application which does not encrypt:
#!/usr/bin/env perl
use strict;
use warnings;
use IO::Socket::INET;
# auto-flush on socket
$| = 1;
# creating a listening socket
my $socket = new IO::Socket::INET (
LocalAddr => '0.0.0.0', # local server address
LocalPort => '7777', # local server port
Listen => 5, # queue size for connections
Proto => 'tcp', # protocol used
);
die "cannot create socket $!\n" unless $socket;
print "server waiting for client connection on port 7777\n";
while(1)
{
# waiting for a new client connection
my $client_socket = $socket->accept() or die "socket accept failed $!";
# get information about a newly connected client
my $client_address = $client_socket->peerhost();
my $client_port = $client_socket->peerport();
print "connection from $client_address:$client_port\n";
# read up to 1024 characters from the connected client
my $client_data = '';
sysread( $client_socket, $client_data, 1024);
print "received data: $client_data\n";
# write response data to the connected client
print $client_socket "Hey $client_data!";
# notify client that response has been sent
shutdown($client_socket, 1);
}
END {
$socket->close();
}
This Server-Application can be called with this Client:
#!/usr/bin/env perl
use IO::Socket::INET;
# auto-flush on socket
$| = 1;
# create a connecting socket
my $socket = new IO::Socket::INET (
PeerHost => '127.0.0.1',
PeerPort => '7777',
Proto => 'tcp',
);
die "cannot connect to the server $!\n" unless $socket;
print "connected to the server\n";
# data to send to a server
my $req = $ARGV[0] . '';
print $socket $req;
# notify server that request has been sent
shutdown($socket, 1);
# receive a response of up to 1024 characters from server
my $response = '';
sysread( $socket, $response,1024);
print "received response: $response\n";
$socket->close();
An interaction of Client and Server could look like this:
inet$ perl server.pl
server waiting for client connection on port 7777
connection from 127.0.0.1:40028
received data: Herbert
inet$ perl client.pl "Herbert"
connected to the server
received response: Hey Herbert!
The cool thing is: The server can also be called from a browser:
So the first conclusion: The code works and is good to showcase basic functionality of a simple Client-Server interaction.
Now the Programs should use SSL to communicate
The Server and Client are written so, that SSL-Ability can be achieved by just adding a few lines in the code:
$ diff inet/server.pl ssl/server.pl
7c7
< use IO::Socket::INET;
---
> use IO::Socket::SSL 'inet4';
13c13
< my $socket = new IO::Socket::INET (
---
> my $socket = IO::Socket::SSL->new (
17a18,19
> SSL_cert_file => 'cert.pem', # SSL certificate
> SSL_key_file => 'key.pem', # SSL certificate key
$ diff inet/client.pl ssl/client.pl
5c5
< use IO::Socket::INET;
---
> use IO::Socket::SSL 'inet4';
11c11
< my $socket = new IO::Socket::INET (
---
> my $socket = new IO::Socket::SSL (
14a15
> SSL_ca_file => 'cert.pem',
So the new SSL enabled code is:
#!/usr/bin/env perl
use strict;
use warnings;
use IO::Socket::SSL 'inet4';
# auto-flush on socket
$| = 1;
# creating a listening socket
my $socket = IO::Socket::SSL->new (
LocalAddr => '0.0.0.0', # local server address
LocalPort => '7777', # local server port
Listen => 5, # queue size for connections
Proto => 'tcp', # protocol used
SSL_cert_file => 'cert.pem', # SSL certificate
SSL_key_file => 'key.pem', # SSL certificate key
);
die "cannot create socket $!\n" unless $socket;
print "server waiting for client connection on port 7777\n";
while(1)
{
# waiting for a new client connection
my $client_socket = $socket->accept() or die "socket accept failed $!";
# get information about a newly connected client
my $client_address = $client_socket->peerhost();
my $client_port = $client_socket->peerport();
print "connection from $client_address:$client_port\n";
# read up to 1024 characters from the connected client
my $client_data = '';
sysread( $client_socket, $client_data, 1024);
print "received data: $client_data\n";
# write response data to the connected client
print $client_socket "Hey $client_data!";
# notify client that response has been sent
shutdown($client_socket, 1);
}
END {
$socket->close();
}
and
#!/usr/bin/env perl
use IO::Socket::SSL 'inet4';
# auto-flush on socket
$| = 1;
# create a connecting socket
my $socket = new IO::Socket::SSL (
PeerHost => '127.0.0.1',
PeerPort => '7777',
Proto => 'tcp',
SSL_ca_file => 'cert.pem',
);
die "cannot connect to the server $!\n" unless $socket;
print "connected to the server\n";
# data to send to a server
my $req = $ARGV[0] . '';
print $socket $req;
# notify server that request has been sent
shutdown($socket, 1);
# receive a response of up to 1024 characters from server
my $response = '';
sysread( $socket, $response,1024);
print "received response: $response\n";
$socket->close();
To run the code, a certificate has to be created first:
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365
Now Server and Client can be started and interact nicely:
ssl$ perl server.pl
Enter PEM pass phrase:
server waiting for client connection on port 7777
connection from 127.0.0.1:40041
received data: Sabine
ssl$ perl client.pl "Sabine"
connected to the server
received response: Hey Sabine!
But what does not work is a connection from a browser like Firefox or Chrome, even though I converted the certificate using:
openssl pkcs12 -export -in cert.pem -inkey key.pem -out webcert.p12
I also imported the newly created certificate into the browser over its import menu.
The connection just gets refused. The browser can't connect and the server fails at $socket->accept() without any helpful message.
UPDATE: There is a message in the exported variable $SSL_ERROR:
SSL accept attempt failed error:1407609C:SSL routines:SSL23_GET_CLIENT_HELLO:http request
I did some testing with the tool analyze ssl
p5-ssl-tools-master$ perl analyze-ssl.pl --show-chain --all-ciphers -v3 127.0.0.1:7777
+ checking host=127.0.0.1(127.0.0.1) port=7777
* version SSLv23 no verification, ciphers= -> TLSv1_2,ECDHE-RSA-AES128-GCM-SHA256
* version SSLv23 no verification, ciphers=HIGH:ALL -> TLSv1_2,ECDHE-RSA-AES128-GCM-SHA256
* version TLSv1_2 no verification, ciphers= -> TLSv1_2,ECDHE-RSA-AES128-GCM-SHA256
* version TLSv1_2 no verification, ciphers=HIGH:ALL -> TLSv1_2,ECDHE-RSA-AES128-GCM-SHA256
* version TLSv1_1 no verification, ciphers= -> TLSv1_1,ECDHE-RSA-AES256-SHA
* version TLSv1_1 no verification, ciphers=HIGH:ALL -> TLSv1_1,ECDHE-RSA-AES256-SHA
* version TLSv1 no verification, ciphers= -> TLSv1,ECDHE-RSA-AES256-SHA
* version TLSv1 no verification, ciphers=HIGH:ALL -> TLSv1,ECDHE-RSA-AES256-SHA
* version SSLv3, no verification, ciphers= -> FAIL! SSL connect attempt failed because of handshake problems error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure
+ 127.0.0.1 failed permanently 'tcp connect: Verbindungsaufbau abgelehnt', no more IP to try
tcp connect: Verbindungsaufbau abgelehnt
The server seems to accept certain requests and fails at the end, maybe in the same way as with the browser?
ssl$ perl server.pl
Enter PEM pass phrase:
server waiting for client connection on port 7777
connection from 127.0.0.1:40042
received data:
connection from 127.0.0.1:40043
received data:
connection from 127.0.0.1:40044
received data:
connection from 127.0.0.1:40045
received data:
connection from 127.0.0.1:40046
received data:
connection from 127.0.0.1:40047
received data:
connection from 127.0.0.1:40048
received data:
connection from 127.0.0.1:40049
received data:
socket accept failed at server.pl line 27.
My Question
Why is the request with the browser not working?
The code should support a browser request in general since it works without SSL.
It seems to be a browser specific SSL setting since the SSL-Perl-Client has no problem.
Or is the import of the certificate into the browser not working as intended?
Can anyone give me a hint or solution in this matter?
UPDATE: When I look at the error message "SSL23" in $SSL_ERROR and the error message in the client test "SSL3" there seems to be a compatibility problem with SSL versions? Do I need to specify explicitly which version I want? (On the other hand the Client-Test for "SSL23" seems to run through successfully...)
Thanks a lot.
UPDATE: Output with $IO::Socket::SSL::DEBUG = 3;
ssl$ perl server.pl
Enter PEM pass phrase:
DEBUG: .../IO/Socket/SSL.pm:2554: new ctx 42708208
server waiting for client connection on port 7777
DEBUG: .../IO/Socket/SSL.pm:799: no socket yet
DEBUG: .../IO/Socket/SSL.pm:801: accept created normal socket IO::Socket::SSL=GLOB(0x28ac158)
DEBUG: .../IO/Socket/SSL.pm:829: starting sslifying
DEBUG: .../IO/Socket/SSL.pm:873: Net::SSLeay::accept -> -1
DEBUG: .../IO/Socket/SSL.pm:1779: SSL accept attempt failed
DEBUG: .../IO/Socket/SSL.pm:1784: SSL accept attempt failed error:1407609C:SSL routines:SSL23_GET_CLIENT_HELLO:http request
socket accept failed: SSL accept attempt failed error:1407609C:SSL routines:SSL23_GET_CLIENT_HELLO:http request at server.pl line 28.
DEBUG: .../IO/Socket/SSL.pm:2587: free ctx 42708208 open=42708208
DEBUG: .../IO/Socket/SSL.pm:2599: OK free ctx 42708208

... SSL accept attempt failed error:1407609C:SSL routines:SSL23_GET_CLIENT_HELLO:http request
My guess is that you still use a http:// URL to access the server even though you would need to use a https:// URL. This means that the browser sends a HTTP request to the server instead of first doing the TLS handshake and only sending the HTTP request after the successful handshake.
Apart from that you count on the browser understanding the old and long deprecated HTTP 0.9 protocol which consists of only the response body without any HTTP header. Not all browser understand this.

Related

Using IO::Socket::SSL over an IO::Socket::SOCKS proxy

I'd like to mix SSL and SOCKS sockets. In other words, I want to send TLS encrypted data over a SOCKS proxy and I'd like to use IO::Socket::SSL and IO::Socket::Socks
The only option I can think of is to duplicate IO::Socket::SSL into an IO::Socket::SocksSSL class that inherit from IO::Socket::Socks. That's the only way to have the right order for (eg send). I need first to have the SSL method invoked and then it will invoke the parent (IO::Socket::Socks) send. Same for connect where the SSL connect would invoke the Socks connect and then start the TLS negotiation.
Unfortunately, the IO::Socket::SSL does not have a $SOCKET_CLASS var that would allow a subclass to easily decide what it inherits from, so I to change that one line in SSL.pm and duplicate all the code
I'm probably missing something here
Using a SOCKS proxy for TCP (and thus SSL) essentially means to first create a TCP socket, do some initial SOCKS handshake and then continue to work with the socket like with a normal TCP socket. IO::Socket::Socks->new(...) does this initial SOCKS handshake and returns a normal TCP socket. IO::Socket::SSL->start_SSL($socket,...) then does the TLS handshake on this socket. Combining both essentially does the same as IO::Socket::SSL->new(...), only using a SOCKS proxy instead of a direct connection.
Thus the code might look something like this:
use strict;
use warnings;
use IO::Socket::Socks;
use IO::Socket::SSL;
# establish TCP connection to target via SOCKS proxy
my $cl = IO::Socket::Socks->new(
ProxyAddr => '127.0.0.1',
ProxyPort => 1234,
ConnectAddr => 'whatsmyip.net',
ConnectPort => 443
) or die $!;
# upgrade the TCP socket to TLS
IO::Socket::SSL->start_SSL($cl,
# hostname is needed for SNI and certificate validation
SSL_hostname => 'whatsmyip.net'
) or die $SSL_ERROR;
# do a simple HTTP request on it
print $cl "GET / HTTP/1.0\r\nHost: whatsmyip.net\r\n\r\n";
print <$cl>;

IO::Socket::SSL - establishing client connection

As per the documentation of IO::Socket::SSL (PERL) I understand that if I want to just send command to specific server-program that running on port 9999 on my host, Ican do it this way:
my $cl=IO::Socket::SSL->new("localhost:9999"); # locallost is my real case, anyway
if($cl) {
$cl->connect_SSL or die $#;
# Something about certificates?
$cl->syswrite("Command");
close($cl);
}
But the error I get is: "SSL connect attempt failed with unknown error error:140770FC:SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol at blabla.cgi line 888"
The server initialized thi way (in another pl program):
use IO::Socket::SSL;
use Net::WebSocket::Server;
my $CON={};
my #crt=&SSLCerts(); die 'E101' if(#crt==0);
my $ssl=IO::Socket::SSL->new(
Listen => 10000,
Timeout => 45,
LocalPort => 9999,
Proto => 'tcp',
SSL_cert_file => "$EF::Base/ssl/certs/$crt[0][0].crt",
SSL_key_file => "$EF::Base/ssl/keys/$crt[1][0].key"
) or die "E102: $!";
Net::WebSocket::Server->new(
listen => $ssl,
silence_max=> 3600,
tick_period => 5,
on_tick => sub {
# Empty for now
},
on_connect => sub {
my($serv,$conn)=#_; my($cid,$sid);
$conn->on(
handshake => sub {
my($cnc,$hdk)=#_;
my $nsn=$hdk->req->resource_name;
$cid=substr($nsn,4,index($nsn,'&L=')-4);
$CON->{$cid}=$cnc; # Register incomming connection
},
binary => sub {
# Handle incomming message from the client
},
disconnect => sub {
delete $CON->{$cid};
}
);
}
)->start;
Typical Websocket client that is connecting from the browser via "wss://" connects without any trouble.... The server MUST be SSL...
Here I am just trying to do the same from within perl.
What I am doing wrong? Nothing mentioned about certificates in client, only in server - the server is working fine. Maybe configuration? I have purchased SSL certificates and I use them for the server that running ok on that port.
The host is Linux (CentOS - if it matters).
... SSL23_GET_SERVER_HELLO:unknown protocol
This is the kind of error you get if the client tries to do a SSL handshake and the server responds with something which is not SSL. Typically this happens if you connect to a server which is not (properly) SSL enabled (at least not on this port) or requires some plain text to upgrade to SSL (like in case of SMTP STARTTLS and similar).
This kind of error has usually nothing to do with certificates.
This kind of error can only happen if you try to do an SSL handshake on an already established SSL socket but the server does not expect this. This seems to happen in your case:
my $cl=IO::Socket::SSL->new("localhost:9999"); # locallost is my real case, anyway
if($cl) {
$cl->connect_SSL or die $#;
...
The SSL connection is already being established by IO::Socket::SSL->new. This is the same with IO::Socket::INET or similar: if the target is given it will already connect inside new and an additional connect or connect_SSL should not be done. This is also reflected in the documentation and examples.
Since version 2.045 (released 02/2017) IO::Socket::SSL will simply ignore a connect_SSL if the SSL handshake is already done. You are likely using an older version of IO::Socket::SSL where connect_SSL will start a new handshake even if the TLS handshake was already finished. This handshake inside the TLS connection will result in the strange error you see.

Override DNS For Specific Domains Like A Hosts File, But Without Using Hosts file

I need to issue a series of parallelized web requests from the same server to a specific domain, but control what IP address these requests actually go to. Originally, I came up with a scheme where I would request the IP I wanted specifically, and then manually set the Host: www.example.com header on the request, and use a series of handlers to make sure that redirects issued followed the same pattern.
This seemed to work for some time, but lately I've been having trouble with redirects to HTTPS. The handshake will fail, and the request in turn. I have tried disabling SSL verification in a variety of ways, including:
local $ENV{ PERL_LWP_SSL_VERIFY_HOSTNAME } = 0;
local $ENV{ HTTPS_DEBUG } = 1;
$ua->ssl_opts(
SSL_ca_file => Mozilla::CA::SSL_ca_file(),
verify_hostname => 0,
SSL_verify_mode => 0x00,
);
IO::Socket::SSL::set_ctx_defaults(
SSL_verifycn_scheme => 'www',
SSL_verify_mode => 0,
);
I have also tried using LWP::UserAgent::DNS::Hosts to solve the problem, but it persists.
<edit>I should note that the reason why turning off peer validation for SSL is not solving the problem is likely because for some reason requesting this way is actually causing the handshake to fail, not failing on a validation point.</edit>
One thing that works is making an entry in /etc/hosts to point the domain at the appropriate IP, however this is not practical, because I may need to run tens, or hundreds, of tests, in parallel, on the same domain.
Is there a way to emulate the functionality of adding an entry to /etc/hosts that does not involve requesting the IP specifically and overriding the Host: ... HTTP header?
EDIT: SSL Debug Info
DEBUG: .../IO/Socket/SSL.pm:1914: new ctx 140288835318480
DEBUG: .../IO/Socket/SSL.pm:402: socket not yet connected
DEBUG: .../IO/Socket/SSL.pm:404: socket connected
DEBUG: .../IO/Socket/SSL.pm:422: ssl handshake not started
DEBUG: .../IO/Socket/SSL.pm:455: not using SNI because hostname is unknown
DEBUG: .../IO/Socket/SSL.pm:478: set socket to non-blocking to enforce timeout=180
DEBUG: .../IO/Socket/SSL.pm:491: Net::SSLeay::connect -> -1
DEBUG: .../IO/Socket/SSL.pm:501: ssl handshake in progress
DEBUG: .../IO/Socket/SSL.pm:511: waiting for fd to become ready: SSL wants a read first
DEBUG: .../IO/Socket/SSL.pm:531: socket ready, retrying connect
DEBUG: .../IO/Socket/SSL.pm:491: Net::SSLeay::connect -> -1
DEBUG: .../IO/Socket/SSL.pm:1388: SSL connect attempt failed with unknown error
DEBUG: .../IO/Socket/SSL.pm:497: fatal SSL error: SSL connect attempt failed with unknown error error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure
DEBUG: .../IO/Socket/SSL.pm:1948: free ctx 140288835318480 open=140288835318480
DEBUG: .../IO/Socket/SSL.pm:1953: free ctx 140288835318480 callback
DEBUG: .../IO/Socket/SSL.pm:1956: OK free ctx 140288835318480
And in the response I get:
Can't connect to redacted.org:443
SSL connect attempt failed with unknown error error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure at /System/Library/Perl/Extras/5.18/LWP/Protocol/http.pm line 51.
It fails equally well on our server (using an older legacy version of Perl, which I will not disclose here as it seems irrelevant).
The server initially responds to a non-HTTPS request with a 301 redirect to the HTTPS site. Then the failure occurs. I will post reproducing code with the specific details of my request removed, but any site which redirects non-HTTPS traffic to HTTPS should suffice.
use IO::Socket::SSL qw/ debug4 /;
use LWP::UserAgent;
use LWP::UserAgent::DNS::Hosts;
use HTTP::Request;
use Mozilla::CA;
use Data::Dumper;
LWP::UserAgent::DNS::Hosts->register_hosts(
'recacted.org' => '127.0.0.1', # no I am not redirecting to loopback in reality, this is anonymized
'www.redacted.org' => '127.0.0.1',
);
LWP::UserAgent::DNS::Hosts->enable_override;
my $ua = LWP::UserAgent->new;
$ua->ssl_opts( SSL_ca_file => Mozilla::CA::SSL_ca_file() );
my $request = HTTP::Request->new(GET => 'http://redacted.org/');
my $response = $ua->request($request);
print $response->content; #Dumper ( $response->is_success ? $response->headers : $response );
Again, that is not the production code, just enough code to reproduce the issue. It doesn't seem to have anything to do with SSL verification, but moreover an inability to negotiate the request, presumably because LWP::UserAgent::DNS::Hosts is doing exactly what I was doing: changing the request target to the desired IP, and then writing the Host: ... header manually. Why this causes the SSL handshake to fail, I do not know.
On my local machine debugging
openssl version -a: 1.0.2j 26 Sep 2016
IO::Socket::SSL->VERSION == 1.966
Net::SSLeay->VERSION == 1.72
On a server of ours
openssl version -a: 1.0.1t 3 May 2016
IO::Socket::SSL->VERSION == 1.76
Net::SSLeay->VERSION == 1.48
Given that it works with an explicit /etc/hosts file but not with just replacing PeerAddr or using LWP::UserAgent::DNS::Hosts this looks like a problem with the SNI extension. This TLS extension is used to provide the TLS server with the requested hostname (similar to the HTTP Host header) so that it can choose the appropriate certificate. If this SNI extension is missing some servers return a default certificate while others throw an error, like in this case.
The fix is to provide the hostname using SSL_hostname in ssl_opts. Such fix could probably also help with LWP::UserAgent::DNS::Hosts, i.e in LWP/Protocol/https/hosts.pm:
12 if (my $peer_addr = LWP::UserAgent::DNS::Hosts->_registered_peer_addr($host)) {
13 push #opts, (
14 PeerAddr => $peer_addr,
15 Host => $host,
16 SSL_verifycn_name => $host,
NEW SSL_hostname => $host, # for SNI
17 );
18 }

Port hopping on IO::SOCKET::INET

i am try to get a better understanding on Perl and was stumble about sockets. i am try to understand a "simple" example i found on xmodulo. I was expecting that like in the example the port will be 7777. But it seems like the port used for this socket communication is somewhere above 35000 and on every call of the client script the port is incremented by +1. Why ist the port different to the 7777 and why it is incrementing on every call?
the server example looks like this:
use IO::Socket::INET;
# auto-flush on socket
$| = 1;
# creating a listening socket
my $socket = new IO::Socket::INET (
LocalHost => '0.0.0.0',
LocalPort => '7777',
Proto => 'tcp',
Listen => 5,
Reuse => 1
);
die "cannot create socket $!\n" unless $socket;
print "server waiting for client connection on port 7777\n";
while(1)
{
# waiting for a new client connection
my $client_socket = $socket->accept();
# get information about a newly connected client
my $client_address = $client_socket->peerhost();
my $client_port = $client_socket->peerport();
print "connection from $client_address:$client_port\n";
# read up to 1024 characters from the connected client
my $data = "";
$client_socket->recv($data, 1024);
print "received data: $data\n";
# write response data to the connected client
$data = "ok";
$client_socket->send($data);
# notify client that response has been sent
shutdown($client_socket, 1);
}
$socket->close();
the client example is:
use IO::Socket::INET;
# auto-flush on socket
$| = 1;
# create a connecting socket
my $socket = new IO::Socket::INET (
PeerHost => '192.168.1.10',
PeerPort => '7777',
Proto => 'tcp',
);
die "cannot connect to the server $!\n" unless $socket;
print "connected to the server\n";
# data to send to a server
my $req = 'hello world';
my $size = $socket->send($req);
print "sent data of length $size\n";
# notify server that request has been sent
shutdown($socket, 1);
# receive a response of up to 1024 characters from server
my $response = "";
$socket->recv($response, 1024);
print "received response: $response\n";
$socket->close();
A connection isn't defined by
local address
peer address
port
It's defined by
local address
local port
peer address
peer port
For example,
>netstat /a
Active Connections
Proto Local Address Foreign Address State
...
TCP 10.0.0.2:34208 stackoverflow:http ESTABLISHED
TCP 10.0.0.2:34212 stackoverflow:http ESTABLISHED
TCP 10.0.0.2:34213 stackoverflow:http ESTABLISHED
TCP 10.0.0.2:34224 stackoverflow:http ESTABLISHED
TCP 10.0.0.2:34226 stackoverflow:http ESTABLISHED
TCP 10.0.0.2:34227 stackoverflow:http ESTABLISHED
...
You didn't specify a local port for the client, so the system picked an available one. That's the right thing to do. There's no reason to limit the client to one port. It can even cause problems.
For example, let's say your web browser tried to bind its sockets to port 80 (the port on which web servers listen). Your web browser would only be able to have one request pending at a time. That would be bad. You want to be able to create multiple connections to the same service. This allows you to request two different images at the same time, this allows you to load two pages in two different tabs at the same time, and so on. In the example above, my machine had six connections to stackoverflow.com's port 80, but that wouldn't have been possible if the web browser has bound the socket to port 80.

Unable to send pipelined http request over a perl socket

I have the following perl script to send pipelined http request over a sinlge tcp connection. The first request goes through and i am able to get the response. The second reqeust also gets sent, but no response is received for this request. I am able to see both requests being received on the server in the trace.
use IO::Socket::INET;
$| = 1;
$socket = new IO::Socket::INET (
PeerHost => '10.102.218.56',
PeerPort => '80',
Proto => 'tcp',);
die "cannot connect to the server $!\n" unless $socket;
print "connected to the server\n";
# data to send to a server
my $req = "GET /test/file5.html HTTP/1.1\r\nHost:10.102.218.50\r\nAccept: */*\r\n\r\n\r\n";
my $size = $socket->send($req);
print "1. sent data of length $size\n";
$socket->recv($response, 1024);
print "received response: $response\n";
my $req = "GET /test/file5.html HTTP/1.1\r\nHost:10.102.218.50\r\nAccept: */*\r\n\r\n\r\n";
my $size = $socket->send($req);
print "1. sent data of length $size\n";
$socket->recv($response, 1024);
print "received response: $response\n";
sleep 1;
$socket->close();
On the Apache access_log i see only one instance of the HTTP request being received :
10.102.218.50 - - [02/Sep/2014:23:04:50 +0530] "GET /test/file5.html HTTP/1.1" 200 6 "-" "-"
I am guessing that I am missing some characters that indicate the end of an HTTP request of the server. But i am not able to find what they are.
What am i doing wrong here?
Edit: Could the Apache server be closing the connection after the first HTTP request is answered. Is there a setting for this?
Edit2: KeepAlive was set to Off on my apache server. Setting it to ON fixes the issue.
Found the problem. The KeepAlive was set to off on my Apache server. Setting the KeepAlive to On fixed the problem.