2013-03-31 2 views
2

Как создать программу, которая прозрачно перенаправляет соединения на новые IP-адреса/порты?Как можно создать программный маршрутизатор на .NET?

Например, если клиент инициирует TCP-подключение IP-адресом 111.111.111.111 и TCP-портом 111, тогда программа может быть настроена для пересылки этого и следующих пакетов IP/port 222.222.222.222:222.

Под прозрачных, я имею в виду:

  • Минимальной производительность штраф
  • Нет необходимости корректировать клиент или конечный пункт назначения программного обеспечения/конфигурации (так же, как Прозрачный прокси не требует явной настройки в браузере, чтобы быть настроить)
  • предложений как низкий уровень, как это возможно с сетевой ОС слоем

Я хотел бы сделать это с .NET, C# и Windows. Но я не хочу создавать простой TCP-прокси по различным, но неуказанным причинам. Если это невозможно сделать, это может быть приемлемым ответом при отсутствии возможного решения.

+1

Это не маршрутизации. То, что вы описываете, является «port-bouncer» или прокси-сервером TCP. Они тривиальны для реализации. – Dai

+1

@Dai Thanks - Googling «TCP proxy» дает полезную информацию. Это работает: {1. Создайте прослушивающий сокет. 2. Получать байты из входящих соединений. 3. Откройте новый сокет для адресата пересылки. 4. Отправьте байты в новый сокет.}? Я боюсь, что эта тривиальная схема не будет прозрачной. – Nat

+1

Хотя в сущности вашего вопроса есть более простой ответ кандидата, существует ответ, который больше соответствует вашему названию и характеру вашего комментария: https://bitbucket.org/merarischroeder/softrouter/wiki/Home [примечание: незавершенное]. Когда кто-то подключается к 111.111.111.111:111, программа (программное обеспечение, выполняемая через устройство Winpcap 10 Мбит/с) может перехватывать такой пакет - даже если на этом порту нет прослушивателя TCP и пересылается по мере необходимости. Это было бы прозрачно, успокаивая ваш страх. Некоторые моды чрезмерно усердны, когда речь идет о закрытии вопросов, это трудная работа. – Todd

ответ

7

Вот один я написал несколько недель назад для эксперимента:

using System; 
using System.IO; 
using System.Net; 
using System.Net.Sockets; 
using System.Globalization; 
using System.Threading; 

namespace TcpTunnel { 

public static class Program { 

    public static void Main(String[] args) { 

     if(args.Length != 3) { 

      Console.WriteLine("<remoteAddress> <remotePort> <listenPort>"); 
      return; 
     } 

     ServerConfiguration config; 

     try { 

      config = new ServerConfiguration(args[0], args[1], args[2]); 

     } catch(ArgumentException aex) { 

      Console.WriteLine("<remoteAddress> <remotePort> <listenPort>"); 
      Console.WriteLine(aex.Message); 
      return; 
     } 

     Thread serverThread = new Thread(ServerThread); 
     serverThread.Start(config); 

     Console.WriteLine("Enter \"q<enter>\" to stop program."); 

     String line; 
     while((line = Console.ReadLine()).ToUpperInvariant() != "Q"); 

     config.ServerSocket.Shutdown(SocketShutdown.Both); 
     config.ServerSocket.Close(); 
    } 

    private class ServerConfiguration { 

     public IPAddress RemoteAddress; 
     public UInt16 RemotePort; 
     public UInt16 ListenPort; 

     public ServerConfiguration(String remoteAddress, String remotePort, String listenPort) { 

      RemoteAddress = IPAddress.Parse(remoteAddress); 
      RemotePort = UInt16 .Parse(remotePort, NumberStyles.Integer, CultureInfo.InvariantCulture); 
      ListenPort = UInt16 .Parse(listenPort, NumberStyles.Integer, CultureInfo.InvariantCulture); 
     } 

     public Boolean RunServer = true; 

     public Socket ServerSocket; 
    } 

    private static void ServerThread(Object configObj) { 

     ServerConfiguration config = (ServerConfiguration)configObj; 

     /////////////////////////////////////// 
     // Setup 



     /////////////////////////////////////// 
     // Wait for client 

     Socket serverSocket = config.ServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Unspecified); 

     serverSocket.Bind(new IPEndPoint(IPAddress.Any, config.ListenPort)); 
     serverSocket.Listen(1); 

     Console.WriteLine("Now listening for port {0}, will forward to {1}.", config.ListenPort, config.RemotePort); 

     while(config.RunServer) { 

      Socket client = serverSocket.Accept(); 

      Thread clientThread = new Thread(ClientThread); 
      clientThread.Start(new ClientContext() { Config = config, Client = client }); 
     } 

    } 

    private class ClientContext { 

     public ServerConfiguration Config; 
     public Socket    Client; 
    } 

    private static void ClientThread(Object contextObj) { 

     ClientContext context = (ClientContext)contextObj; 

     Socket    client = context.Client; 
     ServerConfiguration config = context.Config; 

     /////////////////////////////////////// 
     // Connect to remote server. 

     IPEndPoint remoteEndPoint = new IPEndPoint(config.RemoteAddress, config.RemotePort); 

     Socket remote = new Socket(remoteEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Unspecified); 

     remote.Connect(remoteEndPoint); 

     /////////////////////////////////////// 
     // Run tunnel. 

     Console.WriteLine("Running tunnel."); 

     Byte[] buffer = new Byte[4096]; 

     for(;;) { 

      if(client.Available > 0) { 

       Int32 count = client.Receive(buffer); 
       if(count == 0) return; 

       remote.Send(buffer, count, SocketFlags.None); 
      } 

      if(remote.Available > 0) { 

       Int32 count = remote.Receive(buffer); 
       if(count == 0) return; 

       client.Send(buffer, count, SocketFlags.None); 
      } 
     } 
    } 

} 

}