How do I generate a connection reset programatically? - php

I'm sure you've seen the "the connection was reset" message displayed when trying to browse web pages. (The text is from Firefox, other browsers differ.)
I need to generate that message/error/condition on demand, to test workarounds.
So, how do I generate that condition programmatically? (How to generate a TCP RST from PHP -- or one of the other web-app languages?)
Caveats and Conditions:
It cannot be a general IP block. The test client must still be able to see the test server when not triggering the condition.
Ideally, it would be done at the web-application level (Python, PHP, Coldfusion, Javascript, etc.). Access to routers is problematic. Access to Apache config is a pain.
Ideally, it would be triggered by fetching a specific web-page.
Bonus if it works on a standard, commercial web host.
Update:
Sending RST is not enough to cause this condition. See my partial answer, below.
I've a solution that works on a local machine, Now need to get it working on a remote host.

I would recommend doing this via a custom socket via CLI as messing with the apache process could be messy:
#!/usr/bin/php -q
<?php
set_time_limit (0);
$sock = socket_create(AF_INET, SOCK_STREAM, 0);
socket_bind($sock, '1.1.1.1', 8081) or die('Could not bind to address');
socket_listen($sock);
$client = socket_accept($sock);
sleep(1);
$pid = getmypid();
exec("kill -9 $pid");
?>
This will generate the desired error in Firefox as the connection is closed before read.
If you feel insanely daring, you could throw this into a web script but I wouldn't even venture trying that unless you own the box and know what you're doing admin wise.

I believe you need to close the low-level socket fairly abruptly. You won't be able to do it from Javascript. For the other languages you'll generally need to get a handle on the underlying socket object and close() it manually.
I also doubt you can do this through Apache since it is Apache and not your application holding the socket. At best your efforts are likely to generate a HTTP 500 error which is not what you're after.

Update:
This script worked well enough to test our connection-reset workaround, so it's a partial answer.
If someone comes up with the full solution that works on a remote host, I'll gladly mark that as the answer.
The following script works every time when running and tested on the same machine. But when running on a remote host, the browser gets the following last 3 packets:
Source Dest Protocol Info
<server> <client> TCP 8081 > 1835 [RST] Seq=2 Len=0
<server> <client> TCP 8081 > 1835 [RST] Seq=2 Len=0
<server> <client> TCP http > 1834 [ACK] Seq=34 Ack=1 Win=6756 Len=0
As you can see, the RST flag is set and sent. But Firefox fails silently with a blank page -- no messages of any kind.
Script:
<?php
$time_lim = 30;
$listen_port = 8081;
echo
'<h1>Testing generation of a connection reset condition.</h1>
<p><a target="_blank" href="http://' .$_SERVER["HTTP_HOST"]. ':' .$listen_port. '/">
Click here to load page that gets reset. You have ' . $time_lim . ' seconds.</a>
</p>
'
;
flush ();
?>
<?php
//-- Warning! If the script blocks, below, this is not counted against the time limit.
set_time_limit ($time_lim);
$socket = #socket_create_listen ($listen_port);
if (!$socket) {
print "Failed to create socket!\n";
exit;
}
socket_set_nonblock ($socket); //-- Needed, or else script executes until a client interacts with the socket.
while (true) {
//-- Use # to suppress warnings. Exception handling didn't work.
$client = #socket_accept ($socket);
if ($client)
break;
}
/*--- If l_onoff is non-zero and l_linger is zero, all the unsent data will be
discarded and RST (reset) is sent to the peer in the case of a connection-
oriented socket.
*/
$linger = array ('l_linger' => 0, 'l_onoff' => 1);
socket_set_option ($socket, SOL_SOCKET, SO_LINGER, $linger);
//--- If we just close, the Browser gets the RST flag but fails silently (completely blank).
socket_close ($socket);
echo "<p>Done.</p>";
?>

Related

PHP Checking if a port is Active

