Iptables: correspondencia del tráfico saliente con conntrack y propietario. Funciona con gotas extrañas.


11

En mi script de iptables, he estado experimentando con la escritura de reglas tan finas como sea posible. Limito qué usuarios pueden usar qué servicios, en parte por seguridad y en parte como un ejercicio de aprendizaje.

Usando iptables v1.4.16.2 en Debian 6.0.6 ejecutando el kernel 3.6.2.

Sin embargo, he encontrado un problema que aún no entiendo ...

puertos de salida para todos los usuarios

Esto funciona perfectamente bien. No tengo reglas genéricas de seguimiento de estado.

## Puerto de salida 81
$ IPTABLES -A OUTPUT -p tcp --dport 81 -m conntrack --ctstate NUEVO, ESTABLECIDO -j ACEPTAR
$ IPTABLES -A INPUT -p tcp --sport 81 -s $ MYIP -m conntrack --ctstate ESTABLISHED -j ACCEPT

puertos de salida con coincidencia de usuario

## puerto de salida 80 para cuenta de uso
$ IPTABLES -A SALIDA --propietario propietario --uid-propietario useraccount -p tcp --dport 80 -m conntrack --ctstate NUEVO, ESTABLECIDO --sport 1024: 65535 -j ACEPTAR
$ IPTABLES -A INPUT -p tcp --sport 80 --dport 1024: 65535 -d $ MYIP -m conntrack --ctstate ESTABLISHED -j ACCEPT

Esto permite que el puerto 80 salga solo para la cuenta "useraccount", pero reglas como esta para el tráfico TCP tienen problemas.

## Registros salientes predeterminados + reglas de bloqueo
$ IPTABLES -A OUTPUT -j LOG --log-prefix "BAD OUTGOING" --log-ip-options --log-tcp-options --log-uid
$ IPTABLES -A SALIDA -j DROP

La cuestión

Lo anterior funciona, el usuario "useraccount" puede obtener archivos perfectamente bien. Ningún otro usuario en el sistema puede hacer conexiones salientes al puerto 80.

useraccount @ host: $ wget http://cachefly.cachefly.net/10mb.test

Pero el wget anterior deja entradas caídas x7 en mi syslog:

18 de octubre 02:00:35 kernel xxxx: MALA SALIDA IN = OUT = eth0 SRC = xx.xx.xx.xx DST = 205.234.175.175 LEN = 40 TOS = 0x00 PREC = 0x00 TTL = 64 ID = 12170 DF PROTO = TCP SPT = 37792 DPT = 80 SEQ = 164520678 ACK = 3997126942 VENTANA = 979 RES = 0x00 ACK URGP = 0  

No obtengo estas caídas para reglas similares con tráfico UDP. Ya tengo reglas establecidas que limitan qué usuarios pueden realizar solicitudes de DNS.

Los paquetes ACK salientes descartados parecen provenir de la cuenta raíz (URGP = 0) que no entiendo. Incluso cuando cambio useraccount por root.

Creo que los paquetes ACK se clasifican como nuevos porque conntrack comienza a rastrear las conexiones después del tercer paso del protocolo de enlace de 3 vías, pero ¿por qué se descartan?

¿Se pueden ignorar estas gotas de forma segura?

Editar

Así que a menudo veo reglas como estas, que funcionan bien para mí:

$ IPTABLES -A SALIDA -s $ MYIP -p tcp -m tcp --dport 80 -m estado - estado NUEVO, ESTABLECIDO -j ACEPTAR
$ IPTABLES -A INPUT -p tcp -m tcp --sport 80 -d $ MYIP -m state --state ESTABLISHED -j ACCEPT

Cambié "-m state --state" por "-m conntrack --ctstate" ya que la coincidencia de estado es aparentemente obsoleta.

¿Es una buena práctica tener reglas genéricas de seguimiento de estado? ¿Las reglas anteriores no se consideran correctas?

Para un control estricto sobre las conexiones de los usuarios salientes, ¿sería mejor algo como esto?

$ IPTABLES -A ENTRADA -m conntrack --ctstate ESTABLECIDO -j ACEPTAR
$ IPTABLES -A OUTPUT -m conntrack --ctstate ESTABLISHED -j ACCEPT

$ IPTABLES -A OUTPUT -p tcp --dport 80 -s $ SERVER_IP_TUNNEL -m conntrack --ctstate NEW -m owner --uid-owner useraccount -j ACCEPT

$ IPTABLES -A OUTPUT -p tcp --dport 80 -s $ SERVER_IP_TUNNEL -m conntrack --ctstate NEW -m owner --uid-owner otheraccount -j ACCEPT

¿Podría publicar todas las reglas, incluida la cadena FORWARD y la tabla nat si este host también está enrutando el tráfico desde LAN.
Serge

