使用 .NET Core 通过 HTTP 代理连接到外部数据库

问题描述 投票:0回答:1

我的要求是从我的组织网络连接到外部 SQL Server 数据库。我的 .NET Core 应用程序托管在 Openshift 容器中,它必须通过内部 Bluecoat Web 代理 -> 防火墙到达外部数据库。

现在我的方法是创建一个到这个外部数据库的 TCP 隧道,然后使用下面的连接字符串连接到数据库。

var connectionString = "Data Source=127.0.0.1,1433;Initial Catalog=myDatabase;Integrated Security=false;User ID=username;Password=sqlPassword;TrustServerCertificate=true;";

TCP 隧道创建成功,但当我尝试连接到数据库时,在建立与 SQL Server 的连接时出现网络相关或特定于实例的错误。找不到服务器或无法访问服务器。 (更多的是一般错误)

当我检查双方的日志时,我可以看到 TCP 隧道创建成功,但从外部来看,我随后看到 [RST,ACK](重置确认)。

我想知道我当前尝试的方法是否正确,或者是否有其他方法可以更好地做到这一点。

这是我的 TCP 隧道创建和 SQL 连接代码:

// Connect to the proxy server
var tcpClient = new TcpClient(proxyIP, proxyPort);
NetworkStream networkStream = tcpClient.GetStream();
    
// Create the proxy authentication header
string authInfo = Convert.ToBase64String(Encoding.ASCII.GetBytes($"{proxyUsername}:{proxyPassword}"));
string connectRequest = $"CONNECT {targetHost}:{targetPort} HTTP/1.1\r\n" +
                        $"Host: {targetHost}:{targetPort}\r\n" +
                        $"Proxy-Authorization: Basic {authInfo}\r\n" +
                        "Proxy-Connection: Keep-Alive\r\n\r\n";
    
// Send the CONNECT request to the proxy
byte[] requestBytes = Encoding.ASCII.GetBytes(connectRequest);
await networkStream.WriteAsync(requestBytes, 0, requestBytes.Length);
    
// Read the response from the proxy
StreamReader reader = new StreamReader(networkStream);
string responseLine = await reader.ReadLineAsync();
    
if (!responseLine.Contains("200 Connection established"))
{
    Console.WriteLine("Failed to establish a connection with the target server.");
    return;
}
    
// At this point, the tunnel is established
Console.WriteLine("Tunnel established");

// from here I'm connecting to my database
var con = new SqlConnection(connectionString);

// This line throws the error
con.Open();   

我还尝试了下面的代码从 SQL 服务器读取。但我没有看到任何回应。这是正确的做法吗?

那么,对于数据读取,我可以使用以下内容吗?我尝试了,但没有看到任何反应。

byte[] sqlQueryBytes = Encoding.ASCII.GetBytes("SELECT COUNT(*) FROM tblTest");
networkStream.Write(sqlQueryBytes, 0, sqlQueryBytes.Length);
    
byte[] responseBuffer = new byte[4096];
int bytesRead = networkStream.Read(responseBuffer, 0, responseBuffer.Length);
string response = Encoding.ASCII.GetString(responseBuffer, 0, bytesRead);
Console.WriteLine(response);
sql-server asp.net-core tcp openshift proxy-server
1个回答
0
投票

通过创建TcpListener解决了这个问题,监听器将创建TCP隧道。因此,从代码中,我们访问 localhost:(listnerPort)。下面是对我有用的代码示例,

为监听器创建BackgroundService,

public class TcpTunnelService : BackgroundService
{
 protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
string proxyAddress = "11.22.22.11";
int proxyPort = 8081;

string sqlAddress = "11.22.33.44";
int sqlPort = 1433;

var listener = new TcpListener(IPAddress.Any, 8888);
        listener.Start();

        while (!stoppingToken.IsCancellationRequested)
        {
            var client = await listener.AcceptTcpClientAsync();
            _ = HandleClientAsync(client, proxyAddress, proxyPort, sqlAddress, sqlPort);
        }
    }

    private async Task HandleClientAsync(TcpClient client, string proxyAddress, int proxyPort, string sqlAddress, int sqlPort)
    {
using(client)
{
 TcpClient proxyClient = new TcpClent();
 await proxyClient.ConnectAsync(proxyAddress, proxyPort);

 using(proxyClent)
 using(NetworkStream cs = clent.Stream())
 using(NetworkStream ps = proxyClent.GetStream())
 {
  string proxyCredentials = Convert.ToBase64String(Encoding.ASCII.GetBytes($"{yourProxyUserName}:{yourProxyPassword}"));
  
  StreamWriter w = new StreamWriter(ps);
  w.WriteLine($"CONNECT {sqlAddress}:{sqlPort} HTTP/1.1");
  w.WriteLine($"Host: {sqlAddress}:{sqlPort}");
  w.WriteLine($"Proxy-Authorization: Basic {proxyCredentials}");
  w.WriteLine("Connection: keep-alive");
  w.WriteLine();
  w.Flush();

  StreamReader sr = new StreamReader(ps);
  string res = await sr.ReadLineAsync();

  if(!res.Contains("200 Connection established"))
  {
   //errror
   return;
  }
  else
  {
   //success
  }

  Task cToProxy = RelayDataAsync(cs, ps);
  Task pToClient = RelayDataAsync(ps, cs);

  await Task.WhenAny(cToProxy, pToClient);
 }
}
}
 private async Task RelayDataAsync(NetworkStream source, NetworkStream dest)
 {
  byte[] buf= new byte[8192];
  int bytesRead;

  while(bytesRead = await source.ReadAsync(buf, 0, buffer.Length)) > 0)
  {
   await dest.WriteAsync(buf, 0, bytesRead);
  }
 }
}

然后像下面一样注册服务,

services.AddHostedService<TcpListenerService>();

连接字符串必须如下所示,

"Data Source=localhost,8888; Initial Catelog= ....."
© www.soinside.com 2019 - 2024. All rights reserved.