I'm in the process of creating my own service status script as both a chance to become more familiar with the PHP language and to design it from the ground up as being as efficient as possible for my needs.
A section of my code used in both my cron job and testing a connection parts queries the IP/Port of a service to make sure it is online. My issue is that the script simply queries whether the port is "Unblocked" on that IP so if for instance I was querying port 21 with an FTP server and that FTP server crashed my script would not detect any changes meaning its not doing what I want it to do. Instead I would be wanting the IP and port to be queried and for my script to see if there is actually something running on that port, if there is show online if not error out. I've had a look on google and it seems like I would have to send a packet/receive a response so PHP can tell there's something active? I'm not sure.
This is my current code below:
<?php
$host = $_POST['servip'];
$port = $_POST['servport'];
if (!$socket = #fsockopen($host, $port, $errno, $errstr, 3)) {
echo "Offline!";
} else {
echo "Online!";
fclose($socket);
}
?>
http://php.net/manual/en/function.fsockopen.php
fsockopen — Open Internet or Unix domain socket connection The socket
will by default be opened in blocking mode. You can switch it to
non-blocking mode by using stream_set_blocking(). The function
stream_socket_client() is similar but provides a richer set of
options, including non-blocking connection and the ability to provide
a stream context.
Since fsockopen will either connect or not connect (timeout) then that tells you whether or not a connection is available ("open") or being blocked (firewall, etc).
// Ping by website domain name, IP address or Hostname
function example_pingDomain($domain){
$starttime = microtime(true);
$file = #fsockopen($domain, 80, $errno, $errstr, 10);
$stoptime = microtime(true);
$status = 0;
if (!$file) {
$status = -1; // Site is down
} else {
fclose($file);
$status = ($stoptime - $starttime) * 1000;
$status = floor($status);
}
return $status;
}
If you really want to know if the FTP server is working or not, your best option is to actually send FTP commands through to it.
An FTP server, upon connect, should typically reply with the first three bytes "220" or "120". 220 is a "greeting". You can read more in RFC 959.
To be completely sure, you might be better off using ftp:// handling in PHP, e.g. actually authenticating a user (maybe user authentication is broken, but it's still able to send a greeting - does that count is "down"?)
Anyway, if you want better than "was I able to connect on that port?" or "did the connect succeed in a timely fashion?", you have to delve into actual communication over the socket. Ultimately, this means you have to do something special for each type of service (for some, read bytes, for others write bytes, etc.)

socket_write: How to send multiple packets without closing the connection?

I have this code:
$requestCount = 0;
$maxRequestCount = 10;
$ip = "192.168.0.100";
$port = 10000;
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
$connect = socket_connect($socket, $ip, $port);
while(true){
if($requestCount == $maxRequestCount){break;}
$write = socket_write($socket, $getHTTP, strlen($getHTTP));
echo "Sending TCP message... OK (lenght = $write).<br>";
$out = '';
while($out = socket_read($socket, 65536)){echo "Reading response... OK (lenght = ". strlen($out).")<br>";}
echo "<br>";
usleep(100);
$requestCount++;
}
socket_close($socket);
When the first request is made the connection is already closed (FYN, ACK).
How do i send 10 packets and then the connection is closed?
You can't. Just like a real-world conversation, there is no way to force somebody who isn't interested to keep listening. In the same way, you can't stop the computer on the other end of your socket from closing it.
Judging from variable names in your code, it looks like you're sending HTTP requests (just on a different port). HTTP servers have the option of closing the connection after they respond to the first request they get in that connection. That's what appears to be happening here. You will have to create a new socket and reconnect to send each request.
Another note: TCP doesn't have "packets". It is a stream oriented connection. I know that sounds like a pedantic difference, but it doesn't make sense to ask how you would "send multiple packets without closing the connection", because you don't get to control how TCP sends your messages.
From the packet capture it can be seen that you send 342 bytes to the peer (line 4) and then the peer responds with 1446 bytes (line 6) and after that closes the connection (FIN in line 7). From then on the server will not accept more data from the client and thus any attempts to send more data will be rejected with RST.
I don't know what you are trying to achieve, but since the server closes the connection before the client is done sending the data there is probably some error. You might get more details from the servers response or it might simply be a protocol validation, i.e. the client does not speak the same protocol as the server or not in a proper way. For instance if you would try to use your code to speak with an HTTP server it would be simply wrong because you don't care about keep-alive, body length etc.
Probably the remote end closed the connection.
Probably it's because you have to control what socket_write returns. You have no warranty that socket_write will write your whole buffer at once. If socket_write return 8142 (for example), you have to cut your buffer $getHTTP = substr($getHTTP, 8142); and try a socket_write again. If socket_write(...) === false there is an error and the connection is closed, you have to test it too.