Este host no está haciendo ningún enrutamiento, el tráfico se origina en la máquina con estas reglas. Solo publiqué las reglas relevantes para el tráfico saliente específico.
arcX

Respuestas:


16

Para abreviar una larga historia, ese ACK se envió cuando el socket no pertenecía a nadie. En lugar de permitir paquetes que pertenecen a un socket que pertenece al usuario x, permita paquetes que pertenezcan a una conexión iniciada por un socket del usuario x.

La historia más larga.

Para comprender el problema, es útil comprender cómo funcionan wgetlas solicitudes HTTP en general.

En

wget http://cachefly.cachefly.net/10mb.test

wgetestablece una conexión TCP cachefly.cachefly.nety, una vez establecida, envía una solicitud en el protocolo HTTP que dice: "Por favor, envíeme el contenido de /10mb.test( GET /10mb.test HTTP/1.1) y, por cierto, ¿podría cerrar la conexión una vez que haya terminado? Connection: Keep-alive). lo hace porque en caso de que el servidor responda con una redirección para una URL en la misma dirección IP, puede reutilizar la conexión.

Ahora el servidor puede responder con: "aquí vienen los datos que solicitó, tenga cuidado con su tamaño de 10 MB ( Content-Length: 10485760), y sí, dejo la conexión abierta". O si no conoce el tamaño de los datos, "Aquí están los datos, lo siento, no puedo dejar la conexión abierta, pero le diré cuándo puede dejar de descargar los datos cerrando mi final de la conexión".

En la URL anterior, estamos en el primer caso.

Entonces, tan pronto como wgethaya obtenido los encabezados para la respuesta, sabe que su trabajo se realiza una vez que ha descargado 10 MB de datos.

Básicamente, lo que wgethace es leer los datos hasta que se hayan recibido 10 MB y salir. Pero en ese punto, hay más por hacer. ¿Qué hay del servidor? Se le ha dicho que deje la conexión abierta.

Antes de salir, wgetcierra ( closellamada al sistema) el descriptor de archivo para el socket. Luego, el closesistema termina de reconocer los datos enviados por el servidor y envía un mensaje FINpara decir: "No enviaré más datos". En ese punto closeregresa y wgetsale. Ya no hay ningún socket asociado a la conexión TCP (al menos ninguno de los cuales es propiedad de ningún usuario). Sin embargo, aún no está terminado. Al recibir eso FIN, el servidor HTTP ve el final del archivo al leer la siguiente solicitud del cliente. En HTTP, eso significa "no más solicitudes, cerraré mi final". Por lo tanto, también envía su FIN, para decir: "No enviaré nada tampoco, esa conexión se va a ir".

Al recibir esa FIN, el cliente envía un "ACK". Pero, en ese punto, ya no wgetexiste, por lo que ACK no es de ningún usuario. Es por eso que está bloqueado por su firewall. Debido a que el servidor no recibe el ACK, enviará el FIN una y otra vez hasta que se dé por vencido y verá más ACK caídos. Eso también significa que al soltar esos ACK, está utilizando innecesariamente los recursos del servidor (que necesita mantener un socket en el estado ÚLTIMO ACK) durante bastante tiempo.

El comportamiento habría sido diferente si el cliente no hubiera solicitado "Keep-alive" o el servidor no hubiera respondido con "Keep-alive".

Como ya se mencionó, si está utilizando el rastreador de conexión, lo que quiere hacer es dejar pasar cada paquete en los estados ESTABLECIDO y RELACIONADO y solo preocuparse por los NEWpaquetes.

Si permite NEWpaquetes de usuario xpero no paquetes de usuario y, entonces xpasarán otros paquetes para conexiones establecidas por usuario , y debido a que no puede haber conexiones establecidas por usuario y(ya que estamos bloqueando los NEWpaquetes que establecerían la conexión), no habrá ningún paquete para las yconexiones de usuario que se realicen.


3

Esto permite el puerto 80 solo para la cuenta "useraccount"

- Bueno, al menos las reglas que has mostrado no implican esto, en realidad.

También hay un lugar para el asesoramiento: no verifique los usuarios en las transmisiones ESTABLECIDAS, solo verifique NUEVO. Tampoco veo un punto en verificar el puerto de origen cuando verifico Entrante ESTABLECIDO, cuál es la diferencia de qué puerto era, ya está en estado ESTABLECIDO del PoV de conntrack. El cortafuegos debe ser lo más simple posible pero eficiente, por lo que el enfoque de navaja de Occam es la mejor opción.


1
Gracias por el consejo. Por lo general, estoy a favor de la simplicidad, pero ese no es el objetivo de este ejercicio en particular.
arcX

1
@arcX, este ejercicio puede fallar debido a que es demasiado complejo e inconsistente: IOW, el comportamiento que ve no puede deberse a los elementos internos del filtro de red (errores, peculiaridades), sino a la forma en que lo usa. Intente simplificar el conjunto de reglas primero ...
poige
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.