如何在.net上创建软件路由器?

本文关键字:软件 路由器 创建 net | 更新日期: 2023-09-27 18:06:56

我怎么能创建一个程序透明地转发连接到新的IP地址/端口?

例如,如果一个客户端发起一个TCP连接,IP地址为111.111.111.111,TCP端口为111,那么该程序可以被配置为转发该数据包和后续数据包,IP/端口为222.222.222.222:222。

我说的透明是指:

  • 最小性能损失
  • 无需调整客户端或最终目的地软件/配置(就像透明Web代理不需要在浏览器中设置显式设置)
  • 处理尽可能低层次的操作系统网络层

我想在。net, c#和Windows中这样做。但是我不想创建一个简单的TCP代理,原因有很多,但没有说明。如果无法做到这一点,在没有可能的解决方案的情况下,这可能是一个可以接受的答案。

如何在.net上创建软件路由器?

这是我几周前为一个实验写的:

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 );
            }
        }
    }
}
}