PHP socket server, check if client is alive

I have a php server listening for 1 c# client.
When a connection is established, it is kept alive until client sends the command "quit" which kills the PHP server.
But when the c# client disconnects without the "quit" command (ie : clicking the close (x) button in the windows form) the server just keep listening, and can't receive any other connection from that client.
Is there a way to check from the server side (PHP) if connection is still alive with client?
My php server code is based on example1 of: http://php.net/manual/en/sockets.examples.php
If someone is interested in reproducing the bug/error behavior, paste code from example1 : http://php.net/manual/en/sockets.examples.php, connect by telnet from a remote client in lan, unplug client wire... php server will hang around forever, no new connection is accepted.
In your loop, you need to check the return value of socket_read(). If it returns FALSE, then there was a read error (which can be caused by the remote host closing the connection). The example code in the link you provided covers this case.
If you need to gracefully handle certain error states, you can always check the socket error code using socket_last_error() -- this note decribes the possible codes.
Edit:
When using putty for telnet, if i close with X button, connecion is closed properly in PHP, but if i unplug the ethernet wire of the putty machine, PHP server just hangs around.
The reason that the connection is closed when killing PuTTY is that PuTTY closes its open connection(s) when exiting. This causes socket_read() to return with an error code (I believe ECONNRESET). If you pull the network cable, it doesn't have a chance to do that.
Depending on how your network is configured, the TCP connection should eventually fail. You can attempt to control the timeout by setting SO_RCVTIMEO with socket_set_option(), but this doesn't always work on all platforms (I'm looking at you, WinSock).
Alternatively, you can roll your own polling loop using socket_select() with a reasonable timeout. If none of the connected sockets have data to send after your timeout, then kill the server.
I did this by checking if the socket_select() $read array includes the connection in question but socket_read() data is empty (twice).
It seems that socket_select() adds disconnected clients to the $read array and socket_read() gives an empty string '' when trying to read the disconnected client's data.
The following code will show the state of connection.
$address='example.com';
$port = '9065';
if (isset($port) && ($socket=socket_create(AF_INET, SOCK_STREAM, SOL_TCP))
&& (socket_connect($socket, $address, $port))) {
$text="Connection successful on IP $address, port $port";
socket_close($socket);
}
else {
$text='Unable to connect<pre>'.socket_strerror(socket_last_error()).'</pre>';
}
echo $text;
As Michael Dodd says, using socket_select() can have all sockets that have received data plus those they have closed. Also you can have all those that their buffer can accept data for transmission, and / or those that have raised some exception. Do have this info, a (separate) copy of sockets array must be placed in 2nd and / 3d parameter of function.
(if not needed, this function must have $null as a variable equal to null, not just null)
The following example shows how to read data and test sockets if they are still open. I am using this code for sockets that have been created by socket_accept() on a listening socket, and it is working without problems. Instead of using socket_recv, socket_read can be used.
//all sockets created have been inserted to an array $socketArray
//get a copy of the sockets array
$tempArray = $socketArray;
//this command will remove from $tempArray all sockets that have no data and are alive, with a timeout of 0 sec, 100 msec
socket_select($tempArray, $null, $null, 0, 100);
if (count($tempArray)) {
//if we have some sockets in the array
foreach($tempArray as $socket) {
//read some data
$count = socket_recv($socket, $socketData, 1024, 0);
if ($count) {
//your code to do what you want with $socketData
} else {
//find socket position in initial socket array
$index = array_search($socket, $socketArray);
//if found, remove it from array and close the socket
if ($index !== false) {
array_splice($socketArray, $index, 1);
socket_close($socket);
}
}
}
}

