Commande pour exécuter un processus enfant «hors ligne» (pas de réseau externe) sous Linux

15

J'ai un programme que je voudrais tester en mode hors ligne sans supprimer mon réseau actuel. Ce programme devrait toujours se connecter aux sockets locaux, y compris les sockets de domaine Unix et le bouclage. Il doit également écouter en boucle et être visible pour les autres applications.

Mais les tentatives de connexion à une machine distante devraient échouer.

J'aimerais avoir un utilitaire qui fonctionne comme strace/ unshare/ sudoet exécute simplement une commande avec Internet (et LAN) caché et tout le reste fonctionne:

$ offline my-program-to-test

Cette question a des indices sur la réponse: bloquer l'accès au réseau d'un processus?

Il y a quelques suggestions, comme exécuter comme un autre utilisateur puis manipuler iptables, ou unshare -n. Mais dans les deux cas, je ne connais pas l'incantation pour que les sockets de domaine Unix et le bouclage soient partagés avec le système principal - les réponses à cette question me disent seulement comment dissocier tout le réseau.

Le programme que je teste doit toujours se connecter à mon serveur X et dbus et même être en mesure d'écouter en boucle les connexions d'autres applications du système.

Idéalement, je voudrais éviter de créer des chroots ou des utilisateurs ou des machines virtuelles ou similaires, car cela devient tout aussi ennuyeux que de débrancher le câble réseau. c'est-à-dire que la question est de savoir comment puis-je rendre cela aussi simple qu'un sudo.

J'aimerais que le processus s'exécute à 100% normalement, sauf que les appels réseau spécifiant une adresse non locale échoueraient. Idéalement en gardant le même uid, le même homedir, le même pwd, le même tout sauf ... hors ligne.

J'utilise Fedora 18, donc les réponses Linux non transférables sont très bien (attendues, même).

Je suis même heureux de résoudre ce problème en écrivant un programme C, si c'est le cas, les réponses qui impliquent d'écrire C sont donc très bien. Je ne sais tout simplement pas quels syscalls ce programme C devrait faire pour révoquer l'accès au réseau externe tout en conservant le réseau local.

Tout développeur essayant de prendre en charge le "mode hors ligne" apprécierait probablement cet utilitaire!

Havoc P
la source

Réponses:

9

La réponse traditionnelle consiste à exécuter le programme en tant qu'autre utilisateur et à l'utiliser iptables -m owner. De cette façon, la configuration réseau est partagée. Cependant, avec l'avènement des espaces de noms, il existe un moyen plus simple.

Avec les espaces de noms, vous ne partagez pas le réseau, puis créez un lien réseau virtuel si vous avez besoin d'un accès réseau limité.

Pour partager des sockets de domaine Unix, tout ce dont vous avez besoin est d'avoir un noyau assez récent, après ce correctif 2010 , donc 2.6.36 ou supérieur (ce qui est le cas sur toutes les distributions actuelles au moment de la rédaction sauf RHEL / CentOS).

Exécutez le programme dans son propre espace de noms IP. Avant de démarrer le programme, établissez une interface Ethernet virtuelle. Il ne semble pas y avoir beaucoup de documentation; J'ai trouvé la bonne incantation dans quelques blogs:

Dans l'extrait ci - dessous, j'utilise ns_execest le cette enveloppe autoursetns de la liste dans la page de manuel pour faire apparaître le côté hôte de la liaison réseau à partir du processus en cours d' exécution dans l'espace restreint. Vous n'en avez pas réellement besoin: vous pouvez configurer le côté hôte du lien depuis l'extérieur de l'espace de noms restreint. Le faire de l'intérieur facilite simplement le contrôle de flux, sinon vous avez besoin d'une synchronisation pour configurer le lien après qu'il a été établi mais avant de démarrer votre programme.

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" "$@"
' /path/to/program --argument

Vous devez faire tout cela en tant que root. L' introduction d'espaces de noms d'utilisateurs dans le noyau 3.8 peut rendre cela réalisable sans autorisations spéciales, à l'exception de la configuration de l'extrémité globale de la liaison réseau.

Je ne sais pas comment partager localhost entre les deux espaces de noms. Les interfaces Ethernet virtuelles créent un pont point à point. Vous pouvez utiliser des iptablesrègles de transfert pour rediriger le trafic de / vers losi vous le souhaitez.

Gilles 'SO- arrête d'être méchant'
la source
Bonne information supplémentaire, merci. Je pense que veth me donne un lien vers "l'extérieur" de l'espace de noms, mais mon nouvel espace de noms équivaut toujours à un nœud de réseau distinct, plutôt qu'au même nœud de réseau moins les interfaces non locales. Les implications sont (?): Le domaine Unix / les sockets abstraites échoueraient toujours, et le bouclage pourrait être transféré via iptables, mais le transfert ne permet pas le partage - c'est-à-dire que l'espace de noms original et restreint peut écouter en boucle et les deux ensembles de (dynamiquement -changing) les ports devraient être visibles dans les deux espaces de noms ... commencer à deviner ce que je veux est impossible ici: - /
Havoc P
1

Cela peut également être réalisé avec les règles iptables correspondant aux groupes de contrôle. J'ai écrit un outil pour résumer les étapes. Bien qu'il nécessite des autorisations root pour la configuration initiale et soit par ailleurs un binaire setuid, je pense qu'il offre un moyen assez simple de résoudre le problème dans la question. Il nécessite une version iptables suffisamment récente et disposant des modules netfilter appropriés.

https://github.com/quitesimpleorg/qsni

crtxcr
la source
0

/ !! \ Ce n'est probablement pas une réponse valide car cela vous fera perdre tout votre trafic, pas seulement le trafic d'un seul pid.

Je ne l'ai pas utilisé, mais je pense que vous pourriez potentiellement utiliser Comcast:

https://github.com/tylertreat/Comcast

réglé sur 100% de perte de paquets

Encore une fois, je n'ai pas testé cela, mais théoriquement, modifié à partir de leur fichier Lisez-moi, vous pouvez le faire:


Linux

Sous Linux, vous pouvez utiliser iptablespour supprimer les paquets entrants et sortants.

$ iptables -A INPUT -m statistic --mode random --probability 1 -j DROP
$ iptables -A OUTPUT -m statistic --mode random --probability 1 -j DROP

Vous pouvez également utiliser tcce qui prend en charge certaines options supplémentaires.

$ tc qdisc change dev eth0 root netem reorder 0 duplicate 0 corrupt 1

Réinitialiser:

$ tc qdisc del dev eth0 root netem
ThorSummoner
la source