Check if SOCKS4 or 5 in PHP? - php

Basically, I have a list of proxies. I'm wanting to separate them into SOCKS4 and SOCKS5. I'd like to code up a small PHP script to do this for me. How would I go about detecting which type it is in PHP?

You need to write yourself some little code that tries to connect with any of your proxies and inspect the socks version. Connection protocol for the different versions and error codes are documented on the wikipedia page about SOCKS.
Taking that into account, the rest is more or less standard socket connection with PHP.
Example:
$proxies = array( '66.135.131.74:1681', '172.52.61.244:48943',
'75.101.237.217:1080', '76.68.128.165:39879',);
foreach ($proxies as $index => $proxy)
{
$type = SOCKSVersion::getType($proxy);
$typeName = SOCKSVersion::getTypeName($type);
printf("Proxy #%d: %s\n", $index, $typeName);
}
Output:
Proxy #0: SOCKS4
Proxy #1: SOCKS4
Proxy #2: Unknown
Proxy #3: SOCKS4
This exemplary implementation does only check for SOCKS4 so, but it could be easily extended to test as well for SOCK4a and SOCKS5 by adding methods similar to isSocks4():
/**
* SOCKS server identifiation class.
*/
class SOCKSVersion
{
const TYPE_UNKNOWN = 0;
const TYPE_SOCKS4 = 1;
const TYPE_SOCKS4a = 2;
const TYPE_SOCKS5 = 3;
/**
* #var string[]
*/
private static $typeNames = array(
self::TYPE_UNKNOWN => 'Unknown',
self::TYPE_SOCKS4 => 'SOCKS4',
self::TYPE_SOCKS4a => 'SOCKS4a',
self::TYPE_SOCKS5 => 'SOCKS5',
);
/**
* #var int
*/
private $timeout = 30;
/**
* #var int
*/
private $host, $port;
/**
* #var string[]
*/
private $errors;
/**
* #var string[]
*/
private $socks4Errors = array(
91 => "Request rejected or failed",
92 => "Request failed because client is not running identd (or not reachable from the server)",
93 => "Request failed because client's identd could not confirm the user ID string in the request",
);
public function __construct($endpoint)
{
$this->setEndpoint($endpoint);
}
/**
* #static
* #param string $proxy
* #return int any of the TYPE_* constants
*/
public static function getType($proxy)
{
$socks = new self($proxy);
return $socks->getSocksVersion();
}
/**
* #static
* #param int $type
* #return string
*/
public static function getTypeName($type)
{
$typeNames = self::$typeNames;
if (isset($typeNames[$type])) {
return $typeNames[$type];
}
return $typeNames[self::TYPE_UNKNOWN];
}
public function setEndpoint($endpoint)
{
if (!$parts = parse_url('http://' . $endpoint)) {
throw new InvalidArgumentException(sprintf('Unable to parse endpoint "%s".', $endpoint));
}
if (empty($parts['host'])) {
throw new InvalidArgumentException('No host given.');
}
if (empty($parts['port'])) {
throw new InvalidArgumentException('No port given.');
}
$this->host = $parts['host'];
$this->port = $parts['port'];
}
/**
* #return int any of the TYPE_* constants
*/
public function getSocksVersion()
{
try {
if ($this->isSocks4()) {
return self::TYPE_SOCKS4;
}
} catch (BadFunctionCallException $e) {
$this->errors[] = sprintf("SOCKS4 Test: ", $this->host, $e->getMessage());
}
return self::TYPE_UNKNOWN;
}
public function isSocks4()
{
$socket = stream_socket_client("tcp://" . $this->host . ":" . $this->port, $errno, $errstr, $this->timeout, STREAM_CLIENT_CONNECT);
if (!$socket) {
throw new BadFunctionCallException(sprintf('Socket-Error #%d: %s', $errno, $errstr));
}
// SOCKS4; #link <http://en.wikipedia.org/wiki/SOCKS#Protocol>
$userId = "";
$packet = "\x04\x01" . pack("n", $this->port) . pack("H*", dechex(ip2long($this->host))) . $userId . "\0";
fwrite($socket, $packet, strlen($packet));
$response = fread($socket, 9);
if (strlen($response) == 8 && (ord($response[0]) == 0 || ord($response[0]) == 4)) {
$status = ord($response[1]);
if ($status != 90) {
throw new BadFunctionCallException(sprintf("Error from SOCKS4 server: %s.", $this->socks4Errors[$status]));
}
} else {
throw new BadFunctionCallException("The SOCKS server returned an invalid response");
}
fclose($socket);
return TRUE;
}
}
Hope this is helpful. If you introduce multiple versions, you should improve the error handling and don't connect more than once to the same host if the connection failed in a previous test.

