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'); } }
/** * Does the authentication step. * * \param Erebot::URIInterface $proxyURI * An object representing the URI of this SOCKS proxy server, * containing the credentials that will be sent during the * authentication step. */ protected function userpass(\Erebot\URIInterface $proxyURI) { $username = $proxyURI->asParsedURL(PHP_URL_USER); $password = $proxyURI->asParsedURL(PHP_URL_PASS); if ($username === null || $password === null) { throw new \Erebot\InvalidValueException('No username or password supplied'); } $ulen = strlen($username); $plen = strlen($password); if ($ulen > 255) { throw new \Erebot\InvalidValueException('Username too long (max. 255)'); } if ($plen > 255) { throw new \Erebot\InvalidValueException('Password too long (max. 255)'); } $this->write("" . pack("Ca*Ca*", $ulen, $username, $plen, $password)); $line = $this->read(2); if ($line[0] != "") { throw new \Erebot\InvalidValueException('Bad subnegociation version'); } if ($line[1] != "") { throw new \Erebot\InvalidValueException('Bad username or password'); } }