philpep's blog philpep's blog rss http://blog.philpep.org fr Sun, 09 May 2010 00:00:00 GMT Pblog Un bot IRC à la CIA en python http://blog.philpep.org/post/Un-bot-IRC-a-la-CIA-en-python http://blog.philpep.org/post/Un-bot-IRC-a-la-CIA-en-python Sun, 09 May 2010 00:00:00 GMT <p>Quand vous utilisez <a href="http://git-scm.com/">git</a> à plusieurs et qu'en plus vous utilisez IRC pour en discuter, il peut être agréable d'avoir un bot qui informe le canal des commit sur le serveur. En particulier pour éviter des <code>merge branch</code> à tout va si on oublie de <code>pull</code> avant de <code>commit</code>. Il y a un service sur le net qui propose de tels bots IRC, c'est <a href="http://cia.vc">CIA.vc</a>. Sauf que le service est à des fins de statistiques sur les logiciels libres et j'aime pas trop que ces données sortent du serveur même si elles sont publiques, puis leur bot on sait pas trop ce qu'il fait.</p> <p>Donc je me suis mis à coder ce petit bot en python qui se connecte sur le canal IRC et attend des ordre via <a href="http://en.wikipedia.org/wiki/XML-RPC">xmlrpc</a>, cet ordre est lancé à chaque commit via un <a href="http://www.kernel.org/pub/software/scm/git/docs/githooks.html">hooks</a> sur le serveur git.</p> <p>Pour ça, tout est dans la librairie python standard, sauf <a href="http://python-irclib.sourceforge.net/">irclib</a> et <a href="http://packages.python.org/GitPython/">gitpython</a>.</p> <p>Le serveur (j'ai enlevé toutes les fonctionnalités qui ne rentrent pas dans le cadre de ce billet) :</p> <div class="codehilite"><pre><span class="c">#!/usr/bin/env python</span> <span class="kn">import</span> <span class="nn">threading</span> <span class="kn">import</span> <span class="nn">irclib</span> <span class="n">chan</span> <span class="o">=</span> <span class="s">&#39;#staff&#39;</span> <span class="n">nick</span> <span class="o">=</span> <span class="s">&#39;napalm0&#39;</span> <span class="n">server</span> <span class="o">=</span> <span class="p">(</span><span class="s">&#39;irc.philpep.org&#39;</span><span class="p">,</span> <span class="mi">6667</span><span class="p">)</span> <span class="n">xmlrpcserver</span> <span class="o">=</span> <span class="p">(</span><span class="s">&#39;localhost&#39;</span><span class="p">,</span> <span class="mi">8888</span><span class="p">)</span> <span class="k">class</span> <span class="nc">PbotIRCClient</span><span class="p">(</span><span class="n">irclib</span><span class="o">.</span><span class="n">SimpleIRCClient</span><span class="p">):</span> <span class="k">def</span> <span class="nf">on_welcome</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">s</span><span class="p">,</span> <span class="n">e</span><span class="p">):</span> <span class="n">s</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">chan</span><span class="p">)</span> <span class="c"># Classe de contrôle du bot par xmlrpc</span> <span class="k">class</span> <span class="nc">PbotControl</span><span class="p">:</span> <span class="k">def</span> <span class="nf">commit</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">files</span><span class="p">,</span> <span class="n">summary</span><span class="p">,</span> <span class="n">base</span><span class="p">,</span> <span class="nb">id</span><span class="p">):</span> <span class="c"># On formate la chaine de commit (Projet: Commiter (fichiers_touchés) sommaire_du_commit</span> <span class="nb">str</span> <span class="o">=</span> <span class="s">&#39;</span><span class="si">%s</span><span class="s">: </span><span class="si">%s</span><span class="s"> (</span><span class="se">\x03</span><span class="s">23</span><span class="si">%s</span><span class="se">\x03</span><span class="s">) </span><span class="si">%s</span><span class="s">&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="n">base</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">files</span><span class="p">,</span> <span class="n">summary</span><span class="p">)</span> <span class="n">pbot</span><span class="o">.</span><span class="n">connection</span><span class="o">.</span><span class="n">privmsg</span><span class="p">(</span><span class="n">chan</span><span class="p">,</span> <span class="nb">str</span><span class="p">)</span> <span class="c"># Et un lien vers le commit diff</span> <span class="n">pbot</span><span class="o">.</span><span class="n">connection</span><span class="o">.</span><span class="n">privmsg</span><span class="p">(</span><span class="n">chan</span><span class="p">,</span> <span class="s">&#39;http://git.philpep.org/&#39;</span><span class="o">+</span><span class="n">base</span><span class="o">+</span><span class="s">&#39;.git/commit/?id=&#39;</span><span class="o">+</span><span class="nb">id</span><span class="p">)</span> <span class="c"># Le serveur xmlrpc</span> <span class="k">class</span> <span class="nc">PbotXMLRPCServer</span><span class="p">(</span><span class="n">threading</span><span class="o">.</span><span class="n">Thread</span><span class="p">):</span> <span class="k">def</span> <span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="n">obj</span> <span class="o">=</span> <span class="n">PbotControl</span><span class="p">()</span> <span class="n">srv</span> <span class="o">=</span> <span class="n">SimpleXMLRPCServer</span><span class="p">(</span><span class="n">xmlrpcserver</span><span class="p">,</span> <span class="n">allow_none</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span> <span class="n">srv</span><span class="o">.</span><span class="n">register_instance</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span> <span class="n">srv</span><span class="o">.</span><span class="n">serve_forever</span><span class="p">()</span> <span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">&#39;__main__&#39;</span><span class="p">:</span> <span class="n">pbot</span> <span class="o">=</span> <span class="n">PbotIRCClient</span><span class="p">()</span> <span class="n">pbot</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">server</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">server</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">nick</span><span class="p">)</span> <span class="n">t</span> <span class="o">=</span> <span class="n">PbotXMLRPCServer</span><span class="p">()</span> <span class="n">t</span><span class="o">.</span><span class="n">start</span><span class="p">()</span> <span class="n">pbot</span><span class="o">.</span><span class="n">start</span><span class="p">()</span> </pre></div> <p>Et le hooks à mettre dans le bare repo <code>hooks/post-commit</code> :</p> <div class="codehilite"><pre><span class="c">#!/usr/bin/env python</span> <span class="kn">from</span> <span class="nn">sys</span> <span class="kn">import</span> <span class="n">argv</span> <span class="kn">from</span> <span class="nn">git</span> <span class="kn">import</span> <span class="n">Repo</span> <span class="kn">from</span> <span class="nn">xmlrpclib</span> <span class="kn">import</span> <span class="n">ServerProxy</span> <span class="c"># Path vers le bare repo (peut être avec &#39;.&#39; ça marche aussi ?)</span> <span class="n">r</span> <span class="o">=</span> <span class="n">Repo</span><span class="p">(</span><span class="s">&#39;/usr/home/git/repositories/pblog2.git&#39;</span><span class="p">)</span> <span class="n">c</span> <span class="o">=</span> <span class="n">r</span><span class="o">.</span><span class="n">commit</span><span class="p">(</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="n">s</span> <span class="o">=</span> <span class="n">ServerProxy</span><span class="p">(</span><span class="s">&#39;http://localhost:8888&#39;</span><span class="p">,</span> <span class="n">allow_none</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span> <span class="c"># Liste des fichiers touchés par le commit</span> <span class="k">try</span><span class="p">:</span> <span class="nb">file</span> <span class="o">=</span> <span class="s">&#39; &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="n">e</span><span class="o">.</span><span class="n">a_blob</span><span class="o">.</span><span class="n">path</span> <span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">c</span><span class="o">.</span><span class="n">diff</span><span class="p">(</span><span class="n">r</span><span class="p">,</span> <span class="n">c</span><span class="o">.</span><span class="n">parents</span><span class="p">[</span><span class="mi">0</span><span class="p">])])</span> <span class="k">except</span><span class="p">:</span> <span class="nb">file</span> <span class="o">=</span> <span class="s">&#39;&#39;</span> <span class="c"># Appel de la méthode xmlrpc</span> <span class="n">s</span><span class="o">.</span><span class="n">commit</span><span class="p">(</span><span class="n">c</span><span class="o">.</span><span class="n">author</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="nb">file</span><span class="p">,</span> <span class="n">c</span><span class="o">.</span><span class="n">summary</span><span class="p">,</span> <span class="s">&#39;pblog2&#39;</span><span class="p">,</span> <span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> </pre></div> <p>Voilà, en quelques lignes de python vous avez un bot sympa et vous savez comment il fonctionne laissez parler votre imagination pour l'améliorer.</p> Mon nouveau jouet http://blog.philpep.org/post/Mon-nouveau-jouet http://blog.philpep.org/post/Mon-nouveau-jouet Wed, 05 May 2010 00:00:00 GMT <p>Pris un coup de folie et je me suis procuré le dernier joujou à la mode, un petit nokia n97. Les forfaits c'est vraiment du viol^Wvol, donc clairement je ne vous recommande pas ça, moi j'ai eu l'opportunité de ne pas le payer donc bon. Ce sera nettement plus convi quand il y aura un opérateur mobile valable avec <a href="http://blog.fdn.fr/post/2010/03/22/Pourquoi-l%E2%80%99Internet-mobile-n%E2%80%99est-PAS-Internet">du vrai internet</a>.</p> <p>En attendant tout ça j'ai quand même pu faire des choses sympa, faut dire que Nokia, contrairement à la pomme, laisse pas mal de liberté essentiellement parce qu'on peut installer tout ce qu'on veut sur la machine et ils fournissent tous les outils pour. J'ai le bestiau depuis seulement quelques jours donc j'ai pas encore trop réfléchi sur le coté <code>dev</code>, mais je pense qu'on peut sortir de la prison <code>Internet by orange</code> avec quelques tools réseau bien pensés.</p> <p>Unes des premières appli que j'ai testé c'est <a href="http://s2putty.sourceforge.net/">putty mobile</a>. En wifi sur le réseau local je passe par le port 22 tout marche normal. Seulement sur internet c'est pas sur le port 22 qu'il est mon serveur mais plutôt disons 1234, et avec <code>Internet by orange</code> forcément le port 1234 sortant ça pourrait bien être du contenu pédonazi et alors ça passe pas.</p> <p>Du coup je browse sur un de mes sites, je chope l'IP <code>80.10.46.66</code> de la passerelle nazie dans mes logs, comme c'est bien pensé l'IP de la passerelle change souvent et faut plutôt utiliser <code>80.10.46.0/24</code> (voir plus si ça se trouve).</p> <p>Un petit coup de <code>pf.conf</code> sur la box :</p> <div class="codehilite"><pre>nazis = &quot;80.10.46.0/24&quot; rdr pass proto tcp to port 1234 -&gt; $serv port ssh # Pour les gens normaux rdr pass proto tcp from $nazis to port ssh -&gt; $serv </pre></div> <p>Et taaadaam :</p> <p class="align-center"><img alt="putty symbian" src="http://static.philpep.org/media/public/Scr000005.jpg" /></p> <p>Sûrement à bientôt pour de nouvelles aventures <code>Internet By Orange</code>.</p> blog.philpep.org rune pblog2 http://blog.philpep.org/post/blog.philpep.org-rune-pblog2 http://blog.philpep.org/post/blog.philpep.org-rune-pblog2 Sun, 02 May 2010 00:00:00 GMT <p>Ça bouge beaucoup <a href="http://git.philpep.org/pblog2.git/">sur le git de pblog2</a> en ce moment. Même si on est encore loin d'avoir une version stable, il est pleinement utilisable et apporte son lot de nouveautés :</p> <ul> <li>Interface d'administration très complète</li> <li>Gestion de pages statiques</li> <li>Possibilité de changer et de créer des nouveaux templates</li> <li>Gestionnaire de médias (pour uploader quand on peut pas scp)</li> <li>Post différés</li> <li>Interface d'édition markdown convi en javascript</li> <li>Installation en HTTP</li> <li>Plus de fichier de configuration (tout se fait par HTTP)</li> </ul> <p><a href="http://design.bender-labs.org">Bender</a> s'est mis à fond sur le javascript, pblog2 utilise maintenant <a href="http://jquery.com/">jQuery</a> qui permet de faire des petites choses sympa (bien entendu pblog2 restera au maximum utilisable <em>sans</em> javascript).</p> <p>On peut maintenant créer son propre design (et donc choisir l'emplacement des divers éléments, nuage de tags, archives etc). Pour l'instant pblog2 est distribué avec deux designs (<a href="http://design.bender-labs.org/design/show/White-Lines">White-line</a> et ouverta le petit nouveau que vous voyez sur ce blog).</p> <p>Grand changement notable : pblog2, à contrario de pblog, utilise <a href="http://www.sqlalchemy.org">SQLAlchemy</a>, ce qui permet d'avoir un code plus court, plus simple et en même temps plus optimisé. En plus pblog2 peut tourner maintenant sous toutes les bases de données gérés par sqlalchemy <a href="http://www.sqlalchemy.org/features.html">et il y en a un paquet</a>.</p> <p>Pour la migration de pblog1 vers pblog2 j'ai codé une petite fonction, vous avez juste à donner le <em>chemin</em> d'installation de pblog1 et pblog2 va importer tous vos posts/commentaires/tags.</p> <p>Il reste beaucoup de travail pour corriger les quelques bugs et rendre l'interface plus cohérente, en attendant n'hésitez pas à filer un coup de main, donner des idées de ce que vous aimeriez bien voir sur pblog2.</p> <div class="codehilite"><pre>git clone git://git.philpep.org/pblog2.git </pre></div> Le parseur de wmfs http://blog.philpep.org/post/Le-parseur-de-wmfs http://blog.philpep.org/post/Le-parseur-de-wmfs Tue, 20 Apr 2010 18:38:22 GMT <p><strong>EDIT</strong>: ce billet se voulait une vulgarisation, mais il faut quand même savoir manipuler les notions d'automates, de grammaire etc. Si ça donne envie d'en savoir plus, tant mieux.</p> <p>En même temps que j'ai laché <a href="http://dwm.suckless.org">dwm</a> pour revenir au bon vieux (pas si vieux que ça) <a href="http://www.wmfs.info">wmfs</a>, j'ai totalement recodé le parseur du fichier de configuration.</p> <p>Un fichier de configuration se doit d'être lisible, et sa projection en mémoire doit être facile à manipuler, malheureusement utiliser le même langage (comme le fait dwm avec son fichier de configuration directement en C) rend la configuration moins convi pour peu que l'on ne soit pas expert. Le parseur sert à ça, traduire un langage simple en langage compréhensible par la machine.</p> <p>L'idée c'est d'expliquer un peu comment le parseur de wmfs fonctionne parce que ça touche une partie de l'informatique théorique que j'aime bien : l'étude des <a href="http://fr.wikipedia.org/wiki/Langage_formel">langages formels</a>.</p> <p><a href="http://fr.wikipedia.org/wiki/Lex_et_yacc">Yacc et lex</a> sont souvent utilisés pour ce genre de choses. Mon code est juste une implémentation C d'un <a href="http://fr.wikipedia.org/wiki/Machine_%C3%A0_%C3%A9tats_finis">automate fini déterministe</a>, il ne doit pas être loin du fonctionnement de yacc <strong>pour une grammaire et une syntaxe particulière</strong> (évidement yacc&amp;lex sont beaucoup plus évolués que mon petit bout de code).</p> <p>Donc le travail de lex c'est de lire le fichier caractère par caractère et de renvoyer des <a href="http://fr.wikipedia.org/wiki/Analyse_lexicale#Token">token</a>, c'est à dire un identifiant syntaxique.</p> <p>Le langage de configuration est comme ça :</p> <div class="codehilite"><pre>[section] option = valeur truc = { &quot;liste&quot;, 1, False } [sous-section] [sous-sous-section] machin = True [/sous-sous-section] [/sous-section] [/section] </pre></div> <p>Je fais une première transformation purement syntaxique :</p> <div class="codehilite"><pre><span class="k">enum</span> <span class="n">conf_type</span> <span class="p">{</span> <span class="n">SEC_START</span><span class="p">,</span> <span class="n">SEC_END</span><span class="p">,</span> <span class="n">WORD</span><span class="p">,</span> <span class="n">EQUAL</span><span class="p">,</span> <span class="n">LIST_START</span><span class="p">,</span> <span class="n">LIST_END</span><span class="p">,</span> <span class="n">NONE</span> <span class="p">};</span> <span class="cm">/* qui correspond à [ [/ un_mot = { } autre */</span> </pre></div> <p>Et je range ça dans deux listes chainées, une qui contient des conf_type et une autre qui contient les mots (des char *) :</p> <div class="codehilite"><pre>Liste des TOKEN Liste des mots (WORD) SEC_START WORD &quot;section&quot; WORD &quot;option&quot; EQUAL WORD &quot;valeur&quot; WORD &quot;truc&quot; EQUAL LIST_START WORD &quot;liste&quot; WORD &quot;1&quot; WORD &quot;False&quot; SEC_START WORD &quot;sous-section&quot; SEC_START WORD &quot;sous-sous-section&quot; WORD &quot;machin&quot; EQUAL WORD &quot;True&quot; SEC_END WORD &quot;sous-sous-section&quot; SEC_END WORD &quot;sous-section&quot; SEC_END WORD &quot;section&quot; </pre></div> <p>Une fois ces deux piles construites, il suffit de dépiler en suivant la grammaire (c'est ce que fait yacc). C'est là qu'on parle d'états finis. Désolé ça aurait été plus compréhensible avec un schéma, mais je sais pas en faire donc j'ai écrit ça avec la syntaxe qu'on utilise pour décrire des grammaires.</p> <div class="codehilite"><pre>start: /* rien */ | SEC_START WORD sections SEC_END WORD start /* une suite de sections */ ; sections: /* rien */ | SEC_START WORD sections SEC_END WORD /* des sous sections */ | WORD EQUAL option sections /* des options */ ; option: WORD /* un mot tout simple (une valeur quoi) */ | LIST_START list LIST_END /* une liste de valeurs */ ; list: /* rien */ | WORD list /* une liste de mots */ ; </pre></div> <p>Le parseur va ainsi remplir une structure générique capable de contenir toutes les configurations qui respectent la grammaire et la syntaxe.</p> <p>Pour wmfs en gros c'est ça :</p> <div class="codehilite"><pre><span class="k">struct</span> <span class="n">conf_opt</span> <span class="p">{</span> <span class="cm">/* options */</span> <span class="kt">char</span> <span class="o">*</span><span class="n">name</span><span class="p">;</span> <span class="kt">char</span> <span class="o">*</span><span class="n">val</span><span class="p">[</span><span class="mi">10</span><span class="p">];</span> <span class="cm">/* au plus 10 éléments dans une liste */</span> <span class="n">SLIST_ENTRY</span><span class="p">(</span><span class="n">conf_opt</span><span class="p">)</span> <span class="n">entry</span><span class="p">;</span> <span class="p">}</span> <span class="k">struct</span> <span class="n">conf_sec</span> <span class="p">{</span> <span class="cm">/* section */</span> <span class="kt">char</span> <span class="o">*</span><span class="n">name</span><span class="p">;</span> <span class="n">SLIST_HEAD</span><span class="p">(,</span> <span class="n">conf_opt</span><span class="p">)</span> <span class="n">optlist</span><span class="p">;</span> <span class="cm">/* liste chaînée des options de la section */</span> <span class="n">TAILQ_HEAD</span><span class="p">(,</span> <span class="n">conf_sec</span><span class="p">)</span> <span class="n">sub</span><span class="p">;</span> <span class="cm">/* liste chaînée des sous sections */</span> <span class="n">TAILQ_ENTRY</span><span class="p">(</span><span class="n">conf_sec</span><span class="p">)</span> <span class="n">entry</span><span class="p">;</span> <span class="p">}</span> </pre></div> <p>J'utilise abusivement des macros de <a href="http://www.freebsd.org/cgi/man.cgi?query=queue">&lt;sys/queue.h&gt;</a>.</p> <p>Ensuite il suffit de coder une API qui va récupérer des options/sections précises sur la structure, mais c'est pas le plus dur à faire.</p> <p>Voilà un peu l'idée, l'intérêt de cette méthode c'est qu'elle est certaine (pas ou peu de bugs incompréhensibles), rapide : le fichier de configuration n'est traversé qu'une seule fois, pas besoin de strlen(), strchr(), strcmp(), strstr() qui prennent des plombes.</p> <p>EDIT : j'ai failli oublier de donner le lien vers <a href="http://git.wmfs.info/wmfs.git/tree/src/parse">le code</a></p> les coredump sous Linux http://blog.philpep.org/post/les-coredump-sous-Linux http://blog.philpep.org/post/les-coredump-sous-Linux Thu, 15 Apr 2010 23:49:02 GMT <p>Sous FreeBSD les coredump sont automatiquement générés, voyez plutôt l'entrée <code>default</code> de <a href="http://www.freebsd.org/cgi/man.cgi?query=login.conf">/etc/login.conf(5)</a> avec le coredumpsize=unlimited.</p> <p>Pour faire la même chose sous Linux (en l'occurrence sur Archlinux ce n'est pas le cas par defaut) :</p> <p>Dans <code>/etc/sysctl.conf</code> :</p> <div class="codehilite"><pre>kernel.core_pattern = %e.core </pre></div> <p>Et pour rendre la taille des .core illimitée j'ai édité mon <code>~/.zprofile</code> :</p> <div class="codehilite"><pre>ulimit -c unlimited </pre></div> <p>Et pour rendre les changement effectifs :</p> <div class="codehilite"><pre>sysctl kernel/core_pattern=%e.core # Si vous n&#39;avez pas sysctl : echo &quot;%e.core&quot; | sudo tee /proc/sys/kernel/core_pattern # et on se reconnecte </pre></div> <p>Et pour tester :</p> <div class="codehilite"><pre>cat &gt; foo.c &lt;&lt; EOF #include &lt;stdlib.h&gt; int main(void) { char *p = malloc(sizeof(*p)); free(p+1); return 0; } EOF cc foo.c &amp;&amp; ./a.out [.....] zsh: abort (core dumped) ./a.out # \o/ gdb ./a.out a.out.core .... </pre></div> realpath secure ? http://blog.philpep.org/post/realpath-secure http://blog.philpep.org/post/realpath-secure Mon, 15 Mar 2010 00:00:00 GMT <p>Dans le cadre d'une application serveur (type transfert de fichier : http, ftp, ...), pour contrôler l'accès aux fichiers j'utilise <a href="http://www.freebsd.org/cgi/man.cgi?query=realpath&amp;sektion=3">realpath(3)</a>. Cette fonction permet d'avoir le path (chemin) réel d'un fichier, sans lien relatif dans un des dossiers. Ainsi on a juste à faire un <a href="http://www.freebsd.org/cgi/man.cgi?query=strncmp">strncmp(3)</a> pour le comparer à la <em>racine</em> de l'application.</p> <p>Par exemple une partie du code du serveur HTTP que je suis en train de coder (<code>uri</code> est quelque chose de la forme <code>/../foo/bar/../machin.html</code> et <code>conf_root</code> la racine du style <code>/usr/local/www/</code></p> <div class="codehilite"><pre><span class="kt">char</span> <span class="n">path</span><span class="p">[</span><span class="n">PATH_MAX</span><span class="p">];</span> <span class="kt">char</span> <span class="n">root</span><span class="p">[</span><span class="n">PATH_MAX</span><span class="p">];</span> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">realpath</span><span class="p">(</span><span class="n">uri</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span> <span class="n">path</span><span class="p">)</span> <span class="o">||</span> <span class="o">!</span><span class="n">realpath</span><span class="p">(</span><span class="n">conf_root</span><span class="p">,</span> <span class="n">root</span><span class="p">)</span> <span class="o">||</span> <span class="n">strncmp</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="n">root</span><span class="p">,</span> <span class="n">strlen</span><span class="p">(</span><span class="n">root</span><span class="p">))</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="k">return</span> <span class="n">send_error</span><span class="p">(</span><span class="mi">404</span><span class="p">);</span> </pre></div> <p>Prenez ce post pour une question, à part le <a href="http://www.freebsd.org/cgi/man.cgi?query=chroot&amp;sektion=2">chroot(2)</a> et <em>realpath</em>, comment bien contrôler l'accès aux fichiers ?</p> <p>J'y connais rien en <em>filesystems</em>, mais si on pouvait avoir un moyen rapide de savoir si un fichier est dans tel ou tel fichier ce serait grandement pratique. Sans me vanter j'ai souvent des idées géniales en informatique, mais bien souvent ça a été pensé et implémenté depuis plus de 10 ans ! Du coup si vous avez plus d'information, je suis prêt à converser sur ce sujet avec vous...</p> IPV6 step one two http://blog.philpep.org/post/IPV6-step-one-two http://blog.philpep.org/post/IPV6-step-one-two Thu, 04 Mar 2010 22:13:28 GMT <p>La semaine dernière, j'expliquais <a href="http://blog.philpep.org/post/IPV6-step-1">comment j'avais intégré l'IPV6</a> dans mon réseau. Depuis la donne à fortement changé puisque j'ai mis ma freebox en mode <strong>non</strong> routeur, et donc mon propre routeur sous FreeBSD (ma nouvelle carte wifi marche pas sous OpenBSD).</p> <p>Du coup on en arrive au problème de la freebox qui se comporte en routeur IPV6 même en mode <strong>non</strong> routeur, voyez plutôt <a href="http://www.mail-archive.com/frnog@frnog.org/msg03947.html">cette discussion FRNOG</a> ou on nous explique que ça va peut être changer bientôt. En attendant, pas moyen de router proprement l'IPV6 de Free sans passer par un proxy ndp ou un bridge logiciel, sans compter qu'il n'est pas possible d'avoir un reverse DNS avec l'IPV6 de Free.</p> <p>Grâce à sieur <a href="http://blog.bsdsx.fr/">bsdsx</a> j'ai découvert <a href="http://tunnelbroker.net/">tunnelbrocker.net</a> qui est un service type <a href="http://en.wikipedia.org/wiki/Tunnel_broker">tunnel broker</a> en gros les paquet IPV6 sont encapsulés dans de l'IPV4 entre chez vous et le bout du tunnel (plusieurs sont disponibles suivant votre localisation), ils fournissent un /64 ou un /48 et surtout la possibilité d'avoir un reverse DNS.</p> <p>Sachez qu'il y a encore une troisième façon d'avoir une connectivité IPV6, basé sur la <a href="http://www.ietf.org/rfc/rfc3068.txt">RFC 3068</a> ou encore <a href="http://fr.wikipedia.org/wiki/6to4">6to4</a>, qui permet à n'importe qui d'obtenir un /48 sans demander rien à personne (c'est la passerelle 6to4 la plus proche de vous qui prend en charge le routage de votre traffic), le prefixe est calculé à partir de votre IPV4 publique.</p> <p>J'ai grosso modo donné les 3 manière communes d'accéder au réseau IPV6 quand on est abonné chez Free. Chaque méthode à son avantage (ou pas), vous pouvez lire <a href="http://www.culte.org/listes/linux-31/2008-08/msg00011.html">ce mail</a>.</p> <p>Perso j'ai choisi le tunnel broker Huricane Electrics qui marche bien, il suffit de créer un compte et un tunnel, ils donnent même la config pour FreeBSD mais pour fixer ça en dur dans <a href="http://www.freebsd.org/cgi/man.cgi?query=rc.conf">rc.conf</a> :</p> <div class="codehilite"><pre>ipv6_enable=&quot;YES&quot; ipv6_gateway_enable=&quot;YES&quot; gif_interfaces=&quot;gif0&quot; gifconfig_gif0=&quot;82.229.137.130 216.66.84.46&quot; # Mon IP publique suivie de l&#39;IP du tunnel ipv6_ifconfig_gif0=&quot;2001:470:1f14:7bf::2 2001:470:1f14:7bf::1 prefixlen 128&quot; ipv6_defaultrouter=&quot;2001:470:1f14:7bf::1&quot; # On relie le réseau local (sur l&#39;interface vr1 chez moi) ipv6_ifconfig_vr1=&quot;2001:470:1f15:7bf:dead:c0de::1 prefixlen 96&quot; </pre></div> <p>La conf pf qui va avec :</p> <div class="codehilite"><pre>ext_if = &quot;vr0&quot; int_if = &quot;vr1&quot; gif_if = &quot;gif0&quot; tun_end = &quot;216.66.84.46&quot; # Le bout du tunnel localnet = $int_if:network block log all pass inet proto icmp all icmp-type { echoreq unreach } pass inet6 proto icmp6 all icmp6-type { echoreq unreach timex toobig neighbrsol neighbradv } pass out proto { tcp udp } all pass out on $ext_if from $ext_if to $tun_end # On peut filtre ici (là tout passe sans filtrage) pass in on $gif_if inet6 proto { tcp udp icmp6 } to $localnet </pre></div> <p>En cas de doutes, vous pouvez faire des nmap depuis l'interface web de tunnelbroker.net.</p> <p>Pour la config du reverse DNS c'est pas plus compliqué qu'en IPV4 (juste plus long) :</p> <div class="codehilite"><pre>; master/local6.rev $TTL 3600 ; 1 heure f.b.7.0.5.1.f.1.0.7.4.0.1.0.0.2.ip6.arpa. IN SOA ns.philpep.org. root.philpep.org. ( 2010022601 ; serial 8H ; refresh 4H ; retry 4W ; expire 1D ) ; Min TTL @ IN NS ns.philpep.org. 1.0.0.0.0.0.0.0.e.d.0.c.d.a.e.d IN PTR solo.philpep.org. ; et named.conf zone &quot;f.b.7.0.5.1.f.1.0.7.4.0.1.0.0.2.ip6.arpa&quot; { type master; file &quot;master/local6.rev&quot;; }; </pre></div> <p>Autre chose à savoir, l'IPV6 c'est pas encore ça puisqu'on est encore obligé à un moment ou un autre d'encapsuler l'IPV6 dans l'IPV4 et de passer par des tunnels plus ou moins loin, la connectivité sortante en souffre énormément (allez faire un tour sur youtube.com en IPV6 en passant par un tunnel broker...), du coup ça peut être une bonne idée de préférer l'IPV4 sur la machine où il y a le browser :</p> <div class="codehilite"><pre>/etc/rc.d/ip6addrctl prefer_ipv4 # ou alors QUE pour firefox about:config network.dns.disableIPv6 </pre></div> <p>Si quelqu'un à déjà mis en place son réseau IPV6 en 6to4 avec <a href="http://www.freebsd.org/cgi/man.cgi?query=stf">stf(4)</a>, j'ai lu que la connectivité entrante était moins fiable qu'avec un tunnel broker, je voudrais que quelqu'un m'explique ??</p> <p>Quelques liens :</p> <ul> <li><a href="http://www.gcu-squad.org/2006/02/aaah-mais-si-mais-ah-ah-bien-sur-mais-oui-savait/">Découverte du 6to4 chez gcu.info</a></li> <li><a href="http://fr.wikipedia.org/wiki/6to4">6to4 wikipedia</a></li> <li><a href="http://en.wikipedia.org/wiki/Tunnel_broker">Tunnel broker wikipedia</a></li> <li><a href="http://en.wikipedia.org/wiki/List_of_IPv6_tunnel_brokers">Liste de Tunnel Broker wikipedia</a></li> <li><a href="http://www.mail-archive.com/frnog@frnog.org/msg03947.html">Il a free mais il a pas tout compris FRNOG</a></li> <li><a href="http://www.culte.org/listes/linux-31/2008-08/msg00011.html">IPV6 au CULTE</a></li> </ul> Astuce pf du jour http://blog.philpep.org/post/Astuce-pf-du-jour http://blog.philpep.org/post/Astuce-pf-du-jour Tue, 23 Feb 2010 14:09:07 GMT <p>J'ai la chance d'avoir une bibliothèque avec un rayon informatique bien rempli dans mon Université, dernièrement j'y ai emprunté <a href="http://www.eyrolles.com/Informatique/Livre/le-livre-de-packet-filter-9782212125160">ce bouquin</a>. Là dedans j'y ai vu une syntaxe pour décrire le réseau local que j'avais raté quand j'ai lu <a href="http://www.openbsd.org/faq/pf/fr/index.html">la doc</a> :</p> <div class="codehilite"><pre>ext_if = &quot;rl0&quot; # Au lieu de localnet = &quot;{ 192.168.0.0/24, 2a01:e35:2e58:9820::/64 }&quot; # On peut mettre localnet = $ext_if:network # Ou encore localnet = rl0:network </pre></div> <p><a href="http://blog.philpep.org/tag/Packet%20Filter">Pf</a> va lui même calculer le réseau local à l'aide de l'IP du netmask et du prefixe.</p> <p>Attention tout de même si vous avez plusieurs IP (v4 et v6) sur l'interface, ça peut produire des règles redondantes, en cas de doute :</p> <div class="codehilite"><pre>pfctl -sr </pre></div> <p>EDIT (27/02/10) : En fait quand il y a des alias sur l'IP il va les évaluer mais pour ne spécifier que l'adresses (sans les alias) on peut mettre $ext_if:network:0 </p> IPV6 step 1 http://blog.philpep.org/post/IPV6-step-1 http://blog.philpep.org/post/IPV6-step-1 Sun, 21 Feb 2010 23:31:21 GMT <p>Je viens de passer tout (ou presque) mes services en IPV6 (en gardant IPV4 of course) :</p> <div class="codehilite"><pre>% host blog.philpep.org blog.philpep.org is an alias for lenine.philpep.org. lenine.philpep.org has address 82.229.137.130 lenine.philpep.org has IPv6 address 2a01:e35:2e58:9820::5 </pre></div> <p>Donc l'idée c'est de faire un récit de mon passage étant donné le nombre de modifications que j'ai du faire sur la configurations des machines, des softs et des pare feu. Je vais faire tout ça en 2 ou 3 billets.</p> <p>Mon FAI (free) me fournis un préfixe IPV6 2a01:e35:2e58:9820::/64, et ma topologie réseau permet sans se casser la tête de faire fonctionner tout ça. Le réseau est composé de 3 machines (+ quelques intrus en wifi), un routeur OpenBSD, un serveur FreeBSD avec 4 jails et mon laptop FreeBSD. Le mode routeur est activé sur la freebox (sans DHCP) et elle installe un 192.168.0.0/24 sur lequel sont toutes les machines (jails y compris) sont configurés, ainsi toutes les machines sont reliés physiquement sur la freebox ce qui permet d'éviter les problèmes de <a href="http://fr.wikipedia.org/wiki/Internet_Control_Message_Protocol_V6">neighbor solicitation</a> si seul mon routeur serait physiquement relié à la freebox (on peut passer outre avec <a href="http://www.freebsd.org/cgi/man.cgi?query=ndp">ndp(8)</a>)</p> <p>En ipv4 :</p> <div class="codehilite"><pre>+-------------+ +----------------+ +---------+ | SRV + jails |&lt;-----| Routeur |&lt;------| Freebox | +-------------+ +----------------+ +---------+ Filtrage/Routage En IPV4 tout le trafic passe par le routeur qui dispatche sur les jails. </pre></div> <p>Et en ipv6 :</p> <div class="codehilite"><pre>+-------------+ | SRV + jails |&lt;------+ +-------------+ | | +---------+ +----| Freebox | | +---------+ +------------+ | | Routeur |&lt;-------+ +------------+ En IPV6 le traffic est distribué par la freebox, le routeur ne sert plus (à part les services qui sont dessus). </pre></div> <p>La configuration ipv6 des machines sous FreeBSD :</p> <div class="codehilite"><pre># /etc/rc.conf ipv6_enable=&quot;YES&quot; ipv6_ifconfig_rl0=&quot;2a01:e35:2E58:9820::2 prefixlen 64&quot; ipv6_defaultrouter=&quot;2a01:e35:2E58:9820::1&quot; # ... La config jail jail_lenine_ip=&quot;192.168.0.5,2a01:e35:2E58:9820::5&quot; # ... </pre></div> <p>Un petit reboot (où un <code>/etc/rc.d/pleins_de_trucs restart</code>)</p> <p>Sur OpenBSD :</p> <div class="codehilite"><pre># /etc/hostname.vr0 inet 192.168.0.1 255.255.255/0 inet6 2a01:e35:2E58:9820::3 64 # /etc/mygate (freebox) 192.168.0.254 2a01:e35:2E58:9820::1 </pre></div> <p>Après il faut modifier votre <code>pf.conf</code> en supprimant <code>inet</code> de vos règles de filtrage comme ça on sous entend <code>inet</code> et <code>inet6</code>, concernant icmp c'est plus délicat parce qu'il y a deux protocoles.</p> <div class="codehilite"><pre># /etc/pf.conf pass in inet proto icmp pass in inet6 proto icmp6 </pre></div> <p>Ensuite ça devrait tourner :</p> <div class="codehilite"><pre>% ping6 -c 2 www.google.com PING6(56=40+8+8 bytes) 2a01:e35:2e58:9820::2 --&gt; 2a00:1450:8002::67 16 bytes from 2a00:1450:8002::67, icmp_seq=0 hlim=54 time=49.177 ms 16 bytes from 2a00:1450:8002::67, icmp_seq=1 hlim=54 time=53.867 ms --- www.l.google.com ping6 statistics --- 2 packets transmitted, 2 packets received, 0.0% packet loss round-trip min/avg/max/std-dev = 49.177/51.522/53.867/2.345 ms % traceroute6 www.google.com traceroute6: Warning: www.l.google.com has multiple addresses; using 2a00:1450:8002::6a traceroute6 to www.l.google.com (2a00:1450:8002::6a) from 2a01:e35:2e58:9820::2, 64 hops max, 12 byte packets 1 2a01:e35:2e58:9820::1 0.589 ms 0.530 ms 0.480 ms 2 6to4-b8-e3.intf.routers.proxad.net 35.128 ms 33.359 ms 38.152 ms .... # HO LE VILAIN TUNEL ! :&gt; </pre></div> <p>Vous voilà en IPV6, la première chose à faire c'est reconfigurer votre parre feu, normalement vous n'aurez pas à doubler chaque lignes, enlevez juste <code>inet</code> là où il faut et ça passe. Les seules lignes à doubler sont les redirections (<code>rdr</code>), parce qu'il faut envoyer sur une adresse IPV4 ou sur une adresse IPV6.</p> <p>Dans le prochain billet j'expliquerais comment passer petit à petit ses softs sur IPV6.</p> Dual screen avec X.org : the right way http://blog.philpep.org/post/Dual-screen-avec-X.org-:-the-right-way http://blog.philpep.org/post/Dual-screen-avec-X.org-:-the-right-way Sun, 14 Feb 2010 23:02:19 GMT <p>Sur mon laptop, j'ai deux écrans, l'écran par defaut LVDS (en 1280x800) et un autre en VGA (en 1024x768), jusqu'ici pour avoir un dual screen je mettais un :</p> <div class="codehilite"><pre>SubSection &quot;Display&quot; Virtual 2304 800 EndSubSection </pre></div> <p>Dans mon xorg.conf (2304 = 1280 + 1024 et 800 = max(800, 768)) et la configuration dans mon <code>.xinitrc</code> avec xrandr :</p> <div class="codehilite"><pre>xrandr --output VGA --pos 1280x0 --mode 1024x768 xrandr --output LVDS --pos 0x0 --mode 1280x800 xrandr --output LVDS --left-of VGA </pre></div> <p>Ça pose quelques problèmes, par exemple quand je n'utilise pas le deuxième écran je suis obligé de commenter tout ça, il y a moyen de faire plus propre :</p> <div class="codehilite"><pre>Section &quot;ServerLayout&quot; Identifier &quot;Single&quot; Screen &quot;Screen0&quot; EndSection Section &quot;Screen&quot; Identifier &quot;Screen0&quot; Device &quot;Card0&quot; Monitor &quot;Monitor0&quot; EndSection Section &quot;Device&quot; Identifier &quot;Card0&quot; Driver &quot;intel&quot; VendorName &quot;Intel Corporation&quot; BoardName &quot;Mobile 945GM/GMS, 943/940GML Express Integrated Graphics Controller&quot; BusID &quot;PCI:0:2:0&quot; EndSection Section &quot;Monitor&quot; Identifier &quot;Monitor0&quot; Option &quot;Position&quot; &quot;0 0&quot; Option &quot;PreferredMode&quot; &quot;1280x800&quot; EndSection Section &quot;ServerLayout&quot; Identifier &quot;Dual&quot; Screen &quot;Screen1&quot; EndSection Section &quot;Screen&quot; Identifier &quot;Screen1&quot; Device &quot;Card1&quot; Monitor &quot;Monitor0&quot; SubSection &quot;Display&quot; Virtual 2304 800 EndSubSection EndSection Section &quot;Device&quot; Identifier &quot;Card1&quot; Driver &quot;intel&quot; VendorName &quot;Intel Corporation&quot; BoardName &quot;Mobile 945GM/GMS, 943/940GML Express Integrated Graphics Controller&quot; BusID &quot;PCI:0:2:0&quot; Option &quot;monitor-LVDS&quot; &quot;Monitor0&quot; Option &quot;monitor-VGA&quot; &quot;Monitor1&quot; EndSection Section &quot;Monitor&quot; Identifier &quot;Monitor1&quot; Option &quot;Position&quot; &quot;1280 0&quot; Option &quot;RighOf&quot; &quot;Monitor0&quot; Option &quot;PreferredMode&quot; &quot;1024x768&quot; EndSection </pre></div> <p>Ici je spécifie deux <code>ServerLayout</code> : Single et Dual, je déclare les deux moniteurs avec les résolutions qui vont bien et leur place respective (VGA en 1024x768+1280+0 et LVDS en 1280x800+0+0)</p> <p>Ainsi au démarrage je choisis mon layout (par défaut il prendra le premier : Single) : </p> <div class="codehilite"><pre>startx -- -layout Dual </pre></div>