Rebondir avec SSH

Après GCC et les trampolines, voici les rebonds avec SSH. Ou alors, la super-astuce du jour.

Supposez que vous ayez une machine (passerelle, frontal de grappe, etc), avec des machines derrière. Plusieurs fois par jour, vous faites :

ssh frontal ssh node38-01

Un peu plus tard :

ssh frontal ssh node38-02

Pas pratique, hein ?

Heureusement, Nicolas C. m’a donné la solution qui tue.

Acte 1 : l’option ProxyCommand de SSH

     ProxyCommand              Specifies the command to use to connect to the server.  The com-              mand string extends to the end of the line, and is executed with              /bin/sh.  In the command string, '%h' will be substituted by the              host name to connect and '%p' by the port.  The command can be              basically anything, and should read from its standard input and              write to its standard output.  It should eventually connect an              sshd(8) server running on some machine, or execute sshd -i some-              where.  Host key management will be done using the HostName of              the host being connected (defaulting to the name typed by the              user).  Setting the command to ``none'' disables this option              entirely.  Note that CheckHostIP is not available for connects              with a proxy command.

Vous l’aviez compris, vous pouvez faire qqchose comme ça dans votre .ssh/config :

Host node01         ProxyCommand ssh login@frontal "nc node38-01 22"

Un ssh node01 fait ce à quoi vous vous attendiez.

C’est pas mal, mais ça passe pas très bien à l’échelle. Car derrière frontal, forcément, vous avez tout plein de noeuds ! Ca serait mieux d’avoir un truc plus …générique.

Acte 2 : là où vous direz “ouahhh”

Je vous donne la solution directement :

Host *.frontal         ProxyCommand ssh login@frontal "nc \$(basename %h .frontal) %p"

Comme vous l’aviez deviné, suffit de faire un ssh node38-01.frontal pour se connecter à node38-01 en rebondissant sur le frontal. Ou un ssh node38-02.frontal pour se connecter à node38-02. Etc.

Je précise que ce n’est pas moi qui l’ai trouvé. Vous connaissiez ?

Précision pour les gens comme A. L. : Mettre un masque qui veut dire qqchose (par exemple *.imag.fr), c’est une mauvaise idée. Regardez par exemple :

Host *.imag.fr         ProxyCommand ssh login@passerelle.imag.fr "nc \$(basename %h .imag.fr) %p"

Pourquoi est-ce que ça ne marche pas comme on s’y attend ? Quel sera l’effet vu du client ? Vu du serveur ?

GCC, Trampoline, et code auto-modifiable

Aux temps héroïques, le code auto-modifiable était fréquent. Ça consiste à écrire du code qui se modifie lui-même pendant l’exécution, pour faire des micro-optimisations qui tuent (en fait, surtout gagner une indirection par ci par là, mais à l’époque c’était pas négligeable).

Mais en fait, ça n’a pas complètement disparu : GCC, dans un cas précis, en génère d’ailleurs !

Fonctions imbriquées en C

Une fonction imbriquée en C est une fonction définie à l’intérieur d’une autre fonction. A quoi est-ce que ça sert ? Parfois, pour rendre votre code plus clair, vous définissez des fonctions qui ne sont utiles que dans une autre fonction. Il est donc débile de la rendre accessible depuis toutes les autres fonctions ! GNU CC vous autorise à écrire le code suivant (c’est une extension de GCC, ce n’est pas dans la norme C99) :

 int f1() { 	int f2() 	{ 		[...] 	} 	[...] 	f2(); 	[...] } 

C’est bien joli, mais ça pose un problème. Regardez cet exemple (qui compile, n’hésitez pas à essayer) :

 void f0(void (*f)()); long f1 (void) { 	long i = 0; 	void f2(void) 	{ 		i++; 	} 	f0(f2); 	return i; } void f0(void (*f)()) { 	(*f)(); } int main() { 	return f1(); } 

C’est tout à fait légal : f1 passe un pointeur vers f2 à f0, qui se charge d’appeler la fonction en paramètre. Le problème est que f2 modifie i. Or i est une variable locale de f1 (allouée sur la pile par f1). La distance entre ESP dans f2 et les variables locales de f1 sur la pile n’est pas connue : ici, f0 appelle directement f2, mais il pourrait appeler blop(f2) qui lui même appelerait f2. Il faut trouver un moyen de passer à f2 l’adresse du contexte de sa fonction parente.

Trampolines

