php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #18351 socket_read() on closed sock crashed OS and forced instant warm boot of machine
Submitted: 2002-07-15 09:05 UTC Modified: 2002-10-08 21:42 UTC
Votes:1
Avg. Score:5.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:1 (100.0%)
Same OS:1 (100.0%)
From: administrator at zinious dot com Assigned:
Status: No Feedback Package: Sockets related
PHP Version: 4.2.1 OS: Windows 2000 Server sp2, IIS 5.0
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: administrator at zinious dot com
New email:
PHP Version: OS:

 

 [2002-07-15 09:05 UTC] administrator at zinious dot com
Used the standard W32 build of PHP.EXE (I did not compile it).

Wrote a PHP script that acts as a relay server (client connects to me, I connect to the destination server and act as a proxy/gateway to that server for the client).

The destination server had closed the connection and my script socket_select()'ed on it.  However, due to a bug in my script that returned the wrong value, I proceeded to try and socket_read() from the socket instead of closing the client connection and ending the script.

The result of a socket_read() after failing on a socket_select() caused Windows 2000 Server s.p. 2 running IIS 5.0 to die immediately, forced a warm boot of the machine (no GPF, just immediate warm boot).

I reproduced it 3 times, totalling 4 sucessful warm-boots before finding my bug and fixing it.  I have not encountered the problem since.

Incidently, my bug was returning "ZSC_LOSTCONNECTION" from a function that polls the socket, but I was testing for "ZSC_CONNECTIONLOST" instead.

