/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public INtlm CreateInstance() { INtlm ntlm = null; if (loadedAssembly_ != null) { foreach (Type t in loadedAssembly_.GetTypes()) { if (t.IsClass) { foreach (Type i in t.GetInterfaces()) { if (i.FullName == "WwwProxy.INtlm") { try { ntlm = (INtlm)System.Activator.CreateInstance(t); } catch (Exception e) { ntlm = null; WwwProxy.Instance.OnError(null, null, e, e.Message); } break; } } } if (ntlm != null) { break; } } } return(ntlm); }
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// private int OnResponse(byte[] receiveBuffer, int bytesReceived, bool bConnectionClosed) { string proxyResponse = wwwProxy_.defaultEncoding_.GetString(receiveBuffer, 0, bytesReceived); int processedResponseBytes = 0; wwwProxy_.log_.Write("Outbound.OnResponse()", proxyResponse); string header = null; string contents = null; byte[] contentsBytes = null; string defaultCharset = "iso-8859-1"; string charset = defaultCharset; Match httpResponseMatch = Regex.Match(proxyResponse, "^HTTP/\\d\\.\\d\\s+(\\d+)\\s+", RegexOptions.IgnoreCase); if (httpResponseMatch.Success) { ushort httpResponseCode = Convert.ToUInt16(httpResponseMatch.Groups[1].Value); if ((httpResponseCode >= 100) && (httpResponseCode <= 199)) { inbound_.StopKeepAliveTimer(); inbound_.Send(receiveBuffer, 0, bytesReceived); processedResponseBytes = bytesReceived; } else { int contentsIndex = 0; for (int i = 0; i < (proxyResponse.Length - 3); ++i) { if ((receiveBuffer[i] == '\r') && (receiveBuffer[i + 1] == '\n') && (receiveBuffer[i + 2] == '\r') && (receiveBuffer[i + 3] == '\n')) { contentsIndex = i + 4; header = wwwProxy_.defaultEncoding_.GetString(receiveBuffer, 0, i); contentsBytes = new byte[bytesReceived - (contentsIndex)]; Array.Copy(receiveBuffer, contentsIndex, contentsBytes, 0, bytesReceived - (contentsIndex)); break; } } if (header != null) { Match connectionCloseMatch = Regex.Match(header, "^(Proxy-)*(Connection)+:\\s+close", RegexOptions.IgnoreCase | RegexOptions.Multiline); Match contentEncodingTypeMatch = Regex.Match(header, "^Content-Type:\\s+\\S+?\\s*;\\s*charset=(\\S+)?", RegexOptions.IgnoreCase | RegexOptions.Multiline); Match contentLengthMatch = Regex.Match(header, "^Content-Length:\\s+(\\d+)[\r\n]*", RegexOptions.IgnoreCase | RegexOptions.Multiline); Match contentTextTypeMatch = Regex.Match(header, "^Content-Type:\\s+text|application/x-javascript", RegexOptions.IgnoreCase | RegexOptions.Multiline); Match transferEncodingMatch = Regex.Match(header, "^Transfer-Encoding:\\s+chunked\\s*[\r\n]*", RegexOptions.IgnoreCase | RegexOptions.Multiline); if (contentEncodingTypeMatch.Success) { charset = contentEncodingTypeMatch.Groups[1].Value.ToLower(); } Encoding responseEncoding = null; try { responseEncoding = Encoding.GetEncoding(charset); } catch (ArgumentException) { responseEncoding = wwwProxy_.defaultEncoding_; } if (connectionCloseMatch.Success) { responseCloseInbound_ = true; } completableResponse_ = contentTextTypeMatch.Success || (httpResponseCode >= 300); if (!completableResponse_) { inbound_.StopKeepAliveTimer(); inbound_.Send(receiveBuffer, 0, bytesReceived); processedResponseBytes = bytesReceived; } else { if (contentLengthMatch.Success) { int contentsLength = Convert.ToInt32(contentLengthMatch.Groups[1].Value); if (contentsBytes.Length >= contentsLength) { header = Regex.Replace(header, "^Content-Length:\\s+(\\d+)[ \t]*[\r\n]*", "", RegexOptions.IgnoreCase | RegexOptions.Multiline); header = header.TrimEnd(" \t\r\n".ToCharArray()); contents = responseEncoding.GetString(contentsBytes, 0, contentsBytes.Length); processedResponseBytes = contentsIndex + contentsLength; } else { bytesRequired_ = contentsLength - contentsBytes.Length; } } else if (transferEncodingMatch.Success) { int deChunkingIndex = 0; byte[] chunkedContents = new byte[contentsBytes.Length]; Array.Copy(contentsBytes, chunkedContents, contentsBytes.Length); string deChunkedContents = ""; while (true) { int chunkLengthEnd = -1; for (int i = deChunkingIndex; i < chunkedContents.Length; ++i) { if ((chunkedContents[i] == '\r') && (chunkedContents[i + 1] == '\n')) { chunkLengthEnd = i; break; } } if (chunkLengthEnd != -1) { int chunkLength = Convert.ToInt32(responseEncoding.GetString(chunkedContents, deChunkingIndex, chunkLengthEnd - deChunkingIndex).Trim(), 16); deChunkingIndex = chunkLengthEnd + 2; if (chunkLength != 0) { if (chunkedContents.Length >= (deChunkingIndex + chunkLength)) { deChunkedContents += responseEncoding.GetString(chunkedContents, deChunkingIndex, chunkLength); } else { bytesRequired_ = (deChunkingIndex + chunkLength) - chunkedContents.Length; deChunkedContents = null; } } deChunkingIndex += chunkLength; while ((deChunkingIndex < chunkedContents.Length) && ((chunkedContents[deChunkingIndex] == '\r') || (chunkedContents[deChunkingIndex] == '\n'))) { deChunkingIndex++; } if (chunkLength == 0) { break; } } else { deChunkedContents = null; break; } } if (deChunkedContents != null) { header = Regex.Replace(header, "^Transfer-Encoding:\\s+chunked(.*?)[ \t]*[\r\n]*", "", RegexOptions.IgnoreCase | RegexOptions.Multiline); header = header.TrimEnd(" \t\r\n".ToCharArray()); contents = deChunkedContents; processedResponseBytes = contentsIndex + deChunkingIndex; } } else { if (((connectionCloseMatch.Success) && (bConnectionClosed)) || (bConnectionClosed) || (httpResponseCode == 204) || (httpResponseCode == 304)) // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html { contents = responseEncoding.GetString(contentsBytes, 0, contentsBytes.Length); processedResponseBytes = bytesReceived; } } } if (processedResponseBytes != 0) { if (completableResponse_) { header = Regex.Replace(header, "^Proxy-Connection:\\s+(.*)?[ \t]*[\r\n]*", "", RegexOptions.IgnoreCase | RegexOptions.Multiline); header = header.TrimEnd(" \t\r\n".ToCharArray()); } if ((httpResponseCode == 401) || (httpResponseCode == 407)) { if (wwwProxy_.ntlmEnabled_) { Match urlMatch = Regex.Match(request_.completedHeader_, "([A-Z]+)\\s+(.*?)\\s+HTTP/\\d.\\d\r$", RegexOptions.IgnoreCase | RegexOptions.Multiline); if (urlMatch.Success) { try { wwwProxy_.ntlmListMutex_.WaitOne(); string ntlmSite = host_ + ":" + port_; string ntlmPath = urlMatch.Groups[2].Value; Match wwwAuthenticateBasicMatch = Regex.Match(header, "^(WWW|Proxy)-Authenticate:\\s+Basic(.*)?[ \t]*[\r\n]*", RegexOptions.IgnoreCase | RegexOptions.Multiline); if (wwwAuthenticateBasicMatch.Success) { List <INtlm> toRemove = new List <INtlm>(); foreach (INtlm w in wwwProxy_.ntlmList_) { if (w.Site == ntlmSite) { toRemove.Add(w); } } foreach (INtlm w in toRemove) { wwwProxy_.ntlmList_.Remove(w); } } INtlm wwwProxyNtlm = null; foreach (INtlm w in wwwProxy_.ntlmList_) { if ((w.Site == ntlmSite) && (w.Path == ntlmPath)) { wwwProxyNtlm = w; break; } } Match wwwAuthenticateNegotiateMatch = Regex.Match(header, "^(WWW|Proxy)-Authenticate:\\s+Negotiate[ \t]*[\r\n]*", RegexOptions.IgnoreCase | RegexOptions.Multiline); Match wwwAuthenticateNTLMMatch = Regex.Match(header, "^(WWW|Proxy)-Authenticate:\\s+NTLM[\r\n]*", RegexOptions.IgnoreCase | RegexOptions.Multiline); Match wwwAuthenticateNTLMResponseMatch = Regex.Match(header, "^(WWW|Proxy)-Authenticate:\\s+NTLM\\s+([A-Za-z0-9+/=]*)[ \t]*[\r\n]*", RegexOptions.IgnoreCase | RegexOptions.Multiline); if (wwwAuthenticateNegotiateMatch.Success && wwwAuthenticateNTLMMatch.Success) { string authType = wwwAuthenticateNegotiateMatch.Groups[1].Value; header = Regex.Replace(header, "^(WWW|Proxy)-Authenticate:\\s+Negotiate[ \t]*[\r\n]*", "", RegexOptions.IgnoreCase | RegexOptions.Multiline); header = Regex.Replace(header, "(^(WWW|Proxy)-Authenticate:\\s+)NTLM[ \t]*([\r\n]*)", "${1}Basic Realm=\"WwwProxy NTLM (" + authType + ")\"${3}", RegexOptions.IgnoreCase | RegexOptions.Multiline); header = header.TrimEnd(" \t\r\n".ToCharArray()); if (wwwProxyNtlm == null) { wwwProxyNtlm = wwwProxy_.ntlmFactory_.CreateInstance(); if (wwwProxyNtlm != null) { wwwProxyNtlm.Site = ntlmSite; wwwProxyNtlm.Path = ntlmPath; wwwProxyNtlm.Type = authType; wwwProxy_.ntlmList_.Add(wwwProxyNtlm); } } else { wwwProxyNtlm.Reset(); } } else if (wwwAuthenticateNTLMResponseMatch.Success) { string replacementAuth = "${1}" + wwwProxyNtlm.Continue(wwwAuthenticateNTLMResponseMatch.Groups[2].Value) + "${3}"; request_.completedHeader_ = Regex.Replace(request_.completedHeader_, "^((Proxy-)*Authorization:\\s+NTLM\\s+)[a-zA-Z0-9=]+[ \t]*([\r\n]*)", replacementAuth, RegexOptions.IgnoreCase | RegexOptions.Multiline); Send(request_); header = null; } } finally { wwwProxy_.ntlmListMutex_.ReleaseMutex(); } } } } if (header != null) { response_ = new ProxyResponse(); response_.encoding_ = responseEncoding; response_.outbound_ = this; response_.request_ = request_; response_.completable_ = completableResponse_; response_.ssl_ = ssl_; response_.header_ = header; response_.contents_ = contents; wwwProxy_.OnResponse(response_); } } } } } else { inbound_.StopKeepAliveTimer(); inbound_.Send(receiveBuffer, 0, bytesReceived); processedResponseBytes = bytesReceived; bytesRequired_ = 0; processResponse_ = false; } return(processedResponseBytes); }
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 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) { } } }