Un papier (PDF) évoque ce problème pour le C++ (où les closures sont encore plus pratiques qu’en C, notamment lorsqu’on utilise des itérateurs). Il propose une solution élégante utilisant un trampoline. Dans l’article, il démontre la solution avec de l’assembleur 68000. Voici le code ci-dessus compilé pour x86, sans optimisation histoire de garder le code le plus proche possible du C.

 	.file	"t5.c" 	.text 	.type	f2.0, @function f2.0: 	pushl	%ebp 	movl	%esp, %ebp 	subl	$4, %esp 	movl	%ecx, -4(%ebp) 	movl	-4(%ebp), %ecx 	incl	-4(%ecx) 	leave 	ret 	.size	f2.0, .-f2.0 .globl f1 	.type	f1, @function f1: 	pushl	%ebp 	movl	%esp, %ebp 	subl	$40, %esp 	leal	-24(%ebp), %eax 	addl	$0, %eax 	andl	$-1, %eax 	movl	$f2.0, %ecx 	leal	10(%eax), %edx 	subl	%edx, %ecx 	movl	%ecx, %edx 	movb	$-71, (%eax) 	leal	-8(%ebp), %ecx 	movl	%ecx, 1(%eax) 	movb	$-23, 5(%eax) 	movl	%edx, 6(%eax) 	movl	$0, -12(%ebp) 	leal	-24(%ebp), %eax 	addl	$0, %eax 	andl	$-1, %eax 	movl	%eax, (%esp) 	call	f0 	movl	-12(%ebp), %eax 	leave 	ret 	.size	f1, .-f1 .globl f0 	.type	f0, @function f0: 	pushl	%ebp 	movl	%esp, %ebp 	subl	$8, %esp 	movl	8(%ebp), %eax 	call	*%eax 	leave 	ret 	.size	f0, .-f0 .globl main 	.type	main, @function main: 	pushl	%ebp 	movl	%esp, %ebp 	subl	$8, %esp 	andl	$-16, %esp 	movl	$0, %eax 	subl	%eax, %esp 	call	f1 	leave 	ret 	.size	main, .-main 	.section	.note.GNU-stack,"x",@progbits 	.ident	"GCC: (GNU) 3.3.5 (Debian 1:3.3.5-8)" 

Un trampoline, c’est un petit bout de code qui va mettre dans registre (ici ECX, je ne sais pas quelle est la convention exactement) l’adresse de l’environnement de la fonction parente. Dans le code de f2, on voit qu’on incrémente -4(%ecx) pour incrémenter i. Ce petit bout de code est généré sur la pile par f1 avant d’appeler f0. Le code qui génère le code est entre “subl $40, %esp” et “call f0″, en gros. Et mon débogueur me dit que le code généré ressemble à :

 Dump of assembler code from 0xbffff930 to 0xbffffa30:     0xbffff930:     mov    $0xbffff940,%ecx     0xbffff935:     jmp    0x8048354  

Quand f0 fera son call, il appellera une adresse de la pile sans le savoir. Et quand f2 retournera, elle retournera directement dans f0.

C’est trop beau, il doit bien y avoir un problème qqpart …

Hé oui. La pile exécutable, c’est un problème : c’est la base de l’exploitation de beaucoup de trous de sécurité. Du coup, des systèmes essayent de rendre la pile non exécutable. C’est le cas de OpenBSD avec W^X, ou de Linux avec Exec-shield (PDF). Comment faire pour continuer à autoriser les trampolines, alors ? Et bien c’est tout simple. Sous linux, l’en-tête ELF des binaires contient un flag indiquant si ce programme a besoin que la pile soit exécutable. Avec l’exécutable du code de tout à l’heure :

 ***lucas@blop:~% readelf -l t5 | grep STACK   STACK          0x000000 0x00000000 0x00000000 0x00000 0x00000 RWE 0x4 

Tandis qu’avec un autre exécutable (notez le RW au lieu du RWE) :

 ***lucas@blop:~% readelf -l t3 | grep STACK   STACK          0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0x4 

C’est un flag ajouté par GCC.

Bravo si vous avez lu jusque là ;)

Browsers stats from Apinc.org

(I am blogging in english since english pages linked to the previous analysis. I won’t continue to blog in english.)

Apinc provides non-commercial web hosting services. It hosts more than 1000 french associations and individuals, generally not related to computers (sites like Standblog and OpenWeb were excluded from the stats). This gives a good picture of the browser usage on the french Internet (most of the websites hosted are in french).

The graphs don’t need much explanations. A 2-week average is used.

Sauvegardez vos données !

Thomas parlait il y a peu de son système de sauvegarde. Mais avant de décrire mon propre système, revenons un peu sur la nécessité d’un bon système de sauvegarde.

Tout d’abord, les pannes n’arrivent pas qu’aux autres. En 2003, 11% des PME ont perdu des données à cause d’une panne (13% à cause d’un virus), alors que 85% des PME sauvegardent leurs données (source : Étude de BNP PARIBAS sur l’équipement informatique des PME). Au niveau des particuliers, je n’ose même pas imaginer ce que donnent les scores. Et pourtant, les disques IDE sont très peu fiables : 1,9% des disques reviennent en SAV dans les 6 premiers mois d’utilisation (source : Hardware.fr : Taux de SAV des disques dur (chiffres de LDLC). A partir de là, on peut penser à 3 stratégies :

  • Ne rien faire, et prier. C’est un peu risqué quand même, non ? Tout dépend de ce que vous avez sur votre PC, après tout.
  • La stratégie Linus Torvalds : Backups are for wimps. Real men upload their data to an FTP site and have everyone else mirror it. Problème : il faut faire des choses ayant suffisamment d’intérêt pour que les gens commencent à en faire des copies. Il semble que Linus ait d’ailleurs changé d’avis sur la question, comme le montre ce mail.
  • Utiliser un système de sauvegarde

Personnellement, j’utilise un système basé sur rsync, mais avec une surcouche permettant de faire quelques petites choses sympatiques. Ça s’appelle Dirvish. En plus d’effectuer les sauvegardes via rsync, dirvish permet de conserver un historique et de gérer l’expiration des copies. Il fait ça intelligemment en utilisant des hard links pour les fichiers qui ne changent pas lors d’images successives. Par exemple, voici l’historique de mes sauvegardes pour mon /root, avec leurs tailles respectives :

8,0M    20050104-1142 8,0M    20050105-1142 8,0M    20050106-1142 8,0M    20050107-1142 8,0M    20050110-1142 8,0M    20050111-1142 8,0M    20050112-1142 8,0M    20050113-1142 8,0M    20050114-1142 8,0M    20050115-1142 8,0M    20050116-1142 8,0M    20050117-1142 8,0M    20050118-1142

Tout ça ne prend que 8,1M sur mon disque. En pratique, vous pouvez garder beaucoup de copies avec peu d’espace disque, surtout que souvent, les gros fichiers ne sont pas modifiés (images, musique, vidéos). Et en stockant les sauvegardes sur un disque dur différent, vous obtenez déjà un niveau de sécurité acceptable.

Logiciels Libres, orthographe, conjugaison et dictionnaires

Vous aussi, vous ecriver comme des porc ? Et s’est de peer en peer ? Je suis là pour vous sauver. Enfin, je vais donner quelques pistes.

La correction orthographique

C’est la base. Il y a ispell ou (mieux) aspell, qui s’intègrent dans à peu près tout. Pour VIM, il y a un plugin sympa, par exemple. Je laisse Olivier compléter pour Emacs ;) C’est vraiment sympa, avec VIM, d’avoir les mots faux qui se soulignent au fur et à mesure qu’on tape !

La conjugaison

Les vestiges de votre Bécherelle sont introuvables ? Ce n’est pas grave, Verbiste est là (copie d’écran). Après, il faut encore se souvenir ce qu’est le subjonctif, et quand l’employer. Pas évident, hein ? (pour ne rien gâcher, il y a même un paquet Debian)

Dictionnaires

Pas pratique de se jeter sur son dictionnaire français/anglais à tout bout de champ ? Vous hésitez souvent sur la signification des expressions peu orthodoxes employées sur debian-devel lorsque le sujet du débat est l’éventuelle inclusion de hot-babe ?

Là aussi, il existe des solutions libres, avec une architecture client/serveur (ça rigole plus). Dans Debian, dict est le client, dictd le serveur, dict-freedict-eng-fra est le dictionnaire anglais-francais, dict-freedict-fra-eng celui francais-anglais (sans blague), et dict-gcide est un dictionnaire d’anglais libre basé sur le Webster de 1913. Ok, on a vu plus récent, mais ça suffit dans bien des cas.

Et la correction grammaticale ?

Là, il n’y a rien pour l’instant à ma connaissance. :-(

Voilà, j’espère que cet état des lieux aura été utile à au moins une personne !

Analyse des logs Apache d’Apinc

Update available here ! This page is OLD !

APINC, l’Association Pour la promotion de l’Internet Non Commercial, m’a donné l’autorisation d’analyser ses logs Apache pour 2004. Vu la quantité de données (presque 2000 sites, environ 1.5 millions de requêtes par jour, soit au total environ 90G de logs à analyser…), ca permet de faire une analyse assez fine.

Tout d’abord, les mauvaises nouvelles. Non, Linux ne reprend pas de part de marché à Windows. Ou alors, ce n’est pas visible.

PDM OS

Autre fait important, il y a encore énormément de monde qui utilise de vieilles versions de Windows.

PDM Windows

Cela se voit aussi avec la répartition de l’utilisation des versions d’Internet Explorer. Il reste encore un nombre non négligeable de personnes avec IE 5.0 ou inférieur…

PDM MSIE

Mais venons en à ce qui nous intéresse. Tout d’abord, la part de marché des navigateurs respectant les standards est assez élevée sur Apinc. Peut-être est-ce dû au fait que c’est l’hébergeur du Standblog et d’OpenWeb ?

PDM Browsers

Je me suis aussi penché sur la part de marché des différents navigateurs basés sur Gecko. On voit que Firefox prend de plus en plus d’importance, ce qui n’est pas vraiment une surprise…

PDM Gecko

Autre sujet intéressant, la plate-forme Mac : on voit que Safari, basé sur KHTML, domine maintenant Internet Explorer !

PDM MacOS

Penchons nous maintenant sur l’histoire du panda rouge.

PDM firefox

La rapidité avec laquelle la communauté se met à jour est assez impresionnante …

Enfin, à la demande de Tristan Nitot, un graphe montrant le pourcentage de browsers comprenant les standards (voir son post plus bas pour plus de détails).

PDM standards

Je laisse à d’autres le soin de faire d’autres commentaires plus avisés ;-) Je ne diffuse pas les données brutes, mais demandez moi si vous voulez que j’analyse autre chose.

Merci à APINC :-)

(Si vous vous posez la question, les deux traits blancs verticaux correspondent à des pannes d’Apinc.)

Bouchons et dynamique des fluides

Je viens de lire un article intéressant (autre version) sur les bouchons se créant sur les autoroutes. L’auteur propose des solutions évidentes pour aider à les résorber. Ce qui est intéressant, c’est qu’une personne individuelle peut réellement faire une différence. Et ça donne des résultats probants ! Il me semble d’ailleurs qu’une expérience similaire a eu lieu cet été sur l’A7.

RFC 1925

Au détour d’un journal de DLFP, je suis tombé sur une RFC intéressante, la RFC 1925 : The Twelve Networking Truths. Certaines “vérités” sont particulièrement intéressantes :

    (6)  It is easier to move a problem around (for example, by moving         the problem to a different part of the overall network         architecture) than it is to solve it.         (6a) (corollary). It is always possible to add another level of              indirection. [...]    (8)  It is more complicated than you think. [...]    (11) Every old idea will be proposed again with a different name and         a different presentation, regardless of whether it works.         (11a) (corollary). See rule 6a. 

A propos du (11), je me demande combien de temps il va falloir attendre avant qu’un 1A demande sur la ML du clux s’il est possible de monter une disquette depuis les TX MAXDATA. Il y a deux ans, j’avais eu l’honneur d’y penser en premier pour cette année là :)

J’ai enfin fait qqchose de XSLT !

Je voulais me faire un script shell permettant de récupérer la liste des dernières chansons diffusées sur Ouifm et de l’afficher sous une forme pratique en console. La liste des chansons est disponible sur cette page.

Un tel script est faisable en bash avec grep et sed mais c’est … hum ! Vincent dira que c’est aussi faisable en perl, mais on n’y gagne pas grand chose e, clarté. Finalement, Je récupère la page avec wget, je la transforme en XHTML avec tidy, et j’ai tenté de la transformer avec xsltproc. Après plus d’une heure passée à me prendre la tête sans arriver à rien, j’ai fait appel à waloo sur #xmlfr@freenode, qui m’a fait ça en qqes minutes. Mais au moins, maintenant, j’ai un exemple qui marche. Et pour la forme, j’ai rajouté quelques détails.

Le script bash (pour récupérer la page, lancer tidy, etc … : http://bazaar.lucas-nussbaum.net/xslt-ouifm/ouifmlast

La feuille de style XSLT : http://bazaar.lucas-nussbaum.net/xslt-ouifm/ouifmlast.xsl