Here is my full relay script, the fixed version (it's very simple to "unfix it" and modify it to act as a normal relay instead of the special service requests that I wrote in).

Hope this helps guys,
Peter Souza IV
CEO/administrator
administrator@zinious.com
Zinious Software corporation
www.zinious.com


-----script here-----
#!/usr/bin/php -q

<?php

function SocketCheck($socket_to_check)
{
	$readsocks = array($socket_to_check);

	$readsocks = array($socket_to_check);
	$num_changed_sockets = socket_select($readsocks, $writesocks = NULL, $exceptsocks = NULL, 0);

	if ($num_changed_sockets > 0)
	{
		if (($indata = socket_read($socket_to_check, 1024)) !== false)
		{
			if ($indata == "")
				return "ZSC_LOSTCONNECTION";

			return $indata;
		}
		else
		{
			return "ZSC_LOSTCONNECTION";
		}
	}

	return "ZSC_NOCHANGE";
}

function DoServer( )
{
	error_reporting (E_ALL);
	set_time_limit (0);
	ob_implicit_flush ();


	$socket = socket_create( AF_INET , SOCK_STREAM , SOL_TCP);
	$player_socket = socket_create( AF_INET , SOCK_STREAM , SOL_TCP);
	$unused_socket = socket_create( AF_INET , SOCK_STREAM , SOL_TCP);

	$isbind = socket_bind($socket, "192.168.0.2", 23);

	if (!($isbind))
	{
		print "Error binding.\r\n";
		return 0;
	}

	print "--- Z.S.C. Relay Server: port 23 ---\r\n\r\n";

	socket_listen($socket);

	while (true)
	{
		$newsock = socket_accept($socket);
		if ($newsock)
		{
			socket_getpeername($newsock, $host_from);
			$host_from = $host_from." (".gethostbyaddr($host_from).")";
			print "[CONNECTION] connection from $host_from\r\n";

			$xdata = "";
			for ($indata = "ZSC_NOCHANGE"; ((!strstr($xdata,"\n"))&&($indata != "ZSC_LOSTCONNECTION")); $indata = SocketCheck($newsock))
				if (($indata != "ZSC_LOSTCONNECTION") && ($indata != "ZSC_NOCHANGE"))
					$xdata .= $indata;

			if ($indata == "ZSC_LOSTCONNECTION")
			{
				print "[CONNECTION] lost connection to $host_from\r\n";
				socket_close($newsock);
				continue;
			}

			$indata = $xdata;

			if (strstr($indata, "master end relay"))
			{
				socket_write($newsock, "\r\n--- Z.S.C. Relay Server: shutdown ---\r\n");
				print "\r\n--- Z.S.C. Relay Server: shutdown ---\r\n";
				socket_close($newsock);
				socket_close($socket);
				return 0;
			}

			$szCharacterKey = substr($indata, 0, 32);
			$szGameServiceCode = substr($indata, 33, 3);
			$szGamePort = substr($indata, 37, 5);
			$szGameHost = substr($indata, 43);
			while (strstr($szGameHost, "\r") || strstr($szGameHost, "\n"))
				$szGameHost = substr($szGameHost, 0, strlen($szGameHost) - 1);

			print "[CONNECTION] KEY=$indata";

			if (!strstr($indata, "/FE:"))
			{
				$xdata = "";
				for ($indata = "ZSC_NOCHANGE"; ((!strstr($xdata,"\n"))&&($indata != "ZSC_LOSTCONNECTION")); $indata = SocketCheck($newsock))
					if (($indata != "ZSC_LOSTCONNECTION") && ($indata != "ZSC_NOCHANGE"))
						$xdata .= $indata;

				if ($indata == "ZSC_LOSTCONNECTION")
				{
					print "[CONNECTION] lost connection to $host_from\r\n";
					print "[CONNECTION] had received >$xdata<\r\n";
					socket_close($newsock);
					continue;
				}

				$indata = $xdata;
			}

			$text_out = sprintf("%cGSBZSC-Relay%cGSA0000000000ZSC-Relay\r\n%cGSD\r\n%c---%c %cWelcome to Z.S.C. relay server%c %c---%c\r\n%cGSP\r\n\r\n%c---%c %cRelay will begin momentarily%c %c---%c\r\n\r\n", 28, 28, 28, 139, 160, 143, 160, 139, 160, 28, 139, 160, 143, 160, 139, 160);
			socket_write($newsock, $text_out);

			$xdata = "";
			for ($indata = "ZSC_NOCHANGE"; ((!strstr($xdata,"\n"))&&($indata != "ZSC_LOSTCONNECTION")); $indata = SocketCheck($newsock))
				if (($indata != "ZSC_LOSTCONNECTION") && ($indata != "ZSC_NOCHANGE"))
					$xdata .= $indata;
			if ($indata == "ZSC_LOSTCONNECTION")
			{
				print "[CONNECTION] lost connection to $host_from\r\n";
				socket_close($newsock);
				continue;
			}
			$indata = $xdata;



			///////////////
			//  LOG IN!  //
			///////////////

			$r_ip = $szGameHost;
			$r_hostname = $r_ip; // gethostbyaddr($r_ip);
			if ($r_hostname == $r_ip)
			{
				$r_ip = gethostbyname($r_hostname);
				$r_hostname2 = gethostbyaddr($r_ip);
			}
			else
				$r_hostname2 = $r_hostname;

			print "[CONNECTION] conecting to $r_hostname ($r_ip / $r_hostname2)...\r\n";

			if (!socket_connect($player_socket, $r_ip, $szGamePort))
			{
				print "[CONNECTION] Error: could not establish connection\r\n";
				$text_out = sprintf("\r\n\r\n%c---%c %cRelay session is over.  Goodbye!%c %c---%c\r\n\r\n", 139, 160, 143, 160, 139, 160);
				socket_write($newsock, $text_out);
				print "[CONNECTION] closed connection with $host_from\r\n";
				socket_close($newsock);
			}
			else
			{
				$text_out = sprintf("%s\n", $szCharacterKey);
				socket_write($player_socket, $text_out);
				socket_write($player_socket, "/FE:WIZARD /V:2.03 /P:WIN32\n");

				$shutdown_version = 0;
				$remote_shutdown_version = 0;

				for (;;)
				{
					$indata = SocketCheck($player_socket);
					if ($indata != "ZSC_NOCHANGE")
					{
						if ($indata == "ZSC_LOSTCONNECTION")
						{
							print "[CONNECTION] Connection to $r_hostname lost\r\n";
							$remote_shutdown_version = 5;
							break;
						}
						else
						{
							if ($shutdown_version == 0)
								socket_write($newsock, $indata);
	//						print "[RELAY-GAME] $indata";
						}
					}

					$indata = SocketCheck($newsock);
					if ($indata != "ZSC_NOCHANGE")
					{
						if ($indata == "ZSC_LOSTCONNECTION")
						{
							print "[CONNECTION] Connection to $host_from lost\r\n";
							$shutdown_version = 5;
							break;
						}
						else
						{
							if ($remote_shutdown_version == 0)
								socket_write($player_socket, $indata);
	//						print "[RELAY-PLAYER] $indata";
						}
					}
				}

				if ($remote_shutdown_version != 5)
				{
					socket_write($player_socket, "QUIT\n");
					print "[CONNECTION] closing connection to $r_hostname...\r\n";
				}
				socket_close($player_socket);
				$player_socket = socket_create( AF_INET , SOCK_STREAM , SOL_TCP);

				if ($shutdown_version != 5)
				{
					$text_out = sprintf("\r\n\r\n%c---%c %cRelay session is over.  Goodbye!%c %c---%c\r\n\r\n", 139, 160, 143, 160, 139, 160);
					socket_write($newsock, $text_out);
					print "[CONNECTION] closing connection to $host_from...\r\n";
				}
				socket_close($newsock);
			}
		}
		else
		{
			print "[SYSERR] Error on call to accept().\r\n";
			return 0;
		}
	}

	print "--- This line should never display ---\r\n";
}

DoServer( );

?>
-----script here-----

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2002-09-17 21:24 UTC] iliaa@php.net
Please try using this CVS snapshot:

  http://snaps.php.net/php4-latest.tar.gz
 
For Windows:
 
  http://snaps.php.net/win32/php4-win32-latest.zip


 [2002-10-08 21:42 UTC] sniper@php.net
No feedback was provided. The bug is being suspended because
we assume that you are no longer experiencing the problem.
If this is not the case and you are able to provide the
information that was requested earlier, please do so and
change the status of the bug back to "Open". Thank you.


 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sat Nov 23 10:01:28 2024 UTC