Ho un programma che vorrei testare in modalità offline senza interrompere la mia rete effettiva. Questo programma dovrebbe comunque connettersi a socket locali, inclusi socket di dominio unix e loopback. Deve anche ascoltare in loopback ed essere visibile ad altre app.
Ma i tentativi di connessione a una macchina remota dovrebbero fallire.
Mi piacerebbe avere un'utilità che funzioni come strace
/unshare
/sudo
ed esegue semplicemente un comando con Internet (e LAN) nascosti e tutto il resto ancora funzionante:
$ offline my-program-to-test
Questa domanda ha suggerimenti per la risposta:bloccare l'accesso alla rete di un processo?
Ci sono un paio di suggerimenti lì, come eseguire come un altro utente quindi manipolare iptables o unshare -n
. Ma in entrambi i casi non conosco l'incantesimo per ottenere socket di dominio unix e loopback da condividere con il sistema principale:le risposte a questa domanda mi dicono solo come annullare la condivisione dell'intero rete.
Il programma che sto testando deve ancora connettersi al mio server X e dbus e persino essere in grado di ascoltare in loopback le connessioni da altre app sul sistema.
Idealmente vorrei evitare di creare chroot o utenti o VM o simili, poiché diventa fastidioso quanto lo è scollegare il cavo di rete. cioè il punto della domanda è come posso renderlo semplice come un sudo
.
Mi piacerebbe che il processo venisse eseguito normalmente al 100%, tranne per il fatto che le chiamate di rete che specificano un indirizzo non locale fallirebbero. Idealmente mantenendo lo stesso uid, la stessa homedir, la stessa pwd, lo stesso tutto tranne... offline.
Sto usando Fedora 18, quindi le risposte Linux non portabili vanno bene (previste, anche).
Sono anche felice di risolverlo scrivendo un programma C, se è quello che è coinvolto, quindi le risposte che implicano la scrittura di C vanno bene. Semplicemente non so quali syscall dovrebbe fare il programma C per revocare l'accesso alla rete esterna mantenendo la rete locale.
Qualsiasi sviluppatore che tenti di supportare la "modalità offline" apprezzerebbe probabilmente questa utility!
Risposta accettata:
La risposta tradizionale è eseguire il programma come un altro utente e utilizzare iptables -m owner
. In questo modo, la configurazione di rete è condivisa. Tuttavia, con l'avvento degli spazi dei nomi, esiste un modo più semplice.
Con gli spazi dei nomi, annulli la condivisione della rete, quindi crei un collegamento di rete virtuale se hai bisogno di un accesso limitato alla rete.
Per condividere i socket di dominio unix, tutto ciò che serve è avere un kernel sufficientemente recente, dopo questa patch del 2010, quindi 2.6.36 o versioni successive (che è il caso di tutte le distribuzioni correnti al momento della scrittura eccetto RHEL/CentOS).
Eseguire il programma nel proprio spazio dei nomi IP. Prima di avviare il programma, stabilire un'interfaccia ethernet virtuale. Non sembra esserci molta documentazione; Ho trovato l'incantesimo giusto in alcuni blog:
- Spazi dei nomi Linux su Arista
- Alcune note sulle interfacce veth di waldner
- Introduzione agli spazi dei nomi di rete Linux di Scott Lowe
Nello snippet di seguito, utilizzo ns_exec
è il wrapper di setns
elencato nella pagina man per visualizzare il lato host del collegamento di rete dal processo in esecuzione nello spazio dei nomi limitato. In realtà non ne hai bisogno:puoi configurare il lato host del collegamento dall'esterno dello spazio dei nomi limitato. Farlo dall'interno semplicemente facilita il controllo del flusso, altrimenti è necessaria una sincronizzazione per impostare il collegamento dopo che è stato stabilito ma prima di avviare il programma.
unshare -n -- sh -c '
# Create a virtual ethernet interface called "confined",
# with the other end called "global" in the namespace of PID 1
ip link add confined type veth peer name global netns 1
# Bring up the confined end of the network link
ip addr add 172.16.0.2/30 dev confined
ip link set confined up
# Bring up the global end of the network link
ns_exec /proc/1/ns/net ifconfig global 172.16.0.1 netmask 255.255.255.252 up
# Execute the test program
exec sudo -E -u "$TARGET_USER" "$0" "[email protected]"
' /path/to/program --argument
Devi fare tutto questo come root. L'introduzione degli spazi dei nomi utente nel kernel 3.8 potrebbe renderlo fattibile senza permessi speciali, ad eccezione dell'impostazione dell'estremità globale del collegamento di rete.
Non so come condividere localhost tra i due spazi dei nomi. Le interfacce ethernet virtuali creano un bridge point-to-point. Puoi usare iptables
regole di inoltro per reindirizzare il traffico da/verso lo
se lo si desidera.