Iptables: abbinare il traffico in uscita con conntrack e proprietario. Funziona con strane gocce


11

Nel mio script iptables ho sperimentato la scrittura di regole il più finemente dettagliate possibile. Limito a quali utenti è consentito utilizzare quali servizi, in parte per motivi di sicurezza e in parte come esercizio di apprendimento.

Usare iptables v1.4.16.2 su Debian 6.0.6 con il kernel 3.6.2.

Tuttavia ho riscontrato un problema che ancora non capisco ...

porte in uscita per tutti gli utenti

Funziona perfettamente. Non ho regole di tracciamento dello stato generico.

## Porta in uscita 81
$ IPTABLES -A OUTPUT -p tcp --dport 81 -m conntrack --ctstate NUOVO, STABILITO -j ACCETTA
$ IPTABLES -A INPUT -p tcp --sport 81 -s $ MYIP -m conntrack --ctstate STTABLISHED -j ACCEPT

porte in uscita con corrispondenza dell'utente

## porta 80 in uscita per account utente
$ IPTABLES -A OUTPUT --match owner --uid-owner useraccount -p tcp --dport 80 -m conntrack --ctstate NUOVO, STABILITO --sport 1024: 65535 -j ACCEPT
$ IPTABLES -A INPUT -p tcp --sport 80 --dport 1024: 65535 -d $ MYIP -m conntrack --ctstate STTABLISHED -j ACCEPT

Ciò consente alla porta 80 di uscire solo per l'account "accountutente", ma le regole come questa per il traffico TCP presentano problemi.

## Registro in uscita predefinito + regole di blocco
$ IPTABLES -A USCITA -j LOG --log-prefisso "BAD OUTGOING" --log-ip-options --log-tcp-options --log-uid
$ IPTABLES -A OUTPUT -j DROP

Il problema

Quanto sopra funziona, l'utente "useraccount" può ottenere i file perfettamente bene. Nessun altro utente sul sistema può effettuare connessioni in uscita alla porta 80.

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

Ma la wget sopra lascia x7 voci rilasciate nel mio syslog:

18 ott 02:00:35 xxxx kernel: BAD OUTGOING 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 FINESTRA = 979 RES = 0x00 ACK URGP = 0  

Non ricevo queste gocce per regole simili con il traffico UDP. Sono già in atto regole che limitano gli utenti che possono effettuare richieste DNS.

I pacchetti ACK in uscita rilasciati sembrano provenire dall'account root (URGP = 0) che non capisco. Anche quando cambio account utente per root.

Credo che i pacchetti ACK siano classificati come nuovi perché conntrack inizia a tracciare le connessioni dopo il 3 ° passaggio dell'handshake a 3 vie, ma perché vengono eliminati?

Queste gocce possono essere tranquillamente ignorate?

modificare

Quindi vedo spesso regole come queste, che funzionano bene per me:

$ IPTABLES -A OUTPUT -s $ MYIP -p tcp -m tcp --dport 80 -m state --state NEW, STABILITO -j ACCEPT
$ IPTABLES -A INPUT -p tcp -m tcp --sport 80 -d $ MYIP -m state --state STTABLISHED -j ACCEPT

Ho scambiato "-m state --state" con "-m conntrack --ctstate" poiché la corrispondenza dello stato è apparentemente obsoleta.

È buona norma disporre di regole generiche di tracciamento dello stato? Le regole di cui sopra non sono considerate corrette?

Per uno stretto controllo delle connessioni degli utenti in uscita sarebbe meglio qualcosa di simile?

$ IPTABLES -A INPUT -m conntrack --ctstate STTABLISHED -j ACCEPT
$ 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 proprietario --uid-owner useraccount -j ACCEPT

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

Potresti pubblicare tutte le regole tra cui la catena FORWARD e la tabella nat se questo host instrada anche il traffico dalla LAN.
Serge,

Questo host non sta eseguendo alcun routing, il traffico proviene dalla macchina con queste regole. Ho pubblicato solo le regole pertinenti per il traffico in uscita specifico.
arcX,

Risposte:


16

Per farla breve, quell'ACK è stato inviato quando il socket non apparteneva a nessuno. Invece di consentire i pacchetti relativi a un socket che appartiene all'utente x, consentire i pacchetti relativi a una connessione avviata da un socket dall'utente x.

La storia più lunga.

Per capire il problema, aiuta a capire come funzionano wgetle richieste HTTP in generale.

