2
\$\begingroup\$

EDIT

The previous proxy code, after thorough testing, had issues with the stream_copy_to_stream() when sending from $client stream to $dest stream, and vice versa. I have rewritten the code to remedy that issue:

set_time_limit(0); // Run server indefinitely, or until SIGINT (CTRL+c)

$destination = '172.16.12.1:125'; // Where should we connect when client connects to us?
$server_bind = '0.0.0.0:3002'; // Which address:port should we bind to?
// Start the server on address:port
$server = @stream_socket_server("$server_bind", $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN);
if(!$server) die("[ERROR] Failed to bind to $server_bind. Exiting.\r\n");
print_r("[INFO] Listening on $server_bind\r\n");
// Run server forever
while(true) {
    // Wait 10 seconds for client connection
    $client = @stream_socket_accept($server, 10, $peer);
    // If client connects...
    if($client) {
        // ... Set the stream blocking to false
        stream_set_blocking($client, false);
        print_r("[INFO] $peer-<>-$server_bind-<>-$destination-");
        $dest = stream_socket_client($destination, $errno, $errstr, 10, STREAM_CLIENT_CONNECT);
        // If connection to $destination successful...
        if($dest) {
            // ... Set the stream blocking to false
            stream_set_blocking($dest, false);
            // Print successful connection to shell
            print_r("<>-OK\r\n");
            // Fork the connection to child
            $pid = pcntl_fork();
            // die() if fork fails for some reason
            if($pid === -1) die("[ERROR] $peer-<>-$server_bind-<>-$destination-<--Fork failed. Exiting.\r\n");
            // Continue "while(true)" if we are parent
            elseif($pid) continue;
            // If we are child...
            else {
                // ... Loop indefinitely
                while(true) {
                    // Create socket arrays containing $client and $dest
                    $sockets = $w_sockets = [$client, $dest];
                    // If either side disconnects, shutdown both streams
                    if(feof($client) || feof($dest)) {
                        print_r("[INFO] $peer-<>-$server_bind-<>-$destination-<>-Disconnect\r\n");
                        foreach($sockets as $id => $stream) stream_socket_shutdown($stream, STREAM_SHUT_RDWR);
                        // Break from this "while(true)" to exit(0)
                        break;
                    }
                    // Block until either stream updates its read status
                    stream_select($sockets, $w = NULL, $e = NULL, NULL);
                    // Block until either stream updates its write stats
                    stream_select($r = NULL, $w_sockets, $e = NULL, NULL);
                    // ... run ternary conditional to determine which stream to copy from/to
                    // If $client stream updated and $dest stream writable, copy its contents to $dest, otherwise copy $dest contents to $client
                    in_array($client, $sockets) && in_array($dest, $w_sockets) ? stream_copy_to_stream($client, $dest, 1024) : stream_copy_to_stream($dest, $client, 1024);

                }
                // Exit child process after $client/$dest disconnect
                exit(0);
            }
        }
        // If connection to $destination fails...
        else {
            // ... print the failure
            print_r("<--FAIL\r\n");
            // Tell client of failure
            fwrite($client, "Connection to $destination failed. You are being disconnected.\r\n");
            // Shutdown $client stream
            stream_socket_shutdown($client, STREAM_SHUT_RDWR);
            // Break from first "while(true)" to EOF
            break;
        }
    }
}

With the use of pcntl_fork(), this cannot work on Windows. I'm not as well-versed in PHP sockets as I'd like, and would like to make a version of this that can work on Windows in the same fashion (i.e. accept multiple simultaneous connections). What modifications can/must I make in order to produce a copy that would work on Windows as well?

In a fit of spontaneity, I wrote a quick-n-dirty TCP proxy in PHP:

set_time_limit(0); // Run server indefinitely, or until SIGINT (CTRL+c)

$destination = '127.0.0.1:25'; // Where should we connect when client connects to us?
$server_addr = '0.0.0.0'; // Which address should we bind to?
$server_port = '3002'; // Which port should we bind to?
// Start the server on address:port
$server = @stream_socket_server("$server_addr:$server_port", $errno, $errstr);
// Run server forever
while(true) {
    // Wait 10 seconds for client connection
    $client = @stream_socket_accept($server, 10, $peer);
    // If client connects...
    if($client) {
        // ... Set the stream blocking to false
        stream_set_blocking($client, false);
        // Attempt connection to $destination
        $dest = @stream_socket_client($destination, $errno, $errstr, 10);
        // If connection to $destination successful...
        if($dest) {
            // ... Set the stream blocking to false
            stream_set_blocking($dest, false);
            // Print successful connection to shell
            print_r("[CONNECT] $peer-<><>-$destination\r\n");
            // Fork the connection to child
            $pid = pcntl_fork();
            // die() if fork fails for some reason
            if($pid === -1) die("[ERROR] Unable to fork connection. Exiting.\r\n");
            // Continue "while(true)" if we are parent
            elseif($pid) continue;
            // If we are child...
            else {
                // ... Loop indefinitely
                while(true) {
                    // Create socket array for $client and $dest
                    $sockets = [$client, $dest];
                    // If either side disconnects, shutdown both streams
                    if(feof($client) || feof($dest)) {
                        print_r("[DISCONNECT] $peer-<><>-$destination\r\n");
                        for($i = 0; $i < count($sockets); $i++) stream_socket_shutdown($sockets[$i], STREAM_SHUT_RDWR);
                        // Break from this "while(true)" to exit(0)
                        break;
                    }
                    // EDIT: removed tv_usec parameter to block until either stream updates
                    // Only run in_array() ternary conditional if stream_select() returns "truthy" value
                    if(stream_select($sockets, $w = NULL, $e = NULL, NULL))
                        // If $client stream updated, copy its contents to $dest.
                        // Otherwise copy $dest contents to $client
                        in_array($client, $sockets) ? stream_copy_to_stream($client, $dest) : stream_copy_to_stream($dest, $client);
                }
                // Exit child process after $client/$dest disconnect
                exit(0);
            }
        }
        // If connection to $destination fails...
        else {
            // ... print the failure
            print_r("[FAIL] $peer-<><>-$destination\r\n");
            // Shutdown $client stream
            stream_socket_shutdown($client, STREAM_SHUT_RDWR);
            // Break from first "while(true)" to EOF
            break;
        }
    }
}

\$\endgroup\$
  • \$\begingroup\$ You didn't wrap the code in php tags bro. \$\endgroup\$ – user111451 Jul 15 '16 at 1:37
  • \$\begingroup\$ @deeznutsfaggot wow, obvious troll is obvious. \$\endgroup\$ – ʰᵈˑ Jul 15 '16 at 8:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.