I think the best you can do is to first try to establish a CURL connection by trying the highest version - 5.
curl_setopt($curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
This will give you the answer either way. Check curl_error after you execute it. If there is no error, you are using SOCKS5, else you are using SOCKS4.

According to RFC1928, for establishing a SOCKS connection you start by sending these bytes to the server:
1 byte SOCKS version
1 byte Number of authentication methods (n)
n bytes List of method identifiers
And server responds with
1 byte SOCKS version
1 byte Accepted method
This is common between both 4th and 5th versions of SOCKS. So you can start by one version (5, for example) and fall back to another version if server doesn't respond accordingly.

Related

Why socket in object sets to 0

I'm creating a multithreaded server, and i've stucked on this problem. To accept and handle connections i'm using socket_accept, and then creating a Connection object, adding it to array, and then fetching through all array. But for some reason, when i'm doing $connection::read (which does socket_read) the socket in this objects becomes 0. But when object is constructed, everything is fine, dumping socket returns resource, but dumping the same socket in read() throws warnings, because socket is 0. Here some code
ThreadedServer, run()
while ($this->enabled){
foreach ($this->connections as $connection){
/** #var $connection Connection */
$msg = $connection->read(); //here it's already 0, and i'm getting many warnings
if($msg){
//todo
}
}
if (($clientSocket = socket_accept($this->socket))) {
socket_getpeername($clientSocket, $addr, $port);
$this->connections[$hash = self::hash($addr, $port)] = new Connection($clientSocket, $addr, $port, $this);
$this->logger->info("New connection accepted: $hash");
}
}
Connection, in same thread with the ThreadedServer
public function __construct($socket, string $address, int $port, ThreadedServer $server)
{
$this->socket = $socket;
//socket_set_nonblock($this->socket); //not needed?
var_dump($this->socket); //here it returns 'resource'
$this->server = $server;
$this->lastUpdate = microtime(true);
$this->address = $address;
$this->port = $port;
}
public function read(){
var_dump($this->socket); //here it returns 'int (0)'
return socket_read($this->socket, 1024);
}

Is PHP static field real static?

I feel that the PHP static field is static merely throughout a request.
I have this code in my controller class:
static $a = 2;
public function debug()
{
var_dump(self::$a++);
var_dump(self::$a++);
}
No matter how many times I request debug, it outputs:
int 2
int 3
Very different from my knowledge on static in java.
Yes, static in PHP is "real" static.
What you observe is result of different application life cycle in PHP and Java.
In Java, web application run inside WebServer(HTTP server), which after initial class load, on following requests reuse what it already loaded. For this reason class(and static properties) initialization occurs only once in application life cycle.
In case of typical PHP web application it looks a bit different.
HTTP server is independent application which listens for HTTP requests and runs PHP on demand(not all HTTP requests must be passed to PHP).
PHP is run as a separate process, request is passed and after answer is received process is discarded. Every request is handled by completely separate process. Classes(and static properties) are loaded and initialized from scratch every single time.
Below is simple(very) HTTP server written in PHP which will simulate how Java WebServer works.
<?php
class Server {
private $socket;
private $routes = [];
public function __construct($address, $port, $backlog = 5) {
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($socket === false) {
throw new Exception("socket_create() failed: reason: " . socket_strerror(socket_last_error($socket)));
}
if (socket_bind($socket, $address, $port) === false) {
throw new Exception("socket_bind() failed: reason: " . socket_strerror(socket_last_error($socket)));
}
if (socket_listen($socket, $backlog) === false) {
throw new Exception("socket_listen() failed: reason: " . socket_strerror(socket_last_error($socket)));
}
$this->socket = $socket;
}
public function listen() {
while( ($requestSocket = socket_accept($this->socket)) !== false ) {
$this->handleRequestSocket($requestSocket);
}
throw new Exception("socket_accept() failed: reason: " . socket_strerror(socket_last_error($this->socket)));
}
public function registerController($url, $controller) {
$this->routes[$url] = $controller;
}
private function handleRequestSocket($socket) {
$buffer = "";
while(false !== ($part = socket_read($socket, 1024, PHP_NORMAL_READ))){
$buffer .= $part;
if(substr($buffer, -4) == "\r\n\r\n") break;
}
$buffer = trim($buffer);
echo "\n======\n$buffer\n======\n";
$response = $this->handleRequest($buffer);
if (null === $response){
socket_write($socket, "HTTP/1.1 404 Not Found\r\nConnection: close\r\n\r\n");
} else {
socket_write($socket, "HTTP/1.1 200 OK\r\nContent-Length: ".strlen($response)."\r\n\r\n$response");
}
socket_close($socket);
}
private function handleRequest($raw) {
$lines = explode("\r\n", $raw);
$req = explode(" ", $lines[0]);
$method = $req[0];
$url = $req[1];
if(isset($this->routes[$url])) {
return (string) (is_callable($this->routes[$url]) ? $this->routes[$url]($raw) : $this->routes[$url]);
}
return null;
}
}
class ControllerWithStatic {
private static $static = 0;
public function handle() {
return "Hello from static: " . (self::$static++) . "\n";
}
}
$server = new Server($argv[1], $argv[2]);
$c = new ControllerWithStatic();
$server->registerController("/", "Hello world\n");
$server->registerController("/closure", function(){return "Hello world from closure\n";});
$server->registerController("/static", [$c, 'handle']);
$server->registerController("/static2", function(){
return (new ControllerWithStatic())->handle();
});
$server->listen();
Run it using
php server.php HOST PORT
e.g.
php server.php 127.0.0.1 8080
Now open in your browser http://127.0.0.1:8080/static or http://127.0.0.1:8080/static2 and you will get
Hello from static: 0
Hello from static: 1
Hello from static: 2
...
Number will be increasing as long as you don't restart server.

custom error handler: this phpunit test fails. Why? (PHP7)

I'm studying PHP and, meanwhile, writing toy code to understand what I study.
These are my "error and exception handler" functions.
My intention is:
to convert any "old style" PHP error in an Exception
to display the Exception
to log an error message in the syslog
function display_exception($exception)
{
print_r($exception);
}
function log_error_or_exception($error_type, $error_message, $error_number = null, $file_name = null, $line_number = null)
{
$text = 'Message: ' . $error_message . ' - ErrorType: ' . $error_type;
if ($error_number) {
$text .= ' - Error#: ' . $error_number;
}
if ($file_name) {
$text .= ' -> ' . $file_name;
}
if ($line_number) {
$text .= ':' . $line_number;
}
syslog(LOG_ERR, $text);
}
/**
* This function logs any uncaught exception that has been thrown.
* If in the "dev" environment it also displays the Exception
*
* #var Exception $exception
* #return void
*/
function custom_exception_handler($exception)
{
if (ENV == 'dev') {
display_exception($exception);
}
log_error_or_exception(get_class($exception), $exception->getMessage(), $exception->getCode(), $exception->getFile(), $exception->getLine());
}
/**
* This function converts an "old style" PHP Error in an ErrorException
*
* #var int $errno
* #var string $errstr
* #var string|null $errfile
* #var int|null $errline
* #var array $errcontext
* #return false|void
*/
function custom_error_handler(int $errno, string $errstr, string $errfile = null, int $errline = null, array $errcontext = array())
{
// if error_reporting() is false it means that the error was trigger by a line having
// the error control operator "#" so the error should never be displayed.
// Sometimes thought it's convenient to log it
if (!error_reporting()) {
if (ENV == 'dev') {
log_error_or_exception('Error', $errstr, $errno, $errfile, $errline);
}
return false;
}
throw new ErrorException($errstr, $errno, 1, $errfile, $errline);
echo "this should not be displayed";
}
set_exception_handler('custom_exception_handler');
set_error_handler('custom_error_handler');
Now I have an object
<?php
require_once 'app/src/ErrorExceptionHandlers.php';
class Obj
{
public function method($value){
$result = preg_match('/#/', $value);
}
}
If I run this code everything works as expected:
define('ENV', 'dev');
$object = new Obj;
$object->method(array());
I get:
ErrorException Object
(
[message:protected] => preg_match() expects parameter 2 to be string, array given
[string:Exception:private] =>
...
)
If I try to run this phpunit test
<?php
require_once 'app/src/models/obj.php';
define('ENV', 'dev');
class ObjTest extends \PHPUnit_Framework_TestCase
{
/**
* #ExpectedException ErrorException
*/
public function test_method(){
$object = new Obj();
$object->method(array());
}
}
I get:
There was 1 error:
1) ObjTest::test_method
ErrorException: preg_match() expects parameter 2 to be string, array given
Why does the test fail?
So, the annotation names are case sensitive.#ExpectedException should be #expectedException