Nel

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

wgetstabilisce una connessione TCP cachefly.cachefly.nete, una volta stabilita, invia una richiesta nel protocollo HTTP che dice: "Per favore, inviami il contenuto di /10mb.test( GET /10mb.test HTTP/1.1) e, a proposito, potresti per favore non chiudere la connessione dopo aver finito ( Connection: Keep-alive). Il motivo ciò accade perché nel caso in cui il server risponda con un reindirizzamento per un URL sullo stesso indirizzo IP, può riutilizzare la connessione.

Ora il server può rispondere con "entrambi i dati che hai richiesto, fai attenzione, è grande (10 MB Content-Length: 10485760) e sì, lascerò la connessione aperta". Oppure, se non conosce la dimensione dei dati, "Ecco i dati, mi dispiace non poter lasciare la connessione aperta, ma dirò quando è possibile interrompere il download dei dati chiudendo la mia fine della connessione".

Nell'URL sopra, siamo nel primo caso.

Quindi, non appena wgetha ottenuto le intestazioni per la risposta, sa che il suo lavoro viene svolto dopo aver scaricato 10 MB di dati.

Fondamentalmente, ciò che wgetfa è leggere i dati fino a quando non sono stati ricevuti 10 MB e terminati. Ma a quel punto, c'è ancora molto da fare. E il server? È stato detto di lasciare aperta la connessione.

Prima di uscire, wgetchiude ( closechiamata di sistema) il descrittore di file per il socket. Al termine, il closesistema termina di riconoscere i dati inviati dal server e invia un messaggio FINper dire: "Non invierò più dati". A quel punto closeritorna ed wgetesce. Non esiste più alcun socket associato alla connessione TCP (almeno non di proprietà di alcun utente). Tuttavia non è ancora finito. Alla ricezione FIN, il server HTTP visualizza end-of-file quando legge la richiesta successiva dal client. In HTTP, ciò significa "niente più richieste, chiuderò la mia fine". Quindi invia anche la sua FIN, per dire "Nemmeno io invierò nulla, quella connessione sta andando via".

Dopo aver ricevuto quel FIN, il client invia un "ACK". Ma, a quel punto, wgetè scomparso da tempo, quindi ACK non proviene da nessun utente. Ecco perché è bloccato dal tuo firewall. Poiché il server non riceve l'ACK, invierà la FIN ripetutamente fino a quando non si arrenderà e vedrai più ACK rilasciati. Ciò significa anche che facendo cadere quegli ACK, stai inutilmente usando le risorse del server (che deve mantenere un socket nello stato LAST-ACK) per un bel po 'di tempo.

Il comportamento sarebbe stato diverso se il client non avesse richiesto "Keep-alive" o il server non avesse risposto con "Keep-alive".

Come già accennato, se stai usando il tracker di connessione, quello che vuoi fare è far passare ogni pacchetto negli stati STABILITO e CORRELATO e preoccuparti solo dei NEWpacchetti.

Se consenti i NEWpacchetti dall'utente xma non i pacchetti dell'utente y, xpasseranno altri pacchetti per le connessioni stabilite dall'utente e poiché non è possibile stabilire connessioni da parte dell'utente y(poiché stiamo bloccando i NEWpacchetti che stabilirebbero la connessione), non ci sarà alcun pacchetto per le yconnessioni utente che attraversano.


3

Ciò consente l'uscita 80 della porta solo per l'account "accountutente"

- beh, almeno le regole che hai mostrato non lo implicano, in realtà.

C'è anche una stanza per un consiglio: non fare il controllo degli utenti sui flussi ESTABLISHED, basta fare il controllo su NUOVO. Inoltre non vedo alcun motivo nel controllare la porta di origine quando si controlla Incoming ESTABLISHED, qual è la differenza che porta era, è già nello stato ESTABLISHED dal PoV di Conntrack. Il firewall dovrebbe essere il più semplice possibile ma efficiente, quindi l' approccio del rasoio di Occam è la soluzione migliore.


1
Grazie per il consiglio. Di solito sono tutto per semplicità, ma non è questo il punto di questo particolare esercizio.
arcX,

1
@arcX, questo esercizio può fallire a causa di essere troppo complesso e incoerente - IOW, il comportamento che vedi non può essere dovuto agli interni di netfilter (bug, stranezze), ma al modo in cui lo usi. Prova prima a semplificare il
poige,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.