* @author Dominique Stender * @copyright Copyright (c) 2005-2006 Paul Sullivan, Dominique Stender - http://sf.net/projects/cpaint * @version $id: cpaint2.proxy.php 317 2006-09-30 08:42:04Z saloon12yrd $ */ //---- includes ---------------------------------------------------------------- /** * include configuration file */ require_once(dirname(__FILE__) . '/cpaint2.config.php'); //---- functions --------------------------------------------------------------- /** * Similar to PHP's builtin parse_url() function, but makes sure what the schema, * path and port keys are set to http, /, 80 respectively if they're missing * * @access public * @param string $raw_url Raw URL to be split into an array * @return array */ function parse_url_clean($raw_url) { $retval = array(); $raw_url = (string) $raw_url; // make sure parse_url() recognizes the URL correctly. if (strpos($raw_url, '://') === false) { $raw_url = 'http://' . $raw_url; } // end: if // split request into array $retval = parse_url($raw_url); // make sure a path key exists if (!isset($retval['path'])) { $retval['path'] = '/'; } // end: if // set port to 80 if none exists if (!isset($retval['port'])) { $retval['port'] = '80'; } // end: if return $retval; } /** * Performs a check of the URL to be requested against the whitelist. * * Returns true if the URL in question if allowed, false otherwise. * Expects an array generated by PHP's parse_url() function as input parameter. * * @access public * @param array $request_parts The URL in question. * @return boolean */ function whitelist_check($request_parts) { global $cpaint2_proxy_whitelist; $retval = false; $request_check = ''; $whitelist_url = ''; $whitelist_parts = array(); $whitelist_check = ''; // iterate over all URLs within the whitelist foreach($cpaint2_proxy_whitelist as $whitelist_url) { $whitelist_parts = parse_url_clean($whitelist_url); if (array_key_exists('path', $whitelist_parts)) { // perform a check of host and path if path is part of the whitelist entry $whitelist_check = $whitelist_parts['host'] . $whitelist_parts['path']; $request_check = $request_parts['host'] . $request_parts['path']; } else { // compare only the hosts, path is not part of the whitelist entry $whitelist_check = $whitelist_parts['host']; $request_check = $request_parts['host']; } // end: if // check if whitelist check string marks the beginning of the request check string if (strpos($request_check, $whitelist_check) === 0) { $retval = true; break; } // end: if } // end: foreach return $retval; } //---- variables --------------------------------------------------------------- $http_response = ''; $request_allowed = false; $cp_socket = false; $stream_timeout_s = floor($cpaint2_config['proxy']['stream_timeout'] / 1000); $stream_timeout_ms = $cpaint2_config['proxy']['stream_timeout'] - $stream_timeout_s * 1000; $stream_meta = array(); $cp_remote_url = ''; $cp_remote_method = ''; $cp_remote_query = ''; $cp_response_type = ''; $cp_request_body = ''; $cp_request_header = ''; $url_parts = array(); //---- main code --------------------------------------------------------------- // alter PHP's error reporting setting if set if ($cpaint2_config['proxy']['security']['error_reporting'] != '') { error_reporting($cpaint2_config['proxy']['security']['error_reporting']); } // end: if // alter maximum runtime according to configuration if ($cpaint2_config['proxy']['time_limit'] != -1) { set_time_limit($cpaint2_config['proxy']['time_limit']); } // end: if // determine which method to use (fsockopen or CURL) $curl_exists = function_exists('curl_init'); $fsock_exists = function_exists('fsockopen'); // check to see if use_curl option is set and within range // if not, default to 0 (use fsockopen) if ((!isset($cpaint2_config['proxy']['use_curl'])) || ($cpaint2_config['proxy']['use_curl'] < 0) || ($cpaint2_config['proxy']['use_curl'] > 3)) { $cpaint2_config['proxy']['use_curl'] = 0; } if ((!$fsock_exists && $cpaint2_config['proxy']['use_curl'] == 0) || (!$curl_exists && $cpaint2_config['proxy']['use_curl'] == 1)) { die('[CPAINT] No method available for connecting to remote server'); } if ($cpaint2_config['proxy']['use_curl'] == 0) $use_fsock = true; if ($cpaint2_config['proxy']['use_curl'] == 1) $use_fsock = false; if ($cpaint2_config['proxy']['use_curl'] == 2) $use_fsock = $fsock_exists; if ($cpaint2_config['proxy']['use_curl'] == 3) $use_fsock = $curl_exists; if ($_REQUEST['cpaint_remote_url'] != '') { $cp_remote_url = urldecode($_REQUEST['cpaint_remote_url']); $cp_remote_method = urldecode($_REQUEST['cpaint_remote_method']); $cp_remote_query = urldecode($_REQUEST['cpaint_remote_query']); $cp_response_type = strtoupper($_REQUEST['cpaint_response_type']); } // end: if // propagate XML header if necessary if ($cp_response_type == 'XML' || $cp_response_type == 'OBJECT') { header('Content-type: text/xml'); } // end: if // start build HTTP headers if ($cp_remote_method == 'GET') { $cp_remote_url .= '?' . $cp_remote_query; // prepare parameters $url_parts = parse_url_clean($cp_remote_url); if ($use_fsock) { // build basic header $cp_request_header = 'GET ' . $url_parts['path'] . '?' . str_replace(' ', '+', $url_parts['query']) . " HTTP/1.0\r\n" . 'Host: ' . $url_parts['host'] . "\r\n"; } else { $curl['url'] = $url_parts['path'] . '?' . str_replace(' ', '+', $url_parts['query']); $curl['header'][] = 'Host: ' . $url_parts['host'] . "\r\n"; } } elseif ($cp_remote_method == 'POST') { $cp_request_body = '&' . $cp_remote_query; // prepare parameters $url_parts = parse_url_clean($cp_remote_url); if ($use_fsock) { // build basic header $cp_request_header = 'POST ' . $url_parts['path'] . " HTTP/1.0\r\n" . 'Host: ' . $url_parts['host'] . "\r\n" . "Content-Type: application/x-www-form-urlencoded\r\n"; } else { $curl['url'] = $url_parts['path']; $curl['header'][] = 'Host: ' . $url_parts['host'] . "\r\n"; } } // end: if $content_length_header = 'Content-Length: ' . strlen($cp_request_body) . "\r\n"; if ($use_fsock) { // add content-length header $cp_request_header .= $content_length_header; } else { $curl['header'][] = $content_length_header; } // add authentication to header if necessary if (isset($url_parts['user']) && $url_parts['user'] != '') { if ($use_fsock) { $cp_request_header .= 'Authorization: Basic ' . base64_encode($url_parts['user'] . ':' . $url_parts['pass']) . "\r\n"; } else { $curl['userauth'] = $url_parts['user'] . ':' . $url_parts['pass']; } } // end: if // perform a check against the whitelist if necessary if ($cpaint2_config['proxy']['security']['use_whitelist'] == true) { $request_allowed = whitelist_check($url_parts); } else { // whitelist is disabled, allow any request $request_allowed = true; } // end: if if ($request_allowed == true) { if ($use_fsock) { // open connection $cp_socket = @fsockopen($url_parts['host'], $url_parts['port'], $error, $errstr, $cpaint2_config['proxy']['connect_timeout']); if ($cp_socket !== false) { // send headers @fwrite($cp_socket, $cp_request_header . "\r\n\r\n"); // send body if necessary if ($cp_request_body != '') { @fwrite($cp_socket, $cp_request_body . "\r\n"); } // end: if // set stream timeout if ($cpaint2_config['proxy']['stream_timeout'] > -1) { stream_set_timeout($cp_socket, $stream_timeout_s, $stream_timeout_ms); } // end: if while (!feof($cp_socket)) { $http_response .= fgets($cp_socket); } // end: while // check whether the request has timed out. $stream_meta = stream_get_meta_data($cp_socket); if ($stream_meta['timed_out'] == false) { list($http_headers, $http_body) = split("\r\n\r\n", $http_response, 2); echo($http_body); } else { die('[CPAINT] The request ran into a timeout.'); } // end: if @fclose($cp_socket); } // end: if } else { // use curl $curl_session = curl_init(); curl_setopt($curl_session, CURLOPT_URL, $curl['url']); curl_setopt($curl_session, CURLOPT_HEADER, false); curl_setopt($curl_session, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); curl_setopt($curl_session, CURLOPT_FORBID_REUSE, true); if (isset($curl['header'])) { curl_setopt($curl_session, CURLOPT_HTTPHEADER, $curl['header']); } // end: if if (isset($curl['userauth'])) { curl_setopt($curl_session, CURLOPT_USERPWD, $curl['userauth']); curl_setopt($curl_session, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); } // end: if if ($cp_remote_method == 'GET') { curl_setopt($curl_session, CURLOPT_GET, true); } // end: if if ($cp_remote_method == 'POST') { curl_setopt($curl_session, CURLOPT_GET, false); curl_setopt($curl_session, CURLOPT_POST, true); curl_setopt($curl_session, CURLOPT_POSTFIELDS, $cp_request_body); } // end: if if ($cpaint2_config['proxy']['connect_timeout'] > -1) { curl_setopt($curl_session, CURLOPT_CONNECTTIMEOUT, $cpaint2_config['proxy']['connect_timeout']); } // end: if if ($cpaint2_config['proxy']['stream_timeout'] > -1) { curl_setopt($curl_session, CURLOPT_TIMEOUT, $stream_timeout_s); } // end: if curl_exec($curl_session); if (curl_errno($curl_session) != 0) { die('[CPAINT] CURL experienced the error "' . curl_error($curl_session) . '"'); } // end: if curl_close($curl_session); } } else { die('[CPAINT] The host or script cannot be accessed through this proxy.'); } // end: if ?>