Example #1
0
 public function proxify(\Erebot\URIInterface $proxyURI, \Erebot\URIInterface $nextURI)
 {
     $credentials = $proxyURI->getUserInfo();
     $host = $nextURI->getHost();
     $port = $nextURI->getPort();
     $scheme = $nextURI->getScheme();
     if ($port === null) {
         $port = getservbyname($scheme, 'tcp');
     }
     if (!is_int($port) || $port <= 0 || $port > 65535) {
         throw new \Erebot\InvalidValueException('Invalid port');
     }
     $request = "";
     $request .= sprintf("CONNECT %s:%d HTTP/1.0\r\n", $host, $port);
     $request .= sprintf("Host: %s:%d\r\n", $host, $port);
     $request .= "User-Agent: Erebot/dev-master\r\n";
     if ($credentials !== null) {
         $request .= sprintf("Proxy-Authorization: basic %s\r\n", base64_encode($credentials));
     }
     $request .= "\r\n";
     for ($written = 0, $len = strlen($request); $written < $len; $written += $fwrite) {
         $fwrite = fwrite($this->_socket, substr($request, $written));
         if ($fwrite === false) {
             throw new \Erebot\Exception('Connection closed by proxy');
         }
     }
     $line = stream_get_line($this->_socket, 4096, "\r\n");
     if ($line === false) {
         throw new \Erebot\InvalidValueException('Invalid response from proxy');
     }
     $this->_logger->debug('%(line)s', array('line' => addcslashes($line, "..")));
     $contents = array_filter(explode(" ", $line));
     switch ((int) $contents[1]) {
         case 200:
             break;
         case 407:
             throw new \Erebot\Exception('Proxy authentication required');
         default:
             throw new \Erebot\Exception('Connection rejected by proxy');
     }
     // Avoid an endless loop by limiting the number of headers.
     // No HTTP server is likely to send more than 2^10 headers anyway.
     $max = 1 << 10;
     for ($i = 0; $i < $max; $i++) {
         $line = stream_get_line($this->_socket, 4096, "\r\n");
         if ($line === false) {
             throw new \Erebot\InvalidValueException('Invalid response from proxy');
         }
         if ($line == "") {
             break;
         }
         $this->_logger->debug('%(line)s', array('line' => addcslashes($line, "..")));
     }
     if ($i === $max) {
         throw new \Erebot\InvalidValueException('Endless loop detected in proxy response');
     }
 }
Example #2
0
 public function proxify(\Erebot\URIInterface $proxyURI, \Erebot\URIInterface $nextURI)
 {
     $port = $nextURI->getPort();
     $scheme = $nextURI->getScheme();
     if ($port === null) {
         $port = getservbyname($scheme, 'tcp');
     }
     if (!is_int($port) || $port <= 0 || $port > 65535) {
         throw new \Erebot\InvalidValueException('Invalid port');
     }
     // No authentication or username/password-based authentication.
     $this->write("");
     $line = $this->read(2);
     if ($line[0] != "") {
         throw new \Erebot\InvalidValueException('Bad SOCKS version');
     }
     switch (ord($line[1])) {
         case 0:
             // No authentication
             break;
         case 2:
             // Username/password-based authentication
             $this->userpass($proxyURI);
             break;
         default:
             throw new \Erebot\InvalidValueException('No acceptable method');
     }
     // CONNECT.
     $host = $nextURI->getHost();
     $this->write("" . pack("Ca*n", strlen($host), $host, $port));
     $line = $this->read(4);
     if ($line[0] != "") {
         throw new \Erebot\InvalidValueException('Bad SOCKS version');
     }
     $error = ord($line[1]);
     if ($error) {
         // Taken fromt eh RFC.
         $errors = array(1 => 'General SOCKS server failure', 'Connection not allowed by ruleset', 'Network unreachable', 'Host unreachable', 'Connection refused', 'TTL expired', 'Command not supported', 'Address type not supported');
         if (!isset($errors[$error])) {
             throw new \Erebot\InvalidValueException('Unknown error');
         }
         throw new \Erebot\InvalidValueException($errors[$error]);
     }
     switch (ord($line[3])) {
         case 1:
             // IPv4.
             $this->read(4);
             break;
         case 3:
             // Domain name.
             $len = ord($this->read(1));
             $this->read($len);
             break;
         case 4:
             // IPv6.
             $this->read(16);
             break;
         default:
             throw new \Erebot\InvalidValueException('Address type not supported');
     }
     // Consume the port.
     $this->read(2);
 }