Servidor Proxy Universal en C# con Soporte para Autenticación FTP
Este servidor proxy en C# escucha en un puerto local, detecta los tipos de tráfico y los reenvía con un manejo inteligente. Para FTP, inyecta automáticamente las credenciales interceptando los comandos USER/PASS y sustituyéndolos por tus datos de login. Soporta HTTP, HTTPS (vía CONNECT) y FTP usando solo TcpClient y NetworkStream integrados, sin librerías externas.
Arquitectura e Inicialización
El servidor usa TcpListener para monitorear la interfaz de loopback en el puerto elegido. Las credenciales FTP se almacenan en un ConcurrentDictionary para acceso thread-safe.
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}");
}
}
Lánzalo desde Program.Main:
static async Task Main(string[] args)
{
var proxy = new FullProxyServer(8888, "ftp.example.com", "my_username", "my_password");
await proxy.StartAsync();
}
Detección del Tipo de Solicitud
Tras recibir datos del cliente, se analiza el 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);
}
Esto enruta el tráfico según el protocolo.
Manejo de HTTPS vía CONNECT
Para HTTPS, establece un túnel directo:
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);
La copia de streams bidireccional es completamente asíncrona con CancellationTokenSource para cierres limpios.
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();
}
Proxy FTP con Autenticación Automática
La función estrella: interceptar y modificar comandos FTP. Cuando el cliente envía USER, se sustituye por tu nombre de usuario. Ante la respuesta 331 del servidor (se necesita contraseña), se envía PASS automáticamente.
private async Task FtpTunnelWithAuth(NetworkStream clientStream, NetworkStream ftpStream,
string username, string password, string id)
{
bool authenticated = false;
// Interceptar respuestas del servidor FTP
if (!authenticated && response.Contains("331")) // Se solicita contraseña
{
string passCmd = $"PASS {password}\r\n";
await ftpStream.WriteAsync(passBytes);
}
// Interceptar comandos del cliente
if (!authenticated && command.ToUpper().StartsWith("USER"))
{
// Sustituir por nuestro usuario
string userCmd = $"USER {username}\r\n";
await ftpStream.WriteAsync(userBytes);
}
}
Tras la autenticación (respuesta 230), todos los comandos se tunelizan sin cambios.
Configuración del Cliente
- Navegador: Configura el proxy HTTP/HTTPS/FTP en 127.0.0.1:8888
- FileZilla o similar: Proxy genérico, host 127.0.0.1, puerto 8888
Los logs capturan el flujo:
[abc12345] Solicitud FTP
[abc12345] ->FTP: USER anonymous\r\n
[abc12345] FTP->: 331 Nombre de usuario correcto, necesita contraseña\r\n
[abc12345] Envío automático de contraseña
[abc12345] FTP->: 230 Usuario conectado\r\n
[abc12345] Autenticación exitosa
Ventajas Principales
Este servidor ligero cabe en un solo archivo y aprovecha async/await para escalabilidad. Ideal para:
- Saltarse restricciones de proxy en redes corporativas
- Automatizar acceso FTP sin modificar configuraciones del cliente
- Depurar tráfico con logs detallados
- Extender a otros protocolos mediante análisis de comandos
Conclusiones Clave
- Sustitución automática de USER/PASS para FTP sin que el cliente lo note.
- Tunelización bidireccional asíncrona con NetworkStream.
- Almacenamiento thread-safe de credenciales vía ConcurrentDictionary.
- Soporte completo para HTTPS CONNECT y HTTP básico.
- Multiplataforma en .NET 5+.
— Editorial Team
Aún no hay comentarios.