caterpillar/assets/php/index.php

452 lines
14 KiB
PHP
Raw Normal View History

2022-10-05 17:20:02 +00:00
<?php
2024-03-05 07:35:48 +00:00
/* index.php
* Caterpillar Worker on PHP
*
* Caterpillar Proxy - The simple and parasitic web proxy with spam filter
* Namhyeon Go (Catswords Research) <abuse@catswords.net>
* https://github.com/gnh1201/caterpillar
* Created at: 2022-10-06
* Updated at: 2024-03-05
*/
2022-10-05 17:20:02 +00:00
2024-02-26 13:17:52 +00:00
define("PHP_HTTPPROXY_VERSION", "0.1.5");
2024-03-04 07:29:48 +00:00
define("DEFAULT_SOCKET_TIMEOUT", 1);
define("STATEFUL_SOCKET_TIMEOUT", 30);
define("MAX_EXECUTION_TIME", 0);
2022-11-25 12:37:34 +00:00
2024-02-20 02:46:26 +00:00
if (strpos($_SERVER['HTTP_USER_AGENT'], "php-httpproxy/") !== 0) {
2024-02-29 14:10:53 +00:00
exit('<!DOCTYPE html><html><head><title>It works!</title><meta charset="utf-8"></head><body><h1>It works!</h1><p><a href="https://github.com/gnh1201/caterpillar">Download the client</a></p><hr><p>php-httpproxy/' . PHP_HTTPPROXY_VERSION . ' (Server; PHP ' . phpversion() . '; Caterpillar; abuse@catswords.net)</p></body></html>');
2022-10-07 04:48:58 +00:00
}
2024-03-04 07:29:48 +00:00
ini_set("default_socket_timeout", DEFAULT_SOCKET_TIMEOUT); // must be. because of `feof()` works
ini_set("max_execution_time", MAX_EXECUTION_TIME);
2022-10-05 17:20:02 +00:00
2024-02-26 06:04:51 +00:00
function jsonrpc2_encode($method, $params, $id = '') {
2024-02-26 04:55:22 +00:00
$data = array(
"jsonrpc" => "2.0",
2024-02-26 06:04:51 +00:00
"method" => $method,
"params" => $params,
"id" => $id
2024-02-26 04:55:22 +00:00
);
return json_encode($data);
}
2024-02-26 06:04:51 +00:00
function jsonrpc2_result_encode($result, $id = '') {
2024-02-26 04:55:22 +00:00
$data = array(
"jsonrpc" => "2.0",
2024-02-26 06:04:51 +00:00
"result" => $result,
"id" => $id
2024-02-26 04:55:22 +00:00
);
return json_encode($data);
}
2024-02-26 06:04:51 +00:00
function jsonrpc2_error_encode($error, $id = '') {
2024-02-26 04:49:14 +00:00
$data = array(
"jsonrpc" => "2.0",
2024-02-26 06:04:51 +00:00
"error" => $error,
"id" => $id
2024-02-26 04:49:14 +00:00
);
return json_encode($data);
}
2022-10-06 12:03:05 +00:00
function parse_headers($str) { // Parses HTTP headers into an array
2022-10-06 12:48:49 +00:00
// https://stackoverflow.com/questions/16934409/curl-as-proxy-deal-with-https-connect-method
// https://stackoverflow.com/questions/12433958/how-to-parse-response-headers-in-php
2022-10-06 12:03:05 +00:00
$headers = array();
2022-10-05 17:20:02 +00:00
2022-10-06 12:03:05 +00:00
$lines = preg_split("'\r?\n'", $str);
2022-10-06 02:05:59 +00:00
2022-10-06 12:03:05 +00:00
$first_line = array_shift($lines);
$headers['@method'] = explode(' ', $first_line);
2022-10-06 02:39:40 +00:00
2022-10-06 12:03:05 +00:00
foreach ($lines as $line) {
if (!preg_match('/^([^:]+):(.*)$/', $line, $out)) continue;
$headers[$out[1]] = trim($out[2]);
}
2022-10-05 17:20:02 +00:00
2022-10-06 12:03:05 +00:00
return $headers;
}
2022-10-05 17:20:02 +00:00
2024-02-26 06:57:28 +00:00
function read_from_remote_server($remote_address, $remote_port, $scheme, $data = null, $conn = null, $buffer_size = 8192, $id = '') {
2024-02-26 05:52:50 +00:00
if (in_array($scheme, array("https", "ssl", "tls"))) {
$remote_address = "tls://" . $remote_address;
}
2024-03-04 07:29:48 +00:00
$sock = fsockopen($remote_address, $remote_port, $error_code, $error_message, DEFAULT_SOCKET_TIMEOUT);
2024-02-26 05:50:20 +00:00
if (!$sock) {
$error = array(
2024-02-26 06:44:38 +00:00
"status" => 502,
2024-02-26 05:50:20 +00:00
"code" => $error_code,
2024-02-26 13:06:55 +00:00
"message" => $error_message
2024-02-26 05:50:20 +00:00
);
if ($conn == null) {
2024-02-26 06:44:38 +00:00
echo jsonrpc2_error_encode($error, $id);
2024-02-26 05:50:20 +00:00
} else {
2024-02-26 13:06:55 +00:00
$buf = sprintf("HTTP/1.1 502 Bad Gateway\r\n\r\n");
2024-02-26 06:48:39 +00:00
$buf .= jsonrpc2_error_encode($error, $id);
2024-02-26 05:50:20 +00:00
fwrite($conn, $buf);
}
} else {
2024-02-26 06:57:28 +00:00
if ($conn == null) {
// send data
fwrite($sock, $data);
2024-02-26 05:50:20 +00:00
2024-02-26 06:57:28 +00:00
// receive data
$buf = null;
while (!feof($sock) && $buf !== false) {
$buf = fgets($sock, $buffer_size);
2024-02-26 05:50:20 +00:00
echo $buf;
2024-02-26 06:57:28 +00:00
}
} else {
// send data
$buf = null;
while (!feof($conn) && $buf !== false) {
$buf = fgets($conn, $buffer_size);
fwrite($sock, $buf);
}
// receive data
$buf = null;
while (!feof($sock) && $buf !== false) {
$buf = fgets($sock, $buffer_size);
2024-02-26 05:50:20 +00:00
fwrite($conn, $buf);
}
}
fclose($sock);
}
}
2024-02-25 17:51:08 +00:00
// stateless mode
2024-02-26 06:04:51 +00:00
function relay_request($params, $id = '') {
2024-02-26 04:49:14 +00:00
$buffer_size = $params['buffer_size'];
2024-02-26 05:12:57 +00:00
$request_data = base64_decode($params['request_data']);
$request_header = parse_headers($request_data);
$request_length = intval($params['request_length']);
2024-02-26 04:49:14 +00:00
$client_address = $params['client_address'];
$client_port = intval($params['client_port']);
$client_encoding = $params['client_encoding'];
$remote_address = $params['remote_address'];
$remote_port = intval($params['remote_port']);
$scheme = $params['scheme'];
$datetime = $params['datetime']; // format: %Y-%m-%d %H:%M:%S.%f
if (in_array($scheme, array("https", "ssl", "tls"))) {
$remote_address = "tls://" . $remote_address;
2024-02-25 17:51:08 +00:00
}
2024-02-26 04:49:14 +00:00
2024-02-26 05:12:57 +00:00
switch ($request_header['@method'][0]) {
2024-02-25 17:51:08 +00:00
case "CONNECT":
2024-02-26 06:44:38 +00:00
$error = array(
"status" => 405,
"code" => -1,
"message" => "Method Not Allowed"
);
echo jsonrpc2_error_encode($error, $id);
2024-02-25 17:51:08 +00:00
break;
2024-02-26 04:49:14 +00:00
2024-02-25 17:51:08 +00:00
default:
2024-02-26 06:57:28 +00:00
read_from_remote_server($remote_address, $remote_port, $scheme, $request_data, null, $buffer_size, $id);
2024-02-25 17:51:08 +00:00
}
2022-11-25 10:32:17 +00:00
}
2024-02-25 17:51:08 +00:00
// stateful mode
2024-02-26 06:04:51 +00:00
function relay_connect($params, $id = '') {
2024-02-26 04:49:14 +00:00
$buffer_size = $params['buffer_size'];
$client_address = $params['client_address'];
$client_port = intval($params['client_port']);
$client_encoding = $params['client_encoding'];
$remote_address = $params['remote_address'];
$remote_port = intval($params['remote_port']);
$scheme = $params['scheme'];
$datetime = $params['datetime']; // format: %Y-%m-%d %H:%M:%S.%f
2024-02-27 04:40:16 +00:00
$starttime = microtime(true);
2024-03-04 07:29:48 +00:00
$conn = fsockopen($client_address, $client_port, $error_code, $error_message, STATEFUL_SOCKET_TIMEOUT);
2024-02-26 05:50:20 +00:00
if (!$conn) {
2024-02-26 04:49:14 +00:00
$error = array(
2024-02-26 06:44:38 +00:00
"status" => 502,
2024-02-26 04:49:14 +00:00
"code" => $error_code,
2024-02-26 13:06:55 +00:00
"message" => $error_message,
"_params" => $params
2024-02-26 04:49:14 +00:00
);
2024-02-26 06:44:38 +00:00
echo jsonrpc2_error_encode($error, $id);
2024-02-26 04:49:14 +00:00
} else {
2024-02-27 04:40:16 +00:00
$stoptime = microtime(true);
$connection_speed = floor(($stoptime - $starttime) * 1000);
2024-02-26 07:27:49 +00:00
$data = jsonrpc2_encode("relay_accept", array(
2024-02-27 04:40:16 +00:00
"success" => true,
"connection_speed" => $connection_speed
2024-02-26 07:27:49 +00:00
), $id);
fwrite($conn, $data . "\r\n\r\n");
2024-02-26 06:57:28 +00:00
read_from_remote_server($remote_address, $remote_port, $scheme, null, $conn, $buffer_size, $id);
2024-02-26 05:50:20 +00:00
fclose($conn);
2024-02-26 04:49:14 +00:00
}
2024-02-25 17:51:08 +00:00
}
2022-10-06 12:03:05 +00:00
2024-02-27 04:40:16 +00:00
function relay_mysql_connect($params) {
$hostname = $params['hostname'];
$username = $params['username'];
$password = $params['password'];
$database = $params['database'];
$port = array_key_exists('port', $params) ? intval($params['port']) : null;
2024-02-27 08:33:15 +00:00
$charset = array_key_exists('charset', $params) ? $params['charset'] : "utf8";
2024-02-27 04:40:16 +00:00
$mysqli = new mysqli($hostname, $username, $password, $database, $port);
if ($mysqli->connect_errno) {
return array(
"success" => false,
"error" => array(
"status" => 503,
"code" => $mysqli->connect_errno,
"message" => $mysqli->connect_error
)
);
} else {
2024-02-27 08:33:15 +00:00
$mysqli->set_charset($charset);
2024-02-27 04:40:16 +00:00
}
return array(
"success" => true,
"mysqli" => $mysqli,
"result" => array(
"status" => 200
)
);
}
function relay_mysql_query($params, $mysqli) {
$query = trim($params['query']);
$query_type = ""; // e.g., select, insert, update, delete
$pos = strpos($query, ' ');
if ($pos !== false) {
$query_type = strtolower(substr($query, 0, $pos));
}
2024-02-29 08:54:36 +00:00
$query_result = $mysqli->query($query);
2024-02-27 04:40:16 +00:00
if (!$mysqli->error) {
return array(
"success" => false,
"error" => array(
"status" => 503,
"code" => $msqli->errno,
"message" => $mysqli->error
)
);
}
2024-02-29 08:54:36 +00:00
$success = false;
$result = array(
"status" => 200
);
2024-02-29 07:36:05 +00:00
switch($query_type) {
case "select":
2024-02-29 08:54:36 +00:00
$success = true;
$result['data'] = mysqli_fetch_all($query_result, MYSQLI_ASSOC);
2024-02-29 07:36:05 +00:00
break;
case "insert":
2024-02-29 08:54:36 +00:00
$success = $query_result;
2024-02-29 09:39:43 +00:00
$result['last_id'] = @$mysqli->insert_id();
2024-02-29 07:36:05 +00:00
break;
default:
2024-02-29 08:54:36 +00:00
$success = $query_result;
2024-02-27 04:40:16 +00:00
}
return array(
2024-02-29 08:54:36 +00:00
"success" => $success,
"result" => $result
2024-02-27 04:40:16 +00:00
);
}
2024-02-27 05:52:52 +00:00
function relay_sendmail($params) {
$to = $params['to'];
$from = $params['from'];
$subject = $params['subject'];
$message = $params['message'];
$headers = 'From: ' . $from . "\r\n" .
2024-02-29 19:43:54 +00:00
'X-Mailer: php-httpproxy/' . PHP_HTTPPROXY_VERSION . ' (Server; PHP ' . phpversion() . '; Caterpillar)';
2024-02-29 07:36:05 +00:00
$sent = @mail($to, $subject, $message, $headers);
2024-02-27 05:52:52 +00:00
if (!$sent) {
$e = error_get_last();
return array(
"success" => false,
"error" => array(
"status" => 500,
"code" => $e['type'],
"message" => $e['message']
)
);
}
return array(
"success" => true,
"result" => array(
"status" => 200
)
);
}
2024-02-27 05:20:14 +00:00
function relay_get_version() {
2024-02-27 08:33:15 +00:00
return PHP_HTTPPROXY_VERSION;
2024-02-27 04:40:16 +00:00
}
2024-02-27 05:20:14 +00:00
function relay_get_phpversion() {
2024-02-27 08:33:15 +00:00
return phpversion();
2024-02-27 05:20:14 +00:00
}
function relay_get_loaded_extensions() {
2024-02-27 08:33:15 +00:00
return get_loaded_extensions();
2024-02-27 05:20:14 +00:00
}
2024-02-27 06:38:17 +00:00
function relay_dns_get_record($params) {
$hostname = $params['hostname'];
2024-02-27 06:50:24 +00:00
$data = dns_get_record($hostname);
if (!$data) {
return array(
"success" => false,
"error" => array(
"status" => 502,
"code" => -1,
"message" => $hostname . " is not found in DNS records"
)
2024-02-27 06:50:58 +00:00
);
2024-02-27 06:50:24 +00:00
}
return array(
"success" => true,
"result" => array(
"status" => 200,
"data" => $data
)
2024-02-27 06:50:58 +00:00
);
2024-02-27 06:38:17 +00:00
}
2024-02-27 06:27:08 +00:00
function relay_get_geolocation() {
$url = "https://ipapi.co/json/";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
2024-02-27 08:21:27 +00:00
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 1);
2024-02-27 06:27:08 +00:00
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$response = curl_exec($ch);
$error_code = curl_errno($ch);
if ($error_code) {
$error_message = curl_error($ch);
curl_close($ch);
return array(
"success" => false,
"error" => array(
"status" => 502,
"code" => $error_code,
"message" => $error_message
)
);
}
curl_close($ch);
$data = json_decode($response, true);
return array(
"success" => true,
"result" => array(
"status" => 200,
"data" => $data
)
);
}
2024-02-26 13:06:55 +00:00
function get_client_address() {
$client_address = '';
if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
$client_address = $_SERVER['HTTP_CLIENT_IP'];
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$client_address = $_SERVER['HTTP_X_FORWARDED_FOR'];
} else {
$client_address = $_SERVER['REMOTE_ADDR'];
}
return array("client_address" => $client_address);
}
2024-02-27 04:40:16 +00:00
// parse a context
2024-02-29 14:10:53 +00:00
$context = json_decode(file_get_contents('php://input'), true);
2024-02-25 17:51:08 +00:00
2024-02-29 08:38:03 +00:00
// check is it JSON-RPC 2 (stateless)
2024-02-25 17:51:08 +00:00
if ($context['jsonrpc'] == "2.0") {
$method = $context['method'];
switch ($method) {
case "relay_request":
2024-02-26 06:04:51 +00:00
relay_request($context['params'], $context['id']); // stateless mode
2024-02-25 17:51:08 +00:00
break;
2024-02-26 13:06:55 +00:00
2024-02-25 17:51:08 +00:00
case "relay_connect":
2024-02-26 06:04:51 +00:00
relay_connect($context['params'], $context['id']); // stateful mode
2024-02-25 17:51:08 +00:00
break;
2024-02-26 13:06:55 +00:00
2024-02-27 04:40:16 +00:00
case "relay_mysql_query":
$result = relay_mysql_connect($context['params']);
if ($result['success']) {
$mysqli = $result['mysqli'];
$query_result = relay_mysql_query($context['params'], $mysqli);
if ($query_result['success']) {
echo jsonrpc2_result_encode($query_result['result'], $context['id']);
} else {
echo jsonrpc2_error_encode($query_result['error'], $context['id']);
}
} else {
echo jsonrpc2_error_encode($result['error'], $context['id']);
}
break;
2024-02-27 05:52:52 +00:00
case "relay_sendmail":
$result = relay_sendmail($context['params']);
if ($result['success']) {
echo jsonrpc2_result_encode($result['result'], $context['id']);
} else {
echo jsonrpc2_error_encode($result['error'], $context['id']);
}
break;
2024-02-27 05:20:14 +00:00
case "relay_get_version":
echo jsonrpc2_result_encode(relay_get_version(), $context['id']);
break;
case "relay_get_phpversion":
echo jsonrpc2_result_encode(relay_get_phpversion(), $context['id']);
break;
case "relay_get_loaded_extensions":
echo jsonrpc2_result_encode(relay_get_loaded_extensions(), $context['id']);
2024-02-27 04:40:16 +00:00
break;
2024-02-27 06:27:08 +00:00
2024-02-27 06:38:17 +00:00
case "relay_dns_get_record":
2024-02-27 06:50:24 +00:00
$result = relay_dns_get_record($context['params']);
if ($result['success']) {
echo jsonrpc2_result_encode($result['result'], $context['id']);
} else {
echo jsonrpc2_error_encode($result['error'], $context['id']);
}
2024-02-27 06:38:17 +00:00
break;
2024-02-27 06:27:08 +00:00
case "relay_get_geolocation":
2024-02-27 06:50:24 +00:00
$result = relay_get_geolocation();
2024-02-27 06:27:08 +00:00
if ($result['success']) {
echo jsonrpc2_result_encode($result['result'], $context['id']);
} else {
echo jsonrpc2_error_encode($result['error'], $context['id']);
}
break;
2024-02-27 04:40:16 +00:00
2024-02-26 13:06:55 +00:00
case "get_client_address":
echo jsonrpc2_result_encode(get_client_address(), $context['id']);
break;
2024-02-25 17:51:08 +00:00
}
2024-02-17 09:54:31 +00:00
}
2024-02-29 08:38:03 +00:00