fgets reading very slow compared to socket_recv

I've been having issues with reading data from a Python socket server. I've tried several methods and have been searching for a solution for months.
The response I am trying to get from the Python socket server is different every time. It can be 40 characters the first time and over 10k characters the next.
I've tried to use socket_recv() and fgets() and so far fgets works the best for what I need, as socket_recv doesn't get the whole response when fgets does. There's just one problem. It's so much slower compared to socket_recv, and doesn't always get the response.
The problem I am having with fgets is that it takes 2.02 seconds to get the response on a local connection, no matter how big or small it is.
I need it to go down, but I can't for the life of me figure out how to fix it..
Connecting to the Python socket server only takes 22ms, so I don't get why it'd take long at all to get the whole reponse.
Oh and if it helps, the response is a JSON string.
Here's the code I use:
/*
* Recieve
*/
public function recv() {
if (!$this->connected()) {
$this->_errorStr = 'Recieve timeout';
$this->_error = true;
return false;
}
$buf = '';
while ($line = fgets($this->_socket)) {
$buf .= $line;
}
return json_decode($buf);
}
And if you need the whole class:
class Sockets {
/*
* Variables
*/
private $_id,
$_name,
$_ip,
$_port,
$_socket,
$_socketTimeout = 1,
$_triedConnect = false,
$_errorStr = '',
$_error = false;
/*
* Construct class
*/
public function __construct($ip, $port) {
$this->_ip = $ip;
$this->_port = $port;
$this->_socket = false;
}
/*
* Send command
*/
public function command($cmd, $json = true) {
if ($json) {
$cmd = json_encode($cmd);
}
if (!$this->send($cmd)) {
return $this->_errorStr;
}
$r = $this->recv();
if (!$r) {
return $this->_errorStr;
}
return $r;
}
/*
* Connect to server
*/
public function connect() {
$this->_error = false;
if ($this->_triedConnect) {
$this->_errorStr = 'Failed to connect.';
$this->_error = true;
return false;
}
$this->_triedConnect = true;
$this->_errorStr = '';
$errno = 0;
$errstr = '';
$this->_socket = #pfsockopen($this->_ip, $this->_port, $errno, $errstr, $this->_socketTimeout);
if (!$this->_socket) {
$this->_errorStr = sprintf('Can\'t connect to server.. (%errno: %errstr)', $errno, $errstr);
$this->_error = true;
$this->_socket = false;
return false;
}
stream_set_timeout($this->_socket, $this->_socketTimeout);
// Clear stream
while ($this->dataReady()) {
if (!fgets($this->_socket)) {
break;
}
}
if (!$this->connected()) {
$this->_errorStr = 'Lost connection to server!';
$this->_error = true;
$this->_socket = false;
return $this->_errorStr;
}
return true;
}
/*
* Authentication
*/
public function auth() {
}
/*
* Connected
*/
public function connected() {
return $this->_socket !== false;
}
/*
* Data ready
*/
public function dataReady() {
if (!$this->connected()) {
return false;
}
return #stream_select($r = array($this->_socket), $w = null, $x = null, 0) > 0;
}
/*
* Send data
*/
public function send($data) {
if (!$this->connected()) {
$this->_errorStr = 'Not connected!';
$this->_error = true;
return false;
}
if (#fwrite($this->_socket, $data) === false) {
$this->_errorStr = 'Failed to send command!';
$this->_error = true;
return false;
}
return true;
}
/*
* Recieve
*/
public function recv() {
if (!$this->connected()) {
$this->_errorStr = 'Recieve timeout';
$this->_error = true;
return false;
}
$buf = '';
while ($line = fgets($this->_socket)) {
$buf .= $line;
}
return json_decode($buf);
}
/*
* Disconnect
*/
public function disconnect() {
if (!$this->connected()) {
return;
}
fclose($this->_socket);
$this->_socket = false;
$this->_triedConnect = false;
}
}
Any help is really appreciated!
EDIT
The machine I am using is running Windows 8.1 Pro, with Media Center.
I am using Python 2.7.9 for the server with the following dependencies installed:
psutil <- https://pypi.python.org/pypi/psutil
colorama <- https://pypi.python.org/pypi/colorama
pycrypto <- http://www.voidspace.org.uk/python/modules.shtml#pycrypto
It shouldn't matter what type of TCP socket server at all. Just a basic one should work just to test this. Even without the dependencies. Something like this works.
For PHP I am using Wamp and PHP 5.5.12 with the following modules enabled:
php_bz2
php_com_dotnet
php_curl
php_exif
php_fileinfo
php_gd2
php_gettext
php_gmp
php_imap
php_intl
php_ldap
php_mbstring
php_mysql
php_mysqli
php_openssl
php_pdo_mysql
php_pdo_sqlite
php_shmop
php_soap
php_sockets
php_sqlite3
php_xmlrpc
php_xsl
Some, if not all of those, are enabled on default.
To test the Sockets class, all you need is to is something like this:
// Import class file
require_once 'Sockets.php';
$socket = new Sockets('127.0.0.1', 21); // Change the port accordingly
// Connect to socket server
$socket->connect();
// Now in my case, the socket server responds to JSON strings, and nothing else.
// So I am going to show you show I send a command.
$command = array(
'key' => 'encrypted key', // This key is to do some validation on the server-side
'command' => 'command' // This is the command to be issued.
);
// Send command to socket server and dump the response
var_dump($socket->command($command));
// To send a plainstring command use this instead
var_dump($socket->command('command here', false));
After quite a lot of debugging and further searching the interwebs and not finding anything, I finally found an answer to my issue.
The issue was with the Python socket server. After sending a command to the socket server, it sends a response back with the requested data. The socket server should then close the connection. And this is where the issue was. It was sending the response, but not closing the connection, so all I had to do was close the connection after every command. The response time went from 2.02 seconds down to 20ms, which is what I wanted.