Status checker for hundreds IP addresses

I wonder how to make a status checker, checking about 500 addresses in a few minutes?
(it'll check a certain port if its listening).
But I care about the performance... so I don't know if it can be done with PHP. Waiting for your suggestions guys.
Also please give me some examples, if you think that the best way for this thing will be PHP or C#.
Ofc. I meant the TCP connection but not http, since I need to check open port for example: 11740
Edit:
Added third bounty for this question! Please post some better answer than those already posted.
This is very doable in PHP and you could check 500 IP in a few seconds. Use mutli-curl to send out many requests at once (i.e. 100 or all 500). It will take only as long as the slowest IP to respond. But you may want to set a reasonable curl connect timeout of a few seconds. Default network timeout is 2 minutes as I recall.
http://php.net/manual/en/function.curl-multi-exec.php
Note that I'm not saying PHP is your best choice for something like this. But it can be done fairly quickly and easily in PHP.
Here is a full code example. I tested it with real URLs and it all worked. The $results array will contain just about all the stats you can get from a curl request. In your case, since you just care if the port is "open" you do a HEAD request by setting CURLOPT_NOBODY to true.
$urls = array(
'http://url1.com'=>'8080',
'http://url2'=>'80',
);
$mh = curl_multi_init();
$url_count = count($urls);
$i = 0;
foreach ($urls as $url=>$port) {
$ch[$i] = curl_init();
curl_setopt($ch[$i], CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch[$i], CURLOPT_NOBODY, true);
curl_setopt($ch[$i], CURLOPT_URL, $url);
curl_setopt($ch[$i], CURLOPT_PORT, $port);
curl_multi_add_handle($mh, $ch[$i]);
$i++;
}
$running = null;
do {
$status = curl_multi_exec($mh,$running);
$info = curl_multi_info_read($mh);
} while ($status == CURLM_CALL_MULTI_PERFORM || $running);
$results= array();
for($i = 0; $i < $url_count; $i++) {
$results[$i] = curl_getinfo($ch[$i]);
// append port number request to URL
$results[$i]['url'] .= ':'.$urls[$results[$i]['url']];
if ($results[$i]['http_code']==200) {
echo $results[$i]['url']. " is ok\n";
} else {
echo $results[$i]['url']. " is not ok\n";
}
curl_multi_remove_handle($mh, $ch[$i]);
}
curl_multi_close($mh);
print_r($results);
Your best bet might be to use a dedicated port scanner like nmap. I don't know the command-line options off the top of my head, but it should be possible to output a results file and just parse it from PHP.
Here is a way to do this very quickly in PHP using the sockets extension, by setting all the sockets to non blocking. From a purely networking point of view, this is the most efficient way, since this simply tests the TCP connectivity and does not exchange any actual data. Tested on PHP/5.2.17-Win32.
<?php
// An array of hosts to check
$addresses = array(
'192.168.40.40',
'192.168.5.150',
'192.168.5.152',
'google.com',
'192.168.5.155',
'192.168.5.20'
);
// The TCP port to test
$testport = 80;
// The length of time in seconds to allow host to respond
$waitTimeout = 5;
// Loop addresses and create a socket for each
$socks = array();
foreach ($addresses as $address) {
if (!$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) {
echo "Could not create socket for $address\n";
continue;
} else echo "Created socket for $address\n";
socket_set_nonblock($sock);
// Suppress the error here, it will always throw a warning because the
// socket is in non blocking mode
#socket_connect($sock, $address, $testport);
$socks[$address] = $sock;
}
// Sleep to allow sockets to respond
// In theory you could just pass $waitTimeout to socket_select() but this can
// be buggy with non blocking sockets
sleep($waitTimeout);
// Check the sockets that have connected
$w = $socks;
$r = $e = NULL;
$count = socket_select($r, $w, $e, 0);
echo "$count sockets connected successfully\n";
// Loop connected sockets and retrieve the addresses that connected
foreach ($w as $sock) {
$address = array_search($sock, $socks);
echo "$address connected successfully\n";
#socket_close($sock);
}
/* Output something like:
Created socket for 192.168.40.40
Created socket for 192.168.5.150
Created socket for 192.168.5.152
Created socket for google.com
Created socket for 192.168.5.155
Created socket for 192.168.5.20
4 sockets connected successfully
192.168.40.40 connected successfully
192.168.5.150 connected successfully
google.com connected successfully
192.168.5.20 connected successfully
*/
The best way to this would be nmap, as mentioned in other answers.
You'd want to run it like this (-PN is don't ping, -sP means to skip the port scan and just check if the host is up, -PS80 means to check port 80, -n is not to do reverse DNS lookup, -oG - is to output in machine readable format, and the other arguments are IP addresses or hostnames):
nmap -PN -sP -PS80 -n -oG - --send-ip IP1 IP2 ...
And it would look like this:
$ nmap -n -PN -sP -PS80 -oG - 209.85.147.104 87.248.122.122 4.4.4.4
# Nmap 5.21 scan initiated Tue Feb 21 01:07:20 2012 as: nmap -n -PN -sP -PS80 -oG - 209.85.147.104 87.248.122.122 4.4.4.4
Host: 209.85.147.104 () Status: Up
Host: 87.248.122.122 () Status: Up
Host: 4.4.4.4 () Status: Down
# Nmap done at Tue Feb 21 01:07:21 2012 -- 3 IP addresses (2 hosts up) scanned in 0.95 seconds
You could run and parse this from PHP with no trouble. I'm not very experienced in PHP, and haven't tested this, but here's some example code:
<?php
$output = shell_exec('nmap -n -PN -sP -PS80 -oG - --send-ip ' . implode(" ", $ips));
$result = array();
foreach(preg_split("/\r?\n/", $output) as $line) {
if (!(substr($line, 0, 1) === "#")) {
$info = preg_split("[\t ]", $line);
$result[$info[2]] = ($info[5] === "Up");
}
}
?>
Mind you, writing PHP code or C# code or whatever that does this isn't a big deal, it's just that nmap is very very good at what it does, and extremely versatile, that writing code that does this is reinventing the wheel. If you do decide to go that route, make sure you make your code asynchronous, otherwise one slow server would slow down your entire sweep.
As mentioned by kz26, nmap from command-line would be your best option. With PHP functions like system, exec, shell_exec, etc to capture the results for processing.
This guide should help you to get started http://www.cyberciti.biz/tips/linux-scanning-network-for-open-ports.html
C# would be a better option as you can use threads to speed up the process.
In PHP, you can essentially check if a TCP port is open by using fsockopen().
$host = 'example.com';
$port = 80;
$timeout = 30;
$fp = #fsockopen($host, $port, $errno, $errstr, $timeout);
if (!$fp) {
echo "Port $port appears to be closed on $host Reason: $errno: $errstr.\n";
} else {
echo "Port $port is open on $host\n";
fclose($fp);
}
As kz26 said, you could also get something like nmap to check the ports on a bunch of hosts and use php to call it and process the results as well.
PHP should be able to check 500 ips in pretty short amount of time, but it really depends on your internet connection and other specs. Other tools written in lower languages would be a little faster, but I think that php is good for the job. You must just set php execution limit to a suitable value before trying
They keyword in this is non-blocking. You would want to have a certain callback when an attempt is succesful and be able to run more calls in the meantime.
Some functions like sockets from DaveRandom's answer allow for a non-blocking mode to do this in regular php installations. You can also use different programming languages such as node.js to do this very efficiently because they are designed to be non-blocking.
The by far most efficient way to do this is to use raw sockets, however this requires administrative privileges and some boilerplate coding. You choose a local port as the source, send a SYN packet to port 80 of each target address, and collect the return packets on the source port. If they have an ACK flag, the port is open for connections. If they have RST or they don't return, the port isn't open/the host is dead.
Obviously you will need to manually wait for whatever your "timeout" of choice is as this method goes around the OS network stack. This also requires you to construct the TCP and IP headers manually, though, and I doubt it can be done from PHP. It can certainly be done in C, and I believe C# also supports raw sockets (haven't done it in C# myself).
This is extremely fast and doesn't pollute the system with a bunch of open connections or threads.
The best thing you can do is start a number of threads (you decide the number; probably more than 10 and less than a 100). Doing scanning on different threads will speed up your check. I am not sure if you can do multi-threading in php. If not, then c# would be better.

