/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// internal int OnRequest(byte[] receiveBuffer, int bytesReceived, bool internalRequest) { string proxyRequest = wwwProxy_.defaultEncoding_.GetString(receiveBuffer, 0, bytesReceived); int processedRequestBytes = 0; wwwProxy_.log_.Write("Inbound.OnRequest()", proxyRequest); Match httpMatch = Regex.Match(proxyRequest, "^([A-Z]+)\\s+(\\S*)?\\s+HTTP/\\d.\\d\r$", RegexOptions.IgnoreCase | RegexOptions.Multiline); if (httpMatch.Success) { string defaultCharset = "iso-8859-1"; string charset = defaultCharset; string httpVerb = httpMatch.Groups[1].Value; if (httpVerb != "CONNECT") { Match getEndMatch = Regex.Match(proxyRequest, "\r\n\r\n", RegexOptions.IgnoreCase | RegexOptions.Multiline); if (getEndMatch.Success) { string requestRaw = proxyRequest.Substring(0, getEndMatch.Index); string postRaw = null; processedRequestBytes = getEndMatch.Index + 4; Match contentEncodingTypeMatch = Regex.Match(proxyRequest, "^Content-Type:\\s+\\S+?\\s*;\\s*charset=(\\S+)?", RegexOptions.IgnoreCase | RegexOptions.Multiline); if (contentEncodingTypeMatch.Success) { charset = contentEncodingTypeMatch.Groups[1].Value.ToLower(); } Encoding requestEncoding = null; try { requestEncoding = Encoding.GetEncoding(charset); } catch (ArgumentException) { requestEncoding = wwwProxy_.defaultEncoding_; } Match contentLengthMatch = Regex.Match(requestRaw, "^Content-Length:\\s+(\\d+)[ \t]*[\r\n]*", RegexOptions.IgnoreCase | RegexOptions.Multiline); if (contentLengthMatch.Success) { int contentsLength = Convert.ToInt32(contentLengthMatch.Groups[1].Value); if (proxyRequest.Length >= processedRequestBytes + contentsLength) { postRaw = requestEncoding.GetString(receiveBuffer, processedRequestBytes, contentsLength); processedRequestBytes += contentsLength; for (int i = processedRequestBytes; i < bytesReceived; ++i) { if ((receiveBuffer[i] == '\r') || (receiveBuffer[i] == '\n')) { processedRequestBytes++; } else { break; } } } else { requestRaw = null; postRaw = null; } } if (requestRaw != null) { requestRaw = Regex.Replace(requestRaw, "([A-Z]+)\\s+([a-zA-Z]+://.*?/)(.*?)\\s+(HTTP/\\d.\\d)", "$1 /$3 $4", RegexOptions.IgnoreCase | RegexOptions.Multiline); requestRaw = Regex.Replace(requestRaw, "^Accept-Encoding:\\s+(.*)?[ \t]*[\r\n]*", "", RegexOptions.IgnoreCase | RegexOptions.Multiline); requestRaw = Regex.Replace(requestRaw, "^Content-Length:\\s+(.*)?[ \t]*[\r\n]*", "", RegexOptions.IgnoreCase | RegexOptions.Multiline); requestRaw = Regex.Replace(requestRaw, "^Proxy-Connection:\\s+(.*)?[ \t]*[\r\n]*", "", RegexOptions.IgnoreCase | RegexOptions.Multiline); requestRaw = requestRaw.TrimEnd(" \t\r\n".ToCharArray()); Match hostMatch = Regex.Match(requestRaw, "^Host:\\s+(\\S*)?", RegexOptions.IgnoreCase | RegexOptions.Multiline); if (hostMatch.Success) { string host = hostMatch.Groups[1].Value; string port = ssl_ ? "443" : "80"; Match portMatch = Regex.Match(host, "(:)(\\d{1,5})"); if (portMatch.Success) { port = host.Substring(portMatch.Groups[2].Index, portMatch.Groups[2].Length); host = host.Substring(0, portMatch.Groups[1].Index); } ProxyRequest request = new ProxyRequest(); request.inbound_ = this; request.ssl_ = ssl_; request.header_ = requestRaw; request.data_ = postRaw; Outbound sendOutbound = null; currentOutboundsMutex_.WaitOne(); foreach (Outbound o in currentOutbounds_.Keys) { if ((o.host_ == host) && (o.port_ == Convert.ToUInt16(port)) && (currentOutbounds_[o] == null)) { sendOutbound = o; currentOutbounds_[o] = request; break; } } currentOutboundsMutex_.ReleaseMutex(); if (sendOutbound == null) { sendOutbound = new Outbound(wwwProxy_, this, ssl_, host, Convert.ToUInt16(port)); currentOutboundsMutex_.WaitOne(); currentOutbounds_.Add(sendOutbound, request); currentOutboundsMutex_.ReleaseMutex(); } if (!internalRequest) { wwwProxy_.OnRequest(request); } else { wwwProxy_.Pass(request); } StartKeepAliveTimer(); } } else { processedRequestBytes = 0; } } } else { string connectHost = httpMatch.Groups[2].Value; string host = connectHost; string port = "443"; Match portMatch = Regex.Match(host, "(:)(\\d{1,5})"); if (portMatch.Success) { port = host.Substring(portMatch.Groups[2].Index, portMatch.Groups[2].Length); host = host.Substring(0, portMatch.Groups[1].Index); } Outbound outbound = new Outbound(wwwProxy_, this, true, host, Convert.ToUInt16(port)); currentOutboundsMutex_.WaitOne(); currentOutbounds_.Add(outbound, null); currentOutboundsMutex_.ReleaseMutex(); Match connectEndMatch = Regex.Match(proxyRequest, "\r\n\r\n", RegexOptions.Multiline); if (connectEndMatch.Success) { processedRequestBytes = connectEndMatch.Index + 4; } byte[] sslResponseBytes = wwwProxy_.defaultEncoding_.GetBytes("HTTP/1.0 200 OK\r\n\r\n"); Send(sslResponseBytes, 0, sslResponseBytes.Length); ssl_ = true; sslNetworkStream_ = new NetworkStream(inboundSocket_); sslStream_ = new SslStream(sslNetworkStream_, false, new RemoteCertificateValidationCallback(OnRemoteCertificateValidation)); X509Certificate serverCertificate = new X509Certificate((wwwProxy_.certificate_ != null) ? wwwProxy_.certificate_ : "WwwProxy.cer"); sslStream_.AuthenticateAsServer(serverCertificate); } } else { int lineEnd = proxyRequest.IndexOf("\r\n"); throw new Exception("Unhandled Request \"" + proxyRequest.Substring(0, (lineEnd > 0) ? lineEnd : proxyRequest.Length) + "\""); } return(processedRequestBytes); }
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// internal void Complete(ProxyRequest request) { Outbound sendOutbound = null; try { currentOutboundsMutex_.WaitOne(); foreach (Outbound o in currentOutbounds_.Keys) { if (currentOutbounds_[o] == request) { sendOutbound = o; break; } } currentOutboundsMutex_.ReleaseMutex(); } catch (ObjectDisposedException) { } request.completedHeader_ = request.header_; if (request.data_ != null) { request.completedHeader_ += "\r\nContent-Length: " + Convert.ToString(request.data_.Length) + "\r\n\r\n" + request.data_; } else { request.completedHeader_ += "\r\n\r\n"; } if (sendOutbound != null) { if (sendOutbound.useRemoteProxy_) { Match noUrlMatch = Regex.Match(request.completedHeader_, "([A-Z]+)\\s+/(.*?)\\s+(HTTP/\\d.\\d)", RegexOptions.IgnoreCase | RegexOptions.Multiline); if (noUrlMatch.Success) { Match hostMatch = Regex.Match(request.completedHeader_, "^Host:\\s+(\\S*)?", RegexOptions.IgnoreCase | RegexOptions.Multiline); if (hostMatch.Success) { string host = hostMatch.Groups[1].Value; string insert = (sendOutbound.ssl_ ? "https://" : "http://") + host + "/"; request.completedHeader_ = Regex.Replace(request.completedHeader_, "([A-Z]+)\\s+/(.*)\\s+(HTTP/\\d.\\d)", "$1 " + insert + "$2 $3", RegexOptions.IgnoreCase | RegexOptions.Multiline); } } } if (wwwProxy_.ntlmEnabled_) { MatchCollection basicCredentials = Regex.Matches(request.completedHeader_, "^(Proxy-)*Authorization:\\s+Basic\\s+([a-zA-Z0-9=]*)[ \t]*[\r\n]*", RegexOptions.IgnoreCase | RegexOptions.Multiline); if (basicCredentials.Count > 0) { Match urlMatch = Regex.Match(request.completedHeader_, "([A-Z]+)\\s+(.*?)\\s+HTTP/\\d.\\d\r$", RegexOptions.IgnoreCase | RegexOptions.Multiline); if (urlMatch.Success) { string ntlmSite = sendOutbound.host_ + ":" + sendOutbound.port_; string ntlmPath = urlMatch.Groups[2].Value; INtlm wwwProxyNtlm = null; try { wwwProxy_.ntlmListMutex_.WaitOne(); foreach (INtlm w in wwwProxy_.ntlmList_) { if ((w.Site == ntlmSite) && (w.Path == ntlmPath)) { foreach (Match basicCredentialsMatch in basicCredentials) { if ((w.Type == basicCredentialsMatch.Groups[1].Value) || ((w.Type == "WWW") && (basicCredentialsMatch.Groups[1].Value == ""))) { w.Basic = basicCredentialsMatch.Groups[2].Value; wwwProxyNtlm = w; break; } } if (wwwProxyNtlm != null) { break; } } } if (wwwProxyNtlm == null) { foreach (INtlm w in wwwProxy_.ntlmList_) { if ((w.Site == ntlmSite) && (w.Basic != null)) { foreach (Match basicCredentialsMatch in basicCredentials) { if ((w.Basic == basicCredentialsMatch.Groups[2].Value) && ((w.Type == basicCredentialsMatch.Groups[1].Value) || ((w.Type == "WWW") && (basicCredentialsMatch.Groups[1].Value == "")))) { INtlm cloneWwwProxyNtlm = wwwProxy_.ntlmFactory_.CreateInstance(); if (cloneWwwProxyNtlm != null) { cloneWwwProxyNtlm.Site = ntlmSite; cloneWwwProxyNtlm.Path = ntlmPath; cloneWwwProxyNtlm.Type = w.Type; cloneWwwProxyNtlm.Basic = w.Basic; wwwProxy_.ntlmList_.Add(cloneWwwProxyNtlm); wwwProxyNtlm = cloneWwwProxyNtlm; } break; } } if (wwwProxyNtlm != null) { break; } } } } if (wwwProxyNtlm != null) { string[] credentials = wwwProxy_.defaultEncoding_.GetString(Convert.FromBase64String(wwwProxyNtlm.Basic)).Split(':'); string ntlmNegotiate = null; string domain = sendOutbound.host_; string username = credentials[0]; string password = credentials[1]; if (username.Contains("\\")) { int domainUsernameSeparator = username.IndexOf('\\'); if ((domainUsernameSeparator > 0) && (domainUsernameSeparator < (username.Length - 1))) { domain = username.Substring(0, domainUsernameSeparator); username = username.Substring(username.IndexOf('\\') + 1); } } wwwProxyNtlm.Initialise(domain, username, password); ntlmNegotiate = wwwProxyNtlm.Continue(null); if (ntlmNegotiate == null) { ntlmNegotiate = "???"; } string authReplace = "^(" + (wwwProxyNtlm.Type == "Proxy" ? "Proxy-" : "") + "Authorization:\\s+)Basic\\s+[a-zA-Z0-9=]+[ \t]*([\r\n]*)"; request.completedHeader_ = Regex.Replace(request.completedHeader_, authReplace, "${1}NTLM " + ntlmNegotiate + "${2}", RegexOptions.IgnoreCase | RegexOptions.Multiline); } } finally { wwwProxy_.ntlmListMutex_.ReleaseMutex(); } } } } wwwProxy_.log_.Write("Inbound.Complete()", request.completedHeader_); sendOutbound.Connect(); try { sendOutbound.Send(request); } catch (IOException) { } catch (SocketException) { } } }