private ProxyToken HandleOtherRequest(HttpRequestHeader header, DataAdapterToStream stm, ProxyNetworkService service) { Uri url; if (Uri.TryCreate(header.Path, UriKind.Absolute, out url)) { // Use generic token so filters don't get used ProxyToken ret = new ProxyToken(); ret.State.Add("url", url); ret.State.Add("stm", stm); ret.State.Add("header", header); ret.Client = new HttpProxyDummyClient(this, service); ret.Graph = _factory; return(ret); } else { _logger.LogError(CANAPE.Net.Properties.Resources.HttpProxyServer_InvalidUrl, header.Path); // TODO: Put in some decent error codes ReturnResponse(null, 400, "Bad Request", header.Method, header.Version, stm); return(null); } }
private ProxyToken HandleSocksv4Request(DataAdapterToStream stm) { SocksProxyToken ret = null; int req = stm.ReadByte(); ushort port = ReadUShort(stm); byte[] addrBytes = GeneralUtils.ReadBytes(stm, 4); IPAddress addr = new IPAddress(addrBytes); string addrName = addr.ToString(); // Discard username ReadZString(stm); if ((addrBytes[0] == 0) && (addrBytes[1] == 0) && (addrBytes[2] == 0) && (addrBytes[3] != 0)) { StringBuilder builder = new StringBuilder(); _logger.LogVerbose(CANAPE.Net.Properties.Resources.SocksProxyServer_V4AUsed); addrName = ReadZString(stm); addr = null; } if (req == 1) { _logger.LogVerbose(CANAPE.Net.Properties.Resources.SocksProxyServer_V4ConnectionLog, addrName, port); ret = new SocksProxyToken(addr, addrName, port, IpProxyToken.IpClientType.Tcp, false, stm, 4); } return(ret); }
private bool HandleProxyAuthentication(DataReader reader, DataAdapterToStream stm, ref HttpRequestHeader request) { if (_config.RequireAuth) { bool auth = ProcessProxyAuth(request); if (!auth) { ReturnResponse(request, 407, "Proxy Authentication Required", request.Method, request.Version, new HttpHeader[] { new HttpHeader("Proxy-Authenticate", String.Format("Basic realm=\"{0}\"", _config.AuthRealm ?? "canape.local")) }, stm); if (!MustCloseConnection(request)) { // If version 1.1 server we can assume connection will probably stay up so re-read request // Only give it one chance to get it right though request = HttpParser.ReadRequestHeader(reader, false, _logger); auth = ProcessProxyAuth(request); } } return(auth); } else { return(true); } }
private IpProxyToken HandleConnect(HttpRequestHeader header, DataAdapterToStream stm) { string hostName = null; int port = 80; string[] connectHeader = header.Path.Split(':'); IpProxyToken ret = null; if (connectHeader.Length > 0) { hostName = connectHeader[0]; if (connectHeader.Length > 1) { if (!int.TryParse(connectHeader[1], out port)) { _logger.LogError(CANAPE.Net.Properties.Resources.HttpProxyServer_InvalidConnect, connectHeader[1]); port = 0; } } if (port > 0) { ret = new IpProxyToken(null, hostName, port, IpProxyToken.IpClientType.Tcp, false); ret.State.Add("stm", stm); ret.State.Add("header", header); } else { ReturnResponse(null, 400, "Bad Request", header.Method, header.Version, stm); } } return(ret); }
private bool HandleV5Auth(DataAdapterToStream stm) { int authCount = stm.ReadByte(); bool foundAuth = false; if (authCount > 0) { byte[] authModes = GeneralUtils.ReadBytes(stm, authCount); foreach (byte b in authModes) { if (b == 0) { foundAuth = true; break; } } } byte[] ret = new byte[2]; ret[0] = 5; if (foundAuth) { ret[1] = 0; } else { ret[1] = 0xFF; } stm.Write(ret, 0, ret.Length); return(foundAuth); }
private IDataAdapter HandleSocksV5Response(SocksProxyToken token) { DataAdapterToStream stm = token.Adapter; byte[] returnData = new byte[10]; returnData[0] = 5; if (token.Status == NetStatusCodes.Success) { returnData[1] = 0; } else { // General failure returnData[1] = 1; } // Write out data in one go, otherwise Java has a habit of breaking returnData[2] = 0; returnData[3] = 1; stm.Write(returnData, 0, returnData.Length); if (token.Status == NetStatusCodes.Success) { // Clear adapter value so it wont get disposed token.Adapter = null; return(new StreamDataAdapter(stm)); } else { return(null); } }
private ProxyToken HandleConnectRequest(DataAdapterToStream stm) { ProxyToken ret = null; int version = stm.ReadByte(); if (IsSupported(version)) { if (version == 4) { _logger.LogVerbose(CANAPE.Net.Properties.Resources.SocksProxyServer_NewV4ConnectionLog); ret = HandleSocksv4Request(stm); } else if (version == 5) { _logger.LogVerbose(CANAPE.Net.Properties.Resources.SocksProxyServer_NewV5ConnectionLog); ret = HandleSocksv5Request(stm); } } else { _logger.LogError(CANAPE.Net.Properties.Resources.SocksProxyServer_UnsupportedVersionLog, version); } return(ret); }
public SocksProxyToken(IPAddress address, string hostname, int port, IpClientType clientType, bool ipv6, DataAdapterToStream adapter, int version) : base(address, hostname, port, clientType, ipv6) { Adapter = adapter; Version = version; }
public HttpProxyToken(string hostname, int port, bool connect, string[] headers, Uri url, DataAdapterToStream adapter) : base(null, hostname, port, IpClientType.Tcp, false) { Connect = connect; Headers = headers; Url = url; Adapter = adapter; }
/// <summary> /// /// </summary> /// <param name="adapter"></param> /// <param name="meta"></param> /// <param name="globalMeta"></param> /// <param name="service"></param> /// <returns></returns> public override ProxyToken Accept(IDataAdapter adapter, MetaDictionary meta, MetaDictionary globalMeta, ProxyNetworkService service) { ProxyToken token = null; if (_config.SslConfig.Enabled) { IDataAdapter client = null; INetworkLayer ssl = new TlsNetworkLayer(_config.SslConfig); ssl.Negotiate(ref adapter, ref client, null, _logger, null, null, new PropertyBag("Root"), NetworkLayerBinding.Server); } if (adapter is HttpProxyDataAdapter) { HttpProxyDataAdapter proxyAdapter = (HttpProxyDataAdapter)adapter; token = new FullHttpProxyToken(proxyAdapter.Url.Host, proxyAdapter.Url.Port); token.State.Add("adapter", adapter); } else { DataAdapterToStream stm = new DataAdapterToStream(adapter); DataReader reader = new DataReader(stm); try { HttpRequestHeader header = HttpParser.ReadRequestHeader(reader, false, _logger); if (HandleProxyAuthentication(reader, stm, ref header)) { // We just have a connect if (header.IsConnect) { token = HandleConnect(header, stm); } else { token = HandleOtherRequest(header, stm, service); } } } catch (HttpStreamParserException ex) { _logger.LogError(CANAPE.Net.Properties.Resources.HttpProxyServer_InvalidRequest, ex.Message); // TODO: Put in some decent error codes ReturnResponse(null, 400, "Bad Request", "GET", HttpVersion.Version11, stm); } catch (EndOfStreamException) { token = null; } } return(token); }
private ProxyToken HandleSocksv5Request(DataAdapterToStream stm) { if (HandleV5Auth(stm)) { return(HandleV5RequestData(stm)); } return(null); }
public HttpProxyServerAdapter(DataAdapterToStream stm, HttpRequestHeader initialRequest, Logger logger) { _stm = stm; _writer = new DataWriter(_stm); _request = initialRequest; _config = new HttpParserConfig(); _config.StreamBody = true; _logger = logger; Description = stm.Description; }
public HttpProxyServerAdapter(FullHttpProxyServer server, DataAdapterToStream stm, HttpRequestHeader initialRequest, Logger logger) { _server = server; _stm = stm; _writer = new DataWriter(_stm); _request = initialRequest; ProcessProxyRequestHeaders(_request); _config = new HttpParserConfig(); _config.StreamBody = true; _logger = logger; _requestQueue = new Queue <HttpRequestHeader>(); _requestQueue.Enqueue(_request); Description = stm.Description; }
private void ReturnResponse(HttpRequestHeader request, int responseCode, string message, string method, HttpVersion version, IEnumerable <HttpHeader> sendHeaders, DataAdapterToStream stm) { if (request != null) { FlushRequest(request); } HttpResponseDataChunk response = new HttpResponseDataChunk(); if (_config.Version10Proxy && !version.IsVersionUnknown) { response.Version = HttpVersion.Version10; } else { response.Version = version; } response.ResponseCode = responseCode; response.Message = message; response.FinalChunk = true; response.Body = new byte[0]; List <HttpHeader> headers = new List <HttpHeader>(sendHeaders); headers.Add(new HttpHeader("X-Proxy-Server", "CANAPE")); if (response.Body.Length > 0) { headers.Add(new HttpHeader("Content-Type", "text/html")); } response.Headers = headers.ToArray(); if (method.Equals("HEAD", StringComparison.OrdinalIgnoreCase)) { response.HeadResponse = true; } else if (method.Equals("CONNECT", StringComparison.OrdinalIgnoreCase)) { response.ConnectResponse = true; } response.WriteChunk(new DataWriter(stm)); }
private HttpProxyToken HandleOtherRequest(string host, string[] headers, DataAdapterToStream stm) { Uri url; if (Uri.TryCreate(host, UriKind.Absolute, out url)) { return(new HttpProxyToken(url.Host, url.Port, false, headers, url, stm)); } else { _logger.LogError(CANAPE.Net.Properties.Resources.HttpProxyServer_InvalidUrl, host); // TODO: Put in some decent error codes ReturnResponse(500, "Server Error", stm); return(null); } }
private ProxyToken HandleOtherRequest(HttpRequestHeader header, DataAdapterToStream stm, TcpClientDataAdapter tcpAdapter) { string host = null; foreach (KeyDataPair <string> pair in header.Headers) { if (pair.Name.Equals("host", StringComparison.OrdinalIgnoreCase)) { host = pair.Value; } } Uri url = GetUri(host, tcpAdapter); if (url != null) { // Use generic token so filters don't get used IpProxyToken ret = new IpProxyToken(null, url.Host, url.Port, IpProxyToken.IpClientType.Tcp, false); if (_config.SslConfig.Enabled) { ret.Layers = new INetworkLayer[1]; ret.Layers[0] = new SslNetworkLayer(new SslNetworkLayerConfig(false, true) { Enabled = true }); } ret.State.Add("url", url); ret.State.Add("stm", stm); ret.State.Add("header", header); return(ret); } else { _logger.LogError(CANAPE.Net.Properties.Resources.HttpProxyServer_InvalidUrl, header.Path); ReturnResponse(null, 400, "Bad Request", header.Method, header.Version, stm); return(null); } }
private IDataAdapter HandleSocksV4Response(SocksProxyToken token) { DataAdapterToStream stm = token.Adapter; byte[] resp = new byte[8]; resp[1] = token.Status == NetStatusCodes.Success ? REQUEST_SUCCEEDED : REQUEST_FAILED; stm.Write(resp, 0, resp.Length); if (token.Status == NetStatusCodes.Success) { // Clear adapter value so it wont get disposed token.Adapter = null; return(new StreamDataAdapter(stm)); } else { return(null); } }
/// <summary> /// /// </summary> /// <param name="token"></param> /// <param name="meta"></param> /// <param name="globalMeta"></param> /// <param name="service"></param> /// <param name="client"></param> /// <returns></returns> public override IDataAdapter Complete(ProxyToken token, MetaDictionary meta, MetaDictionary globalMeta, ProxyNetworkService service, IDataAdapter client) { IDataAdapter ret = null; // An empty initial request indicates we are a full connection if (token.State.ContainsKey("header")) { HttpRequestHeader initialRequest = (HttpRequestHeader)token.State["header"]; DataAdapterToStream stm = (DataAdapterToStream)token.State["stm"]; if (token.Status == NetStatusCodes.Success) { if (initialRequest.IsConnect) { ReturnResponse(null, 200, "Connection established", initialRequest.Method, initialRequest.Version, stm); // Connect is transparent ret = new StreamDataAdapter(stm); } else { // Use a proxy adapter ret = new HttpProxyServerAdapter(stm, initialRequest, _logger); } } else { ReturnResponse(initialRequest, 404, "Not Found", initialRequest.Method, HttpVersion.Version11, stm); } } else { ret = (IDataAdapter)token.State["adapter"]; } token.State.Clear(); return(ret); }
private void CloneCertChain(Uri url, string destination) { IProxyClientFactory factory = proxyClientControl.Client; if (factory == null) { factory = new IpProxyClientFactory(); } ProxyClient client = factory.Create(new Logger()); collection = new X509Certificate2Collection(); using (IDataAdapter adapter = client.Connect(new IpProxyToken(null, url.Host, url.Port, IpProxyToken.IpClientType.Tcp, false), new Logger(), new Nodes.MetaDictionary(), new Nodes.MetaDictionary(), new PropertyBag(), new Security.CredentialsManagerService())) { DataAdapterToStream stm = new DataAdapterToStream(adapter); using (SslStream ssl = new SslStream(stm, false, VerifyCallback)) { ssl.AuthenticateAsClient(url.Host); } } if (collection.Count > 0) { File.WriteAllBytes(Path.Combine(destination, String.Format("certchain_{0}.pfx", url.Host)), collection.Export(X509ContentType.Pfx)); int count = 1; foreach (X509Certificate2 cert in collection) { string path = Path.Combine(destination, String.Format("cert_{0}_{1}.cer", url.Host, count++)); File.WriteAllText(path, CertificateUtils.ExportToPEM(cert) + CertificateUtils.ExportToPEM((RSA)cert.PrivateKey, null)); } } }
/// <summary> /// /// </summary> /// <param name="adapter"></param> /// <param name="meta"></param> /// <param name="globalMeta"></param> /// <param name="service"></param> /// <returns></returns> public override ProxyToken Accept(IDataAdapter adapter, MetaDictionary meta, MetaDictionary globalMeta, ProxyNetworkService service) { ProxyToken token = null; TcpClientDataAdapter tcpAdapter = adapter as TcpClientDataAdapter; if (_config.SslConfig.Enabled) { IDataAdapter client = null; INetworkLayer ssl = new SslNetworkLayer(_config.SslConfig); ssl.Negotiate(ref adapter, ref client, null, _logger, null, null, new PropertyBag("Root"), NetworkLayerBinding.Server); } DataAdapterToStream stm = new DataAdapterToStream(adapter); DataReader reader = new DataReader(stm); try { HttpRequestHeader header = HttpParser.ReadRequestHeader(reader, false, _logger); token = HandleOtherRequest(header, stm, tcpAdapter); } catch (HttpStreamParserException ex) { _logger.LogError(CANAPE.Net.Properties.Resources.HttpProxyServer_InvalidRequest, ex.Message); // TODO: Put in some decent error codes ReturnResponse(null, 400, "Bad Request", "GET", HttpVersion.Version11, stm); } catch (EndOfStreamException) { token = null; } return(token); }
private HttpProxyToken HandleConnect(string host, string[] headers, DataAdapterToStream stm) { string hostName = null; int port = 80; string[] connectHeader = host.Split(':'); HttpProxyToken ret = null; if (connectHeader.Length > 0) { hostName = connectHeader[0]; if (connectHeader.Length > 1) { if (!int.TryParse(connectHeader[1], out port)) { _logger.LogError(CANAPE.Net.Properties.Resources.HttpProxyServer_InvalidConnect, connectHeader[1]); port = 0; } } if (port > 0) { UriBuilder builder = new UriBuilder(GetProbableProtocol(port), hostName); builder.Port = port; ret = new HttpProxyToken(hostName, port, true, headers, builder.Uri, stm); } else { // TODO: Put in some decent error codes ReturnResponse(500, "Server Error", stm); } } return(ret); }
private ProxyToken HandleV5RequestData(DataAdapterToStream stm) { SocksProxyToken ret = null; IPAddress addr = null; string addrName = null; bool ipv6 = false; ushort port = 0; int ver = stm.ReadByte(); int code = stm.ReadByte(); stm.ReadByte(); // Reserved int type = stm.ReadByte(); if ((ver == 5) && (code == 1)) { byte[] data = null; switch (type) { case 1: // IPv4 { data = GeneralUtils.ReadBytes(stm, 4); addr = new IPAddress(data); addrName = addr.ToString(); } break; case 3: // Domain name { int nameLen = stm.ReadByte(); if (nameLen > 0) { data = GeneralUtils.ReadBytes(stm, nameLen); addrName = Encoding.ASCII.GetString(data); } } break; case 4: // IPv6 data = GeneralUtils.ReadBytes(stm, 16); addr = new IPAddress(data); addrName = addr.ToString(); ipv6 = true; break; default: break; } port = ReadUShort(stm); if ((addrName != null) && (port > 0)) { _logger.LogVerbose(CANAPE.Net.Properties.Resources.SocksProxyServer_V5ConnectionLog, addrName, port); ret = new SocksProxyToken(addr, addrName, port, IpProxyToken.IpClientType.Tcp, ipv6, stm, 5); } } return(ret); }
/// <summary> /// Run method /// </summary> /// <param name="adapter">The data adapter to use</param> /// <param name="logger">The logger to use</param> public override void Run(DataAdapters.IDataAdapter adapter, Utils.Logger logger) { DataAdapterToStream stm = new DataAdapterToStream(adapter); OnRun(stm, logger); }
private void ReturnResponse(HttpRequestHeader request, int responseCode, string message, string method, HttpVersion version, DataAdapterToStream stm) { ReturnResponse(request, responseCode, message, method, version, new KeyDataPair <string> [0], stm); }
/// <summary> /// /// </summary> /// <param name="adapter"></param> /// <param name="globalMeta"></param> /// <param name="meta"></param> /// <param name="service"></param> /// <returns></returns> public override ProxyToken Accept(IDataAdapter adapter, MetaDictionary meta, MetaDictionary globalMeta, ProxyNetworkService service) { HttpProxyToken token = null; if (_ssl != null) { IDataAdapter client = null; _ssl.Negotiate(ref adapter, ref client, null, _logger, null, null, new PropertyBag("Root"), NetworkLayerBinding.Server); } DataAdapterToStream stm = new DataAdapterToStream(adapter); List <string> headers = new List <string>(); // Read out HTTP headers try { while (true) { string nextLine = GeneralUtils.ReadLine(stm); headers.Add(nextLine); if (nextLine.Trim('\r', '\n').Length == 0) { break; } } } catch (EndOfStreamException) { // Pass on the exception if we got killed half way through if (headers.Count > 0) { throw; } } if (headers.Count > 0) { string[] reqValues = headers[0].Trim().Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); // Check it at least has a VERB and a PATH if (reqValues.Length > 1) { if (reqValues[0].Equals("CONNECT", StringComparison.OrdinalIgnoreCase)) { token = HandleConnect(reqValues[1], headers.ToArray(), stm); } else { token = HandleOtherRequest(reqValues[1], headers.ToArray(), stm); } } else { _logger.LogError(CANAPE.Net.Properties.Resources.HttpProxyServer_InvalidRequest, headers[0]); // TODO: Put in some decent error codes ReturnResponse(500, "Server Error", stm); } } return(token); }
private void ReturnResponse(int no, string description, DataAdapterToStream stm) { byte[] response = Encoding.ASCII.GetBytes(String.Format("HTTP/1.0 {0} {1}\r\n\r\n", no, description)); stm.Write(response, 0, response.Length); }
/// <summary> /// /// </summary> /// <param name="token"></param> /// <param name="client"></param> /// <param name="globalMeta"></param> /// <param name="meta"></param> /// <param name="service"></param> /// <returns></returns> public override IDataAdapter Complete(ProxyToken token, MetaDictionary meta, MetaDictionary globalMeta, ProxyNetworkService service, IDataAdapter client) { IDataAdapter ret = null; HttpProxyToken httpToken = (HttpProxyToken)token; DataAdapterToStream stm = httpToken.Adapter; if (httpToken.Status == NetStatusCodes.Success) { if (httpToken.IsHTTPProxyClient) { // We don't have to do anything as such, other than send back any smuggled data if it was a connect call if (httpToken.Response != null) { stm.Write(httpToken.Response, 0, httpToken.Response.Length); } httpToken.Adapter = null; if (httpToken.Connect) { // With CONNECT the data stream is transparent ret = new StreamDataAdapter(stm); } else { // For anything else, rebuild the original headers so it can flow through the graph StringBuilder builder = new StringBuilder(); foreach (string s in httpToken.Headers) { builder.Append(s); } ret = new PrefixedDataAdapter(new StreamDataAdapter(stm), GeneralUtils.MakeByteArray(builder.ToString())); } } else { if (httpToken.Connect) { ReturnResponse(200, "Connection established", stm); httpToken.Adapter = null; ret = new StreamDataAdapter(stm); } else { StringBuilder builder = new StringBuilder(); string[] reqValues = httpToken.Headers[0].Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); // Downgrade to version 1.0 httpToken.Headers[0] = reqValues[0] + " " + httpToken.Url.PathAndQuery + " HTTP/1.0\r\n"; foreach (string s in httpToken.Headers) { // Remove proxy headers if (!s.StartsWith("proxy", StringComparison.OrdinalIgnoreCase)) { builder.Append(s); } } httpToken.Adapter = null; ret = new PrefixedDataAdapter(new StreamDataAdapter(stm), GeneralUtils.MakeByteArray(builder.ToString())); } } } else { ReturnResponse(404, "Not Found", stm); } return(ret); }
/// <summary> /// /// </summary> /// <param name="adapter"></param> /// <param name="globalMeta"></param> /// <param name="meta"></param> /// <param name="service"></param> /// <returns></returns> public override ProxyToken Accept(IDataAdapter adapter, MetaDictionary meta, MetaDictionary globalMeta, ProxyNetworkService service) { DataAdapterToStream stm = new DataAdapterToStream(adapter); return(HandleConnectRequest(stm)); }
private IDataAdapter ConnectServerBC(IDataAdapter adapter, Logger logger, PropertyBag properties) { X509Certificate cert = null; // If server certificate not specified try and auto generate one if (!_config.SpecifyServerCert) { if (_remoteCert != null) { cert = _remoteCert; } else { cert = CertManager.GetCertificate("CN=localhost"); } } else if (_config.ServerCertificate != null) { cert = _config.ServerCertificate.Certificate; } else { // Ideally shouldn't get here, but not necessarily consistent :) cert = CertManager.GetCertificate("CN=localhost"); } DataAdapterToStream stm = new DataAdapterToStream(adapter); TlsServerProtocol server = new TlsServerProtocol(stm, stm, new SecureRandom()); bool setReadTimeout = false; int oldTimeout = -1; try { oldTimeout = stm.ReadTimeout; stm.ReadTimeout = _config.Timeout; setReadTimeout = true; } catch (InvalidOperationException) { } X509Certificate[] certs; // If we have a remote chain then duplicate all certificates if (_remoteChain.Count > 0) { certs = _remoteChain.ToArray(); } else { certs = new X509Certificate[] { cert }; } // Accept with our CA key, doesn't really matter what it is but no point generating each time server.Accept(new CustomTlsServer(certs, CertManager.GetRootCert().PrivateKey, logger)); if (setReadTimeout) { stm.ReadTimeout = oldTimeout; } // Return re-adapted layer return(new StreamDataAdapter(server.Stream, adapter.Description)); }