Zpět na domů

Proxy na C# s FTP autentifikací

Univerzální proxy server na C# podporuje HTTP, HTTPS a FTP s automatickou autentifikací. Zachytává příkazy USER/PASS, používá asynchronní tunelování. Kompletní kód a instrukce k nastavení pro IT specialisty.

Vytváříme FTP proxy na C# s autoautentifikací
Advertisement 728x90

Univerzální proxy server v C# s podporou FTP autentizace

Proxy server v C# přijímá připojení na lokálním portu, určuje typ trafficu a přesměruje jej s zpracováním. Pro FTP je implementována automatická substituce přihlašovacích údajů: přerušování příkazů USER/PASS a nahrazení předdefinovaným loginem/heslem. Podporovány jsou HTTP, HTTPS (metoda CONNECT) a FTP bez externích knihoven, pouze TcpClient a NetworkStream.

Architektura a inicializace

Server používá TcpListener pro naslouchání na Loopback na specifikovaném portu. Přihlašovací údaje FTP jsou uloženy v ConcurrentDictionary pro vláknově bezpečný přístup.

public class FullProxyServer
{
    private readonly TcpListener _listener;
    private readonly ConcurrentDictionary<string, string> _ftpCredentials;
    
    public FullProxyServer(int proxyPort, string ftpServer, string ftpUser, string ftpPassword)
    {
        _listener = new TcpListener(IPAddress.Loopback, proxyPort);
        _ftpCredentials = new ConcurrentDictionary<string, string>();
        _ftpCredentials.TryAdd(ftpServer, $"{ftpUser}:{ftpPassword}");
    }
}

Spuštění v Program.Main:

Google AdInline article slot
static async Task Main(string[] args)
{
    var proxy = new FullProxyServer(8888, "ftp.example.com", "my_username", "my_password");
    await proxy.StartAsync();
}

Určení typu požadavku

Po přijetí dat od klienta je analyzován buffer:

string request = Encoding.ASCII.GetString(buffer, 0, bytesRead);

if (request.StartsWith("CONNECT"))
{
    await HandleConnectRequest(clientStream, request, id);
}
else if (request.Contains("FTP") || request.Contains("ftp"))
{
    await HandleFtpRequest(clientStream, buffer, bytesRead, id);
}
else
{
    await TunnelConnection(clientStream, buffer, bytesRead, id);
}

To umožňuje směrování trafficu podle protokolu.

Zpracování HTTPS přes CONNECT

Pro HTTPS je nastaven přímý tunel:

Google AdInline article slot
var parts = connectLine.Split(' ');
string host = targetParts[0];
int port = int.Parse(targetParts[1]);

var targetClient = new TcpClient();
await targetClient.ConnectAsync(host, port);

string response = "HTTP/1.1 200 Connection Established\r\n\r\n";
await clientStream.WriteAsync(responseBytes);

await TunnelBidirectional(clientStream, targetStream, id);

Obousměrné kopírování proudů je implementováno asynchronně s CancellationTokenSource pro elegantní ukončení.

private async Task TunnelBidirectional(NetworkStream clientStream, NetworkStream targetStream, string id)
{
    var cts = new CancellationTokenSource();
    
    var clientToTarget = CopyDataAsync(clientStream, targetStream, id, "C->T", cts.Token);
    var targetToClient = CopyDataAsync(targetStream, clientStream, id, "T->C", cts.Token);
    
    await Task.WhenAny(clientToTarget, targetToClient);
    cts.Cancel();
}

FTP-proxy s automatickou autentizací

Klíčová funkčnost – přerušování a modifikace FTP příkazů. Po obdržení USER od klienta je substituováno specifikované uživatelské jméno, na 331 (password required) – je odeslán PASS.

private async Task FtpTunnelWithAuth(NetworkStream clientStream, NetworkStream ftpStream,
                                      string username, string password, string id)
{
    bool authenticated = false;
    
    // Přerušujeme odpovědi FTP-serveru
    if (!authenticated && response.Contains("331")) // Požadavek na heslo
    {
        string passCmd = $"PASS {password}\r\n";
        await ftpStream.WriteAsync(passBytes);
    }
    
    // Přerušujeme příkazy klienta
    if (!authenticated && command.ToUpper().StartsWith("USER"))
    {
        // Nahrazujeme login na náš
        string userCmd = $"USER {username}\r\n";
        await ftpStream.WriteAsync(userBytes);
    }
}

Následující příkazy jsou tunelovány bez změn po úspěšné autentizaci (230).

Google AdInline article slot

Nastavení klientů

  • Prohlížeč: HTTP/HTTPS/FTP proxy — 127.0.0.1:8888
  • FileZilla nebo analog: Generic Proxy, host 127.0.0.1, port 8888

Logy zobrazují proces:

[abc12345] FTP požadavek
[abc12345] ->FTP: USER anonymous\r\n
[abc12345] FTP->: 331 User name okay, need password\r\n
[abc12345] Automatické odeslání hesla
[abc12345] FTP->: 230 User logged in\r\n
[abc12345] Autentizace úspěšná

Výhody implementace

Server je lehký, vejde se do jednoho souboru, používá async/await pro škálovatelnost. Vhodný pro:

  • Obcházení proxy omezení v korporátních sítích
  • Automatizaci přístupu k FTP bez změny nastavení klientů
  • Debugování trafficu s logováním
  • Rozšíření pro další protokoly s analýzou příkazů

Co je důležité

  • Automatická náhrada USER/PASS pro FTP bez upozornění klienta.
  • Asynchronní obousměrné tunelování s NetworkStream.
  • Vláknově bezpečné ukládání credentials v ConcurrentDictionary.
  • Podpora HTTPS CONNECT a jednoduchého HTTP.
  • Křížová platformnost na .NET 5+.

— Editorial Team

Advertisement 728x90

Číst dál