2010-04-29 4 views
5

Tengo un programa que escucha en el puerto 443 y luego lo redirecciona a un servidor local SSH o HTTPS dependiendo del protocolo detectado.Transmisión transparente: ¿cómo pasar el socket al servidor local sin modificaciones?

El programa hace esto conectándose al servidor local y transmitiendo todos los datos a través de su propio proceso.

Sin embargo, esto provoca que el host de origen en los servidores locales se registre como localhost.

¿Hay alguna manera de pasar el zócalo directamente al proceso del servidor local (en lugar de simplemente hacer una nueva conexión TCP) para que se retengan los parámetros de sockaddr_in (o)?

La plataforma para esto es Linux.

Respuesta

6

Si tiene control sobre los procesos del servidor local, puede hacerlo. Cree una conexión de socket de dominio UNIX persistente entre el proceso de proxy y el proceso de servidor, luego use sendmsg() en ese socket de dominio UNIX para pasar un mensaje SCM_RIGHTS que contiene el descriptor de archivo del socket TCP. El proceso proxy puede cerrar su manejador al socket TCP.

Cuando el proceso del servidor pasa un descriptor de archivo del proxy en un mensaje SCM_RIGHTS, solo tiene que agregarlo a su conjunto normal de sockets de cliente, como si hubiera venido de accept().

+0

Gracias que es muy interesante, aunque por desgracia no tengo co Controle los servidores locales; son esencialmente cajas negras –

7

Aquí hay un fragmento de código tomado de stunnel (desde client.c en la función local_bind si desea ver todo el código).

#ifdef IP_TRANSPARENT 
int on=1; 
if(c->opt->option.transparent) { 
    if(setsockopt(c->fd, SOL_IP, IP_TRANSPARENT, &on, sizeof on)) 
     sockerror("setsockopt IP_TRANSPARENT"); 
    /* ignore the error to retain Linux 2.2 compatibility */ 
    /* the error will be handled by bind(), anyway */ 
} 
#endif /* IP_TRANSPARENT */ 

memcpy(&addr, &c->bind_addr.addr[0], sizeof addr); 
if(ntohs(addr.in.sin_port)>=1024) { /* security check */ 
    if(!bind(c->fd, &addr.sa, addr_len(addr))) { 
     s_log(LOG_INFO, "local_bind succeeded on the original port"); 
     return; /* success */ 
    } 
    if(get_last_socket_error()!=EADDRINUSE 
#ifndef USE_WIN32 
      || !c->opt->option.transparent 
#endif /* USE_WIN32 */ 
      ) { 
     sockerror("local_bind (original port)"); 
     longjmp(c->err, 1); 
    } 
} 

Anteriormente, c-> bind_addr se establece en la dirección de la conexión entre pares con este código:

else if(c->opt->option.transparent) 
    memcpy(&c->bind_addr, &c->peer_addr, sizeof(SOCKADDR_LIST)); 

La documentación stunnel contiene este consejo para los últimos kernels de Linux:

El modo remoto (2.2.x y> = 2.6.28) requiere que stunnel se ejecute como root. La opción setuid también romperá esta funcionalidad.

Linux> = 2.6.28 requiere la siguiente configuración de iptables y enrutamiento (posiblemente en el archivo /etc/rc.local o equivalente):

iptables -t mangle -N DIVERT 
iptables -t mangle -A PREROUTING -p tcp -m socket -j DIVERT 
iptables -t mangle -A DIVERT -j MARK --set-mark 1 
iptables -t mangle -A DIVERT -j ACCEPT 
ip rule add fwmark 1 lookup 100 
ip route add local 0.0.0.0/0 dev lo table 100 
+0

¡Gracias por el consejo! pero desafortunadamente esa técnica no parece funcionar cuando el host de destino es localhost –

+0

@Luca Farber: agregué más información extraída de las preguntas frecuentes de stunnel. Trata eso. –

+0

Hmm, a pesar de jugar mucho con él, parece que no puedo conseguirlo más allá de connect(), donde se cuelga. "netstat -a -n" muestra la conexión en estado de SYN_SENT (con el host/puerto remoto como fuente y 127.0.0.1:localport como destino). –

1

Usando https://stackoverflow.com/a/2741535/388191, es posible hacer esto con el tráfico al servidor local mediante el uso de CONNMARK para realizar un seguimiento de la conexión transparente locales Recepción y marcar los paquetes salientes para desviar de nuevo a la máquina local:

iptables -t mangle -N DIVERT 
iptables -t mangle -A PREROUTING -i lo -p tcp -m socket -j DIVERT 
iptables -t mangle -A DIVERT -j CONNMARK --set-mark 2 
iptables -t mangle -A DIVERT -j ACCEPT 
iptables -t mangle -A OUTPUT -m connmark --mark 2 -j MARK --set-mark 1 
ip rule add fwmark 1 lookup 100 
ip route add local 0.0.0.0/0 dev lo table 100 
Cuestiones relacionadas