Skip to content

Instantly share code, notes, and snippets.

@afish
Created March 11, 2023 12:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save afish/43f7a70a4c2f39e216729eef1eb1e89f to your computer and use it in GitHub Desktop.
Save afish/43f7a70a4c2f39e216729eef1eb1e89f to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.IO.Pipes;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace PipeProxy
{
class Program
{
static void Main(string[] args)
{
if (args.Length < 2)
{
Exit(Usage());
}
if (args[0] == "client")
{
Client.Start(args);
}
else if (args[0] == "pipe_server")
{
PipeServer.Start(args);
}
else
{
Exit(Usage());
}
}
private static string Usage()
{
return "PipeProxy.exe client local_port pipe_name\nPipeProxy.exe pipe_server destination_ip:destination_port pipe_name\nPipeProxy.exe port_server destination_ip:destination_port por_name";
}
private static void Exit(string message)
{
Console.WriteLine(message);
Environment.Exit(0);
}
}
public class Client
{
private static Random random = new Random();
public static void Start(string[] args)
{
var localPort = int.Parse(args[1]);
var pipeName = args[2];
Console.WriteLine($"Routing from {localPort} via {pipeName}");
IPEndPoint localEndPoint = new IPEndPoint(0, localPort);
Socket listener = new Socket(localEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
listener.Bind(localEndPoint);
listener.Listen(100);
var totalSent = new Dictionary<string, long>();
var totalReceived = new Dictionary<string, long>();
var totalExceptions = new Dictionary<string, long>();
var localDnss = new[] {"localhost"};
foreach (var localDns in localDnss)
{
totalSent[localDns] = 0;
totalReceived[localDns] = 0;
totalExceptions[localDns] = 0;
}
new Thread(() =>
{
while (true)
{
Console.Write(DateTime.Now);
Console.Write(" E/S/R:\t");
Console.WriteLine(string.Join("\t", localDnss.Select(dns => $"{dns}: {totalExceptions[dns]}/{totalSent[dns]}/{totalReceived[dns]}")));
Thread.Sleep(3000);
}
}).Start();
while (true)
{
try
{
while (true)
{
Socket socket = listener.Accept();
Console.WriteLine("New connection accepted to be scattered");
new Thread(() => Start(socket, localDnss, pipeName, random.Next(), totalSent, totalReceived, totalExceptions)).Start();
}
}
catch (Exception e)
{
Console.WriteLine("Exception " + e);
}
}
}
private static void Start(Socket clientSocket, string[] localDnss, string pipeName, int identifier,
Dictionary<string, long> sent, Dictionary<string, long> received, Dictionary<string, long> exceptions)
{
try
{
Console.WriteLine("Connecting");
var pipeClient = new NamedPipeClientStream(".", pipeName, PipeDirection.InOut, PipeOptions.Asynchronous);
pipeClient.Connect();
Console.WriteLine("Connected");
var fileSocket = new PipeSocket(clientSocket, pipeClient, r => received[localDnss[0]]+= r, s => sent[localDnss[0]]+=s);
fileSocket.Start();
}
catch (Exception e)
{
Console.WriteLine("Exception " + e);
}
}
}
class PipeServer
{
public static void Start(string[] args)
{
var destinationIp = args[1].Split(':')[0];
var destinationPort = int.Parse(args[1].Split(':')[1]);
var pipeName = args[2];
Console.WriteLine($"Routing to {destinationIp}:{destinationPort} via {pipeName}");
NamedPipeServerStream pipeServer = new NamedPipeServerStream(pipeName, PipeDirection.InOut, NamedPipeServerStream.MaxAllowedServerInstances, PipeTransmissionMode.Byte, PipeOptions.Asynchronous);
while (true)
{
try
{
while (true)
{
Thread.Sleep(1000);
pipeServer.WaitForConnection();
// I'm forcing IPv4 (IPv6 breaks with Cisco AnyConnect)
IPEndPoint remoteEP = new IPEndPoint(Dns.GetHostEntry(destinationIp).AddressList.First(a => a.AddressFamily == AddressFamily.InterNetwork), destinationPort);
Socket senderSocket = new Socket(remoteEP.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
senderSocket.Connect(remoteEP);
Console.WriteLine("Socket connected to {0}", senderSocket.RemoteEndPoint);
new Thread(() =>
{
var socket = new PipeSocket(senderSocket, pipeServer, r => { }, s => { });
socket.Start();
}).Start();
}
}
catch (Exception e)
{
Console.WriteLine("Exception " + e);
if (e.Message.Contains("being closed"))
{
pipeServer = new NamedPipeServerStream(pipeName, PipeDirection.InOut, NamedPipeServerStream.MaxAllowedServerInstances, PipeTransmissionMode.Byte, PipeOptions.Asynchronous);
}
}
}
}
}
public class PipeSocket
{
private Socket clientSocket;
private Stream pipeSocket;
private Action<int> received;
private Action<int> sent;
public PipeSocket(Socket socket, Stream pipeSocket, Action<int> received, Action<int> sent)
{
this.clientSocket = socket;
this.pipeSocket = pipeSocket;
this.received = received;
this.sent = sent;
}
public void Start()
{
Thread clientThread = new Thread(() =>
{
try
{
var buffer = new byte[100000];
while (true)
{
var read = clientSocket.Receive(buffer);
if (read == 0)
{
pipeSocket.Close();
return;
}
while (true)
{
try
{
pipeSocket.Write(buffer, 0, read);
sent(read);
break;
}
catch (Exception e2)
{
Console.WriteLine("Exception when writing to pipe" + e2);
}
}
}
}
catch (Exception e)
{
Console.WriteLine("Exception in client thread: " + e);
}
});
try
{
Thread senderThread = new Thread(KeepReading);
senderThread.Start();
}
catch (Exception e)
{
Console.WriteLine("Exception " + e);
}
clientThread.Start();
clientThread.Join();
}
private void KeepReading()
{
int totalRead = 0;
int toRead = 100024;
byte[] bytes = new byte[toRead];
try
{
while (true)
{
int howMuchRead = pipeSocket.Read(bytes, 0, toRead);
if (howMuchRead == 0)
break;
totalRead += howMuchRead;
received(howMuchRead);
clientSocket.Send(bytes, 0, howMuchRead, SocketFlags.None);
}
}
catch (Exception e)
{
Console.WriteLine("Exception while reading" + e);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment