Skip to content

Linux Attitude

Le libre est un état d'esprit

Archive

Category: Réseau

Niveau :      
Résumé :

Petit problème pour le plaisir.

Problème

Nous voulons créer un algorithme, voire une formule arithmétique simple, nous permettant de générer des nombres entiers ayant la propriété suivante : pour tout x, l'ensemble des chiffres de l'ensemble des nombres générés inférieurs à x doit être distribués équitablement.

Équitablement signifie que chaque chiffre doit apparaître autant de fois que chaque autre plus ou moins le nombre de chiffres de x.

Prenons un exemple pour bien me faire comprendre :

  • Soit x = 100
  • Prenons l'ensemble des nombres entiers inférieurs à x : 0-99
  • Écrivons les sur 2 chiffres (1=01) et prenons tous les chiffres

Nous avons alors 20 fois le chiffre 0 (10 fois coté dizaines, 10 fois coté unités), 20 fois le 1 ...

Donc c'est équilibré, nous sommes contents.

Prenons x = 99, nous avons tous les nombres sauf 99, donc 20 chiffres de chaque sorte et seulement 18 fois le 9. Deux de moins que les autres or 2 est le nombre de chiffres de x.

Donc c'est équilibré, nous sommes contents.

Prenons x=90, nous n'avons que 9 fois le 9 et 19 fois le 0, ce n'est pas équilibré.

Par conséquent la formule que nous cherchons c'est pas f(x)=x mais quelque chose qui prend une suite logique de nombres mais pas dans l'ordre naturel, comme le fait le code de gray.

Mais pourquoi ?

Pendant que vous réfléchissez, je vais vous expliquer la raison du problème. Lorsque vous câblez une salle machine, vous utilisez de nombreux câbles. Pour une bonne gestion de ces câbles, qui vont rapidement être emmêlés avec d'autres une fois branchés, il faut les identifier pour repérer facilement les 2 bouts d'un même câble.

Une première solution est d'utiliser patchsee, sympa quand on a les moyens et qu'on n'a encore installé aucun câble, mais elle ne marche pas pour notre stock de câble existant.

Une autre solution est d'étiqueter les câbles, mais les étiquettes papier même plastifiées ont tendance à s’abîmer, s'effacer et sont difficilement repérables de loin. On les remplace donc parfois par des clips de repérage.

Malheureusement, nous sommes soumis à la terrible loi de Benford. Appliquée au clips, elle nous condamne a acheter beaucoup de 1, un peu moins de 2, encore moins de 3 etc ... Or ils sont vendu par lots ayant la même quantité de chaque chiffre, drame lorsque vous voulez étiqueter 200 ou 2000 câbles.

La solution : répartir les chiffres de façon à n'acheter que ce que vous consommez. C'est ce que que j'ai décrit d'une façon un peu plus formelle précédemment.

La réponse

Alors vous avez réfléchi ?

Évitez de vous précipiter sur la solution, elle est simple et vous pouvez la trouver.

J'ai dû faire plusieurs essais et quelques calculs pour trouver.

Il y a plusieurs solutions.

Mais très peu de solutions sont simples et faciles à expliquer à celui qui devra utiliser ce système après vous.

La solution que je propose ne nécessite pas de formule compliquée.

Vous avez trouvé ?

Voici ma solution :

  • 00, 11, 22, 33, 44, 55, 66, 77, 88, 99
  • 10, 21, 32, 43, 54, 65, 76, 87, 98, 09
  • 20, 31, 42, ...

Vous voyez le pattern ?

A un nombre à 2 chiffres N=(x)(y) j'associe le nombre M=(x+y)(y) en ne gardant qu'un seul chiffre à chaque opération bien sûr. A un nombre à 3 chiffres N=(x)(y)(z) j'associe le nombre M=(x+y+z)(y+z)(z) etc.

  • Pour faire le 35e nombre je prends le 5 (.5) j'ajoute 3 et je mets le résultat à gauche : 85
  • Pour faire le 125e nombre je prends le 5 (..5) j'ajoute 2 et je mets le résultat à gauche (.75) j'ajoute 1 et je mets le résultat à gauche : 875
  • Pour faire le 589e nombre je prends le 9 (..9) j'ajoute 8 et je mets le résultat à gauche (.79) j'ajoute 5 et je mets le résultat à gauche : 279

Les nombres sont équilibrés car pour chaque série de 10 on a 10 chiffres différents aux unités, 10 chiffres différents aux dizaines ...

De plus ça marche pour le nombre de chiffres que vous voulez, vous pouvez étiqueter 25000 câbles avec cette méthode. Et Vous pouvez même changer de nombre de chiffres en cours de route, coder les 100 premiers nombres sur 2 chiffres et les 900 suivants sur 3 chiffres comme avec les entiers naturels.

Conclusion

Il n'y a pas de petites économies !

D'ailleurs, à ceux qui utilise le codage des nombres naturels, je récupère gracieusement tous les 7, 8 et 9 dont vous n'avez plus usage ! Il me suffira d'adapter le codage en base 3 pour les réutiliser.

Les maths c'est utile parfois ...

Niveau :      
Résumé : ipset; IN A

Ceci n'est pas une amélioration de l'article précédent, mais un complément.

Un firewall basé sur le DNS

On veut être indépendant des ip utilisées par les gens que l'on filtre. On se propose cette fois de faire des règles de filtrage basées sur le forward DNS et non plus le reverse DNS.

Cette fois, on ne peut plus utiliser l'IP du paquet pour récupérer le nom de domaine, mais on peut mettre au jour automatiquement les règles de firewall en fonction d'un domaine défini et non plus avec des IP statiques.

Encore une fois, les précautions précédentes s'appliquent :

  • on base une règle sur quelque chose qu'on ne maitrise pas, voire qu'un attaquant pourrait maitriser : la base dns de la source
  • on devient dépendant du résolveur dns et donc de ses failles

Mais à la différence de la dernière fois, le dns est potentiellement sous contrôle d'un ami (si on parle de whitelist et non de blacklist). De plus on peut imaginer utiliser DNSSEC pour gagner en sécurité.

Changeons de technologie. Puisque nous ne faisons plus de reverse DNS, nous devons connaître à l'avance l'intégralité des domaines. Donc on ne peut plus avoir de regex ou de wildcard. Et puisque nous devons les connaître à l'avance, nous pouvons juste faire des requêtes, stocker les IP résultantes et les utiliser directement dans le firewall.

La technologie du jour s'appelle donc ipset. Elle permet d'utiliser un pool d'ip que l'on peut faire varier dynamiquement dans une règle iptables.

Iptables

Son usage est simple :

# on ne matche que sur l'ip source
iptables -A ... -m --match-set chezmoi.com src -j ...
# on matche sur un couple source/destination
iptables -A ... -m --match-set friendzone src -j ...

Ensuite il suffit de créer les set

ipset --create chezmoi.com iphash
# ip ipset create chezmoi.com hash:ip  (pour ceux qui ont une ancienne version d'ipset)
ipset --create friendzone iphash
# ip ipset create friendzone.com hash:ip  (pour ceux qui ont une ancienne version d'ipset)

Règles en live

Il ne nous reste plus qu'à mettre à jour les set dynamiquement, par exemple en interrogeant régulièrement les serveurs dns.

# on utilise un ipset temporaire pour que le firewall continue de fonctionner pendant nos opérations
ipset --create temp iphash

for rule in rules
do
    ipset --flush temp
    for i in domains[$rule]
    do
        host $rule | 
        xargs ipset --add $rule $ip
    done
    ipset --swap temp $rule
done

ipset --destroy temp

Il n'y a plus qu'a lancer ce script régulièrement grâce à notre ami cron.

Et voila !

Notez qu'il y a moyen avec ipset de matcher plusieurs adresses à la fois (ip, mac, source, destination), de matcher des réseaux et même de matcher des ports.

Niveau :      
Résumé : perl, libipq, IN PTR

Le problème

Les firewall ne proposent jamais de faire une règle qui couperait la connexion en fonction du domaine de l'appelant. C'est gênant car on aimerait bien pouvoir devenir indépendant de l'ip de notre partenaire.

Si on ouvre un accès à un ami, pourquoi devrait-il nous avertir lorsqu'il change d'ip alors qu'il a fait correctement son travail en mettant à jour son DNS.

En réalité il y a de bonnes raisons à cela, en effet le domaine ne se trouve pas dans le paquet il faut donc aller le chercher quelque part. Et cela implique :

  • qu'on base une règle sur quelque chose qu'on ne maîtrise pas, voire pire, qu'un attaquant pourrait maîtriser : la base dns de la source
  • qu'on devient dépendant du résolveur dns et donc de ses failles
  • qu'il est possible que le firewall empêche le firewall d'aller chercher l'info sur le serveur dns
  • qu'il faut attendre que le dns réponde et donc les performances d'un tel firewall risquent d'être catastrophiques

Les deux derniers problèmes sont purement techniques et ont donc une solution technique acceptable moyennant quelques compromis. Par contre les deux premiers problèmes concernent la sécurité et il faut donc garder en tête que si on met en place une telle règle, elle est là pour nettoyer les flux qui traversent notre firewall, mais qu'elle n'apporte que peu de sécurité par rapport à l'absence de règle.

La solution

Maintenant que nous savons qu'il ne faut pas le faire, voyons comment faire :-)

Tout d'abord il y a deux possibilités, se baser sur le forward DNS (IN A et IN AAAA) ou sur le reverse dns (IN PTR). Aujourd'hui je vous propose le pire des cas, le reverse DNS, puisque votre configuration est directement tributaire de la volonté de l'attaquant.

Commençons par un prototype, donc en perl, parce que je le veux bien.

Le point important ici est de faire la résolution dns en espace utilisateur. Pour cela il faut d'utiliser libipq, la bibliothèque permettant de communiquer entre l'espace utilisateur et netfilter la partie noyau du firewall linux.

Il nous faut donc :

  • libipq : IPTables::IPv4::IPQueue
  • parser les paquets ip : NetPacket::IP
  • faire des requêtes dns : Net::DNS

Et voici le script tout simple, le reste de l'article est en commentaire dans le script.


continue reading...

Niveau :      
Résumé : ip link add link eth0 vlan1 type vlan id 1

Je suis de retour !

Désolé pour le lag ... mais je réponds aux commentaires.

Problème

Aujourd'hui, un problème qu'on m'a posé récemment. Comment faire lorsqu'on a un parc de box (routeur wifi, machine embarquée, ...) et qu'on veut pouvoir à tout moment se connecter physiquement sur son port ethernet et la configurer en utilisant ip (par ssh, snmp ...).

La première solution est d'avoir une configuration réseau immuable sur ces machines ET de répertorier d'une façon ou d'une autre un identifiant unique pour chacune de ces machines qu'on peut alors faire correspondre à une ip. C'est assez contraignant et ça impacte fortement la configuration réseau des machines. Ça risque de nous empêcher de réutiliser ce port pour communiquer dans un réseau existant le reste du temps.

La deuxième solution serait d'utiliser un protocole type zeroconf pour configurer automatiquement le réseau lorsqu'on se branche, l'inconvénient est de réussir à le désactiver lorsque la machine se retrouve dans son réseau de destination qui n'utilise pas nécessairement zeroconf tout en le gardant actif pour le configurateur.

Je vous propose donc une solution différente : l'ip unique. Toutes les machines à configurer ont la même IP. C'est bien beau me direz-vous, mais comment fait-on pour éviter les conflits sur le réseau de destination ? Et comment fait-on pour que ces machines communiquent ensemble ?

C'est tout simple, on met cette IP sur un vlan prédéfini. Ainsi vous n'avez plus aucune contrainte sur la configuration réseau de l'appareil. Ce peut être une box en bridge ou en routeur, une machine physique avec un routage complexe, ou une machine configurée en dhcp.

Solution pour linux

Pour ajouter une interface réseau virtuelle associée à un vlan :

# le vlan 1 sur l'interface eth0 sera dans l'interface virtuelle vlan1 
$ ip link add link eth0 vlan1 type vlan id 1 

# ou, pour ceux qui n'aiment pas le couteau suisse, ip, il y a l'outil d'origine
$ vconfig add eth0 1 # pas le choix, l'interface s'appellera nécessairement eth0.1

Et il suffit de lui configurer une ip choisie en dur et c'est fini, vous pouvez mettre n'importe quelle configuration pour eth0 ...

$ ip addr add 192.168.254.254/28 dev eth0.1

Pour faire ceci en statique, sur une debian like il faut modifier /etc/network/interfaces en nommant l'interface à configurer eth0.1 Pour les redhat like il faut créer le fichier /etc/sysconfig/network-script/ifcfg-eth0.1

Niveau :      
Résumé : ngrep

I'm back ! Ça faisait longtemps ! Vous m'avez manqué.

J'ai quelques petits articles pour vous. Oui c'est vraiment la reprise, même si c'est pas encore du triple A.

Aujourd'hui ngrep. Ngrep est un pote de tcpdump, il sait utiliser les mêmes filtres que tcpdump et stocker les paquets dans un format pcap lisible par wireshark si besoin. Mais son intérêt principal est qu'il sait matcher le contenu des paquets.

Là où en tcpdump vous feriez :

$ tcpdump host 10.0.0.1 and port 80

Vous pouvez utiliser ngrep récupérer un paquet particulier :

$ ngrep 'GET' 'host 10.0.0.1 and port 80'

Dans les options les plus utiles on trouve :

  • -O pour sauvegarder les paquets et les analyser ensuite, par exemple avec wireshark
  • -x pour dumper la version hexadécimale du paquet (pratique pour un protocole binaire)
  • -X pour matcher sur la version hexadécimale du paquet (pratique pour un protocole binaire)
  • -K1 pour tuer la connexion en envoyant un paquet RST à la source du paquet en question (pas de garantie 100% avec cette méthode :)

Et un exemple pour la route pour couper la connexion de celui qui dirait du mal de vous sur un serveur irc :

$ ngrep -K1 'peck sux' 'dst 10.0.0.1 and dst port 6667'

Niveau :      
Résumé : tcpdump ssl ; ptrace ; ltrace

Vous attendez la suite de mon article sur ce qui passe par les oreilles d'un android ? Hé bien vous allez attendre encore un peu ...

Lorsque vous récupérez via tcpdump un flux SSL (au hasard du https), il est chiffré et c'est justement l'intérêt du SSL de vous empêcher de lire ce flux.

Mais si si vous maitrisez une des deux extrémités, il devrait être normal que vous puissiez lire ce flux. C'est pourquoi nous allons le faire.

Côté serveur

Dans le cas où vous maitrisez le côté serveur, il suffit d'ouvrir la trace tcpdump (sauvegardée avec l'option -s0 -w file) sous wireshark et de le configurer pour qu'il utilise la clé serveur pour déchiffrer le flux :comme ici et de choisir de suivre le flux ssl au lieu du flux TCP.

C'est simple et efficace.

Côté client

Maintenant si vous êtes côté client sans certificat client, vous êtes coincés. Et c'est là que j'ai une solution à vous proposer.

Il existe plusieurs moyen pour espionner vos processus, tout d'abord vous pouvez créer un wrapper autour de la lib SSL et utiliser LD_PRELOAD pour la charger avant le processus. C'est bien mais difficile à mettre en œuvre, surtout si le processus tourne déjà, je vous laisse explorer cette voie de votre côté.

La deuxième solution est d'utiliser ptrace pour espionner le processus. Techniquement complexe, cette méthode nous est grandement facilitée par l'outil ltrace.

Pour la suite je vais supposer que les services à espionner passent par openssl, mais rien ne vous empêche de faire la même chose avec gnutls.

Espionner un processus

C'est simple :

# vous le lancez directement : 
$  ltrace ma commande
# ou vous espionnez un processus qui tourne déjà 
$ ltrace -p pid

Ça vous montre le fonctionnement, mais c'est aussi illisible qu'un strace.

Espionner le SSL

Ajoutons quelques options pour trier ce fouillis :

$ ltrace -l /usr/lib/libssl.so.0.9.8 -s 20000 -e SSL_read,SSL_write

Et voilà, la liste des appels ! Mais ce n'est pas suffisant.

Ajoutons les lignes suivantes dans /etc/ltrace.conf (ou dans ~/.ltrace.conf) :

int SSL_read(addr,string[retval],int);
int SSL_write(addr,string[arg3],int);

On relance la commande et maintenant nous avons le contenu de la communication en clair.

Mais il y a un petit bug dans ltrace, string[retval] devrait couper les chaines de SSL_read en fonction de la valeur de retour, mails ne le fait pas.

Corrigeons cela avec un petit script de formatage et cette fois nous avons toute la communication en clair !

$ ltrace -l /usr/lib/libssl.so.0.9.8 -s 20000 -e SSL_read,SSL_write -p pid 2> /tmp/trace
$ perl -pe 's/(SSL_read.*?, ")(.*)(".*? )(\d+)$/$1.substr($2,0,$4).$3.$4/e' /tmp/trace | less

Cloonix

Jan 18

Niveau :      
Résumé : ./start_cloonix_net ; ./graph

De temps en temps je vous fais un article sur le réseau, et je teste quasiment tous mes articles dans la vraie vie. Et là vous vous dites, mais c'est énorme ! Mais comment que fait-il ? A-t-il l'infrastructure ?

En fait non, enfin si mais non. Pour tester le réseau, j'utilise tout simplement cloonix.

Cloonix n'est pas une distribution, mais un outil permettant de gérer des machines virtuelles et de les mettre en réseau. Pratique, tout se fait graphiquement ou presque.

Installation

La version ubuntu ne marche pas sur ma debian, j'ai donc du utiliser les sources. Ça compile bien, il suffit d'appeler doitall dans le répertoire sources. Par contre faites attention, la version source ne contient pas de vm de démo.

Donc après compilation récupérez le répertoire virtual_platform_configs ainsi que le répertoire bulk du package ubuntu et déposez-les dans le répertoire de cloonix.

Le répertoire bulk contient les images disque de base des distribution à virtualiser.

Le répertoire virtual_platform_configs contient la définition des vm, les personnalisation spécifiques à chaque machine, ainsi que la façon dont les machines sont reliées.

Utilisation

./start_cloonix_net
./graph

Vous pouvez alors cliquer sur le bouton droit et charger une topologie. C'est à dire une infrastructure telle que stockée dans un des répertoires de virtual_platform_configs. Un fois que toutes les vm sont chargées vous obtenez ceci : Cloonix_IHM

Et c'est parti, vous avez plusieurs machines virtuelles préconfigurées directement utilisables. Pour ouvrir un shell sur une des machine, double cliquez dessus. Vous pouvez aussi en ajouter dynamiquement, relier deux cartes réseau ...

Lorsque vous avez fini tuez cloonix et ses vm :

./ctrl -kill

Détails

Très pratique, quasiment rien à faire, cloonix sait utiliser UML ou KVM au besoin.

Pour les tests réseau vous pouvez faire ce que vous voulez, pensez à enregistre votre topologie pour les tests fréquents.

Pensez aussi à modifier la distribution de base dans bulk pour ne plus avoir de modifications a porteriori à faire car tout le contenu d'une vm est perdu dès qu'elle s'éteint.

Enfin pour ceux qui font des tests avec les couches basses du réseau, il est nécessaire d'autoriser le passage des interface en mode promiscuous depuis cloonix avec une commande de la forme :

# le nom de la vm, ne nom de l'interface, 1 pour activer
./ctrl -promisc ROUTER3 eth0 1

La documentation est minimaliste, mais suffit pour s'en sortir.

PS : Si vous avez des idées d'article à me suggérer n'hésitez pas à utiliser la boite à idées.