PHP Socket accept_connection hanging

I recently found out that PHP not only has the fsock* functions, but also functions to create a server itself. I decided to experiment a little bit, and came up with this. Now, the problem is that it hangs on accept_connection() (due to the fact that it's waiting for a connection.) I found out that the solution is to use stream_set_blocking(), which as you can see, I attempted, but to no avail.
I am getting an error message, which reads:
Warning: socket_set_blocking(): supplied resource is not a valid stream resource in /home/insomniaque/workspace/PHP Socket RAT/rat.class.php on line 68
I know that accept_connection() was the problem earlier because when I would connect with a second connection, it would output the data.
<?php
/*
* Project: iRAT
*
* Created on Jan 11, 2010
* Written by Insomniaque
*
*/
class rat
{
/**
* Holds the PHP socket handle for use within the class.
*/
private $socket;
/**
* Holds an array of all the spawned sockets (child sockets) that were
* created when a user connected to the server.
*/
private $spawns = array ();
/**
* Holds the maximum number of connections.
*/
private $maxconn;
/**
* Sets all of the variables required for the class and starts the socket.
* Then it'll start looping, connecting clients and running commands.
*
* #access public
* #param $port The port to bind.
* #param $maxconn The maximum number of client connections.
*/
public function __construct($port = 0, $maxconn = 1)
{
/**
* Check to see if the user has entered 0 as the port, and create a
* random port, if so.
*/
if($port == 0)
$this->port = rand(81, 8079);
else
$this->port = $port;
/**
* Save the maximum connection number.
*/
$this->maxconn = $maxconn;
/**
* Run our function to create the socket now.
*/
if(!$this->createSocket())
{
echo "Failed creating or binding socket.\n";
return false;
}
else
{
echo "Socket has been created and binded.\n";
}
/**
* Turn non-blocking on so we can run multiple clients.
*/
socket_set_blocking($this->socket, 0);
echo "Starting the data receiving loop.\n";
$this->startLoop();
return true;
}
/**
* This function will create the socket for later use.
*
* #access private
* #return bool Returns true if the socket was created successfully,
* returns false if there was an error.
*/
private function createSocket()
{
/**
* Create a socket of IPv4 type using the TCP gateway.
*/
$this->socket = socket_create(AF_INET, SOCK_STREAM, getprotobyname('tcp'));
if(!$this->socket)
return false;
echo "Socket has been created.\n";
/**
* Attempt to bind the socket to localhost:[port]
*/
do
{
if(!isset($i))
$i++;
$port = $this->port;
$bind = socket_bind($this->socket, 0, $port);
if(!$bind)
{
$i++;
$this->port = rand(79, 8079);
}
} while(!$bind && $i <= 5);
if($i == 5)
return false;
echo "Port ".$this->port." has been binded to the RAT.\n";
return true;
}
/**
* Start a loop running on our socket. We will check if we are getting
* data, accept connections and run any commands. When the connection
* is closed, we will return true.
*
* #access private
* #return bool Returns false if the socket can't be listened to. Otherwise
* returns true when the socket is closed.
*/
private function startLoop()
{
if(socket_listen($this->socket, 3))
{
while(true)
{
if(($newspawn = socket_accept($this->socket)) !== false)
{
$this->spawns[] = $newspawn;
echo "A new spawn has connected.";
} else
echo "No new socket";
sleep(1000);
foreach($this->spawns as $key => $spawn)
{
$data = trim(socket_read($spawn, 1024));
if(strlen($data) > 0)
{
if($data == "exit")
{
socket_close($spawn);
unset($this->spawns[$key]);
echo "Spawn killed.\n";
}
if($data == "kill")
{
foreach($this->spawns as $key => $spawn)
{
socket_close($spawn);
unset($this->spawns[$key]);
}
socket_close($this->socket);
echo "Socket closed.\n";
return true;
}
else
{
echo "Data: " . $data . "\n";
}
}
}
}
}
else
{
echo "Failure receiving data.\n";
return false;
}
}
}
?>
Thanks in advance,
John
Use socket_set_nonblock() instead of socket_set_blocking() for a socket resource create by socket_create().
socket_set_blocking() is an alias for
stream_set_blocking() which only works for (php-)streams, like the result of fopen() or stream_socket_create()
edit: You can also use socket_select() or stream_select() to handle both new connections and client data packet, e.g.
private function createSocket()
{
$this->socket = stream_socket_server('tcp://0.0.0.0:'.(int)$this->port, $errno, $errstr);
if(!$this->socket) {
$this->socket = null;
echo "stream_socket_server failed : $errstr ($errno)\n";
return false;
}
echo "Port ".$this->port." has been bound to the RAT.\n";
return true;
}
public function startLoop() {
if ( is_null($this->socket) ) {
return false;
}
$write = array(); $exception=array();
while( !$this->shutdown ) {
// stream_select() alters the array, so $read has to be re-constructed in each iteration somehow
$read = array_merge(array($this->socket), $this->spawns);
// you might want to check $exception as well
if ( 0!==stream_select($read, $write, $exception, 4) ) {
// $now $read only contains those sockets, that will not block
// for fread/accept operations
foreach($read as $s) {
if ( $s===$this->socket ) {
$this->onAccept();
}
else {
$this->onClientPacket($s);
}
}
}
}
$this->shutdown();
}
Keep in mind that if a client sends two commands like e.g.
$fp1 = stream_socket_client("tcp://localhost:81", $errno, $errstr, 30);
fwrite($fp1, "1 blabla");
fwrite($fp1, "exit");
it doesn't necessarily mean your server will get two separate messages.
I believe you would be interested in using stream_socket_create() as opposed to socket_create(), which should return a valid resource to be used with socket_set_blocking().
Note that you will also need to utilize stream_socket_accept() to begin accepting connections on your newly created socket.

Categories