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\$
2
  • \$\begingroup\$ You didn't wrap the code in php tags bro. \$\endgroup\$ Commented Jul 15, 2016 at 1:37
  • \$\begingroup\$ @deeznutsfaggot wow, obvious troll is obvious. \$\endgroup\$ Commented Jul 15, 2016 at 8:09

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.