2009-07-12 14 views
5

Estoy escribiendo una aplicación de servidor tcp simple usando sockets. Por lo que sé, puedo obtener la dirección IP y el puerto del cliente después de llamar a accept().Rechazar la conexión desde un host

Ahora supongamos que tengo una lista de ban y quiero prohibir algunas direcciones de IP de mi servidor. ¿Hay una mejor manera que aceptar la conexión y luego dejarla caer?

¿Hay alguna forma de obtener la IP y el puerto del cliente antes de aceptar la conexión? Si tenemos accept() ¿por qué no tenemos algo como refuse()? ¿Hay alguna manera de rechazar la conexión o simplemente ignorar el intento de conexión de un host?

+0

¿podría agregar etiquetas para el idioma que utiliza? No soy un experto en Sockets, pero tengo algo de experiencia de Actionscript y C# /. NET – BerggreenDK

+2

Y el sistema operativo también ... Windows vs Unix podría hacer una gran diferencia aquí. No creo que haya una solución portátil, pero podría estar equivocado. –

Respuesta

13

La aplicación TCP normalmente completa el TCP de 3 vías apretón de manos antes de que el proceso de usuario, incluso tiene acceso a la conexión, y la función accept() simplemente obtiene la siguiente conexión de la cola. Por lo tanto, es demasiado tarde para pretender que el servidor no funciona. Esto funciona de la misma manera para los datos TCP regulares; la implementación de TCP no espera a que la aplicación realmente entre recv() los datos antes de que se envíe un TCP ACK. Esto evita que el otro lado retransmita innecesariamente paquetes que se recibieron correctamente, y permite que el rendimiento permanezca alto, incluso cuando la aplicación se empantana con otras cosas. En el caso de las conexiones nuevas (paquetes SYN), esto también permite que el kernel se proteja a sí mismo (y a la aplicación) de los ataques de inundación SYN.

Aunque no son portátiles, muchas plataformas proporcionan algún tipo de capacidad de firewall que permitirá filtrar conexiones entrantes basadas en la dirección IP/puerto. Sin embargo, eso generalmente se configura en todo el sistema y no por una aplicación individual.

+0

Entonces, si escucho en un puerto, ¿la conexión se establecerá en segundo plano independientemente de lo que quiera o no? – Calmarius

+1

Llamar listen() le dice al sistema operativo que desea cualquier conexión que pueda establecerse exitosamente en su puerto. A menos que filtre el paquete en un nivel inferior (regla de firewall), responderá a cualquier solicitud de conexión a este puerto. Si decide que no desea una conexión en particular, siempre puede cerrarla(), que es lo que harán algunas de las otras respuestas aquí. – mark4o

4

En ventanas: mira WSAAccept, puede ser que es lo que necesita:

SOCKET WSAAccept(
    __in  SOCKET s, 
    __out struct sockaddr *addr, 
    __inout LPINT addrlen, 
    __in  LPCONDITIONPROC lpfnCondition, 
    __in  DWORD dwCallbackData 
); 

lpfnCondition - la dirección de una función opcional condición, especificado por la aplicación que va a hacer una aceptación/rechazo de decisiones basado en la información de la persona que llama pasada como parámetros, y opcionalmente cree o ensamble un grupo de socket asignando un valor apropiado al parámetro de resultado g de esta función. Si este parámetro es NULL, entonces no se llama a ninguna función de condición.

Para linux solución vea: GNU Común C++ - clase TCPSocket, tiene los métodos de aceptación(), y rechazo().

virtual bool TCPSocket::onAccept (  const InetHostAddress &  ia, 
     tpport_t port 
    ) [inline, protected, virtual] 

Un método de llamar a una clase TCPSocket derivado que actúa como un servidor cuando una solicitud de conexión es aceptada.

El servidor puede implementar reglas específicas de protocolo para excluir el socket remoto de ser aceptado al devolver falso. El método Peek también se puede usar para este propósito.


Sin embargo, sólo puede estrecha toma después de aceptar si pre-condición es falsa :)

+0

Si no hay otra solución, aceptaré y cerraré el socket inmediatamente, como abrir una puerta para preguntar quién es usted y cerrarla si está prohibido ... Pero no quiero abrir esa puerta en absoluto. Quiero hacer que los usuarios prohibidos piensen que la máquina del servidor simplemente está inactiva. – Calmarius

+0

Lo que desea es más elegante, sin embargo, en el desarrollo, necesitamos un equilibrio entre las funciones de agradecimiento y el tiempo/dinero gastado en él. Como dijo XP: hazlo de la manera más simple, luego puedes venir y refactorizarlo. –

1

TCP Wrapper se ha extendido mucho en las plataformas tipo UNIX. Sí, la conexión solo se verifica después deaccept; sin embargo, si lo hace de todos modos, también podría usar la misma configuración que todos los demás.

En esencia, el programa es o bien ejecutar con tcpd o modificados para utilizar libwrap directamente, así:

#include <tcpd.h> 
connfd = accept(listenfd, (struct sockaddr *)&addr, &addrlen); 
if (!hosts_ctl("my_program", STRING_UNKNOWN, inet_ntoa(addr.sin_addr), STRING_UNKNOWN)) { 
    fprintf(stderr, "Client %s connection disallowed\n", inet_ntoa(addr.sin_addr)); 
    close(connfd); 
} 

Luego se configuran /etc/hosts.allow y /etc/hosts.deny de acuerdo a sus deseos, por ejemplo,

 
# /etc/hosts.allow 
my_program: 127.0.0.1 10. 192.168. 

# /etc/hosts.deny 
my_program: ALL 

Esto hará que my_program de rechazar todo intento de conexión desde direcciones que no son locales, pero puede ser cambiado sin tocar my_program en absoluto.

-1

el concepto de no aceptar conexión basada en la dirección IP no funcionará si está transmitiendo NAT.

Cuestiones relacionadas