PHP: socket listen problem

Here is my code:
<?php
$host = "127.0.0.1";
$portListen = 1234;
$portSend = 1240;
// create socket
$sSender = socket_create(AF_INET, SOCK_STREAM, 0);
socket_connect($sSender, $host, $portListen);
socket_write($sSender, "test", strlen ("test"));
$sListen = socket_create(AF_INET, SOCK_STREAM, 0);
socket_set_option($sListen, SOL_SOCKET, SO_REUSEADDR, 1);
socket_bind($sListen, $host, $portSend);
socket_listen($sListen,1);
$dataSock = socket_accept($sListen);
echo socket_read($dataSock, 3, PHP_NORMAL_READ);
// close sockets
socket_close($sSender);
socket_close($sListen);
?>
I send "test" to another application, it receives, and send back "ack". Problem is, I can only do it once. If I refresh, I get the address is already used error. I tried the solutions suggested on php.net but to no avail. Trying to socket_shutdown() before socket_close() only give me not connected warning, and upon refreshing will give me a never ending loading.
From what I understand the reason socket is not immediately closed is because there is still data in the buffer. But as you can see I explicitly state to listen to only 1 connection. Plus I am only sending 3 characters from my application and reading 3 in this script.
What am I doing wrong?
edit: The reason I'm using 2 sockets is because I cannot listen() after write() which give me socket is already connected error. Skipping listen() and going straight for read() after write() give me invalid argument error.
I see, after having a few hours sleep and re-analyzing my code and the documentations, I managed to fix everything. You guys are right, 1 socket is indeed enough and the correct way:
<?php
$host = "127.0.0.1";
$portListen = 1234;
$sSender = socket_create(AF_INET, SOCK_STREAM, 0) or die("Could not create socket\n");
socket_connect($sSender, $host, $portListen) or die("Could not connect\n");
socket_write($sSender, "test", strlen ("test")) or die("Could not write output\n");
echo socket_read($sSender, 3, PHP_NORMAL_READ);
socket_close($sSender);
?>
So simple!
After a connection is closed, the socket enters a linger state so that if (during the close) packets were lost and retransmitted, the response would be a clean acknowledgement instead of RST (reset) indicating no such socket was open. It's part of the TCP specification, you can't make it stop happening.
Listen(1) doesn't mean accept only one connection, it means maintain a queue of up 1 connections waiting for an application to accept() them. So as soon as you accept the first, the socket is ready to listen for more.
Like everybody else, I'm wondering why the odd design, but I assume it's a boiled-down example that presents your problem and doesn't necessarily present your real plan.
Why do you need to create 2 sockets for read and write? It looks like an odd design. Client apps usually open a socket connection to the server, then send a request and read the server's response on the same socket.
Also, creating a listening socket (iow a server) won't scale past any firewall or NAT gateway.
Answer to yor comment: No need to listen. just read (possibly blocking operation if your server hasn't replied yet).

Categories