philpep's blog - tag alix philpep's blog - tag alix rss http://blog.philpep.org fr Sat, 13 Feb 2010 02:31:41 GMT Pblog Jouons avec kvm http://blog.philpep.org/post/Jouons-avec-kvm http://blog.philpep.org/post/Jouons-avec-kvm Sat, 13 Feb 2010 02:31:41 GMT <p>J'ai codé un petit programme tout simple qui fait clignoter les leds de mon routeur dès qu'un service est par terre. Ma méthode (qui ne doit pas être la meilleure mais je m'en fout un peu) consiste à regarder régulièrement la liste des processus et détecter l'arrêt d'un service quand le processus associé n'existe plus. J'ai commencé avec un script shell, puis étant assez mauvais pour tout ce qui ressemble de près ou de loin à du script j'ai décidé de le faire en C (langage d'excellence n'est ce pas...?).</p> <p>Je me suis volontairement compliqué la tache en utilisant des fonctions très proches du système, ainsi s'il est possible d'obtenir une liste de processus via <a href="http://www.freebsd.org/cgi/man.cgi?query=ps">ps(1)</a> avec un <a href="http://www.freebsd.org/cgi/man.cgi?query=popen">popen(3)</a> super crade ou encore <a href="http://www.freebsd.org/cgi/man.cgi?query=sysctl&amp;sektion=3">sysctl(3)</a> j'ai voulu utiliser <a href="http://www.freebsd.org/cgi/man.cgi?query=kvm">kvm(3)</a> <code>kernel memory interface</code> qui est en programmation système la méthode la plus appropriée (d'ailleurs 'ps' est codé avec ça), c'est juste une interface qui va nous permettre d'accéder au données du kernel (une copie bien entendu), ici la liste des processus en cours.</p> <p>Le hic c'est que si les fonctions de kvm sont très standard l'implémentation est très différente suivant les systèmes, comme à peu près toute implémentation, l'important c'est que l'interface soit standard. Ainsi à la lecture de la structure qui décrit les processus <code>kinfo_proc</code> de <a href="http://svn.freebsd.org/viewvc/base/head/sys/sys/user.h?view=markup">sys/user.h</a> on se dit chouette pleins d'info à disposition, sauf que sur OpenBSD c'est pas du tout la même forme (ni le même fichier d'ailleurs). D'où l'importance d'une interface riche et c'est ce que nous promet <code>kvm</code>.</p> <p>Assez causé passons au code (je n'explique pas ou peu le code en dehors des fonctions kvm)</p> <div class="codehilite"><pre><span class="cp">#include &lt;stdio.h&gt;</span> <span class="cp">#include &lt;stdlib.h&gt;</span> <span class="cp">#include &lt;string.h&gt;</span> <span class="cp">#include &lt;unistd.h&gt;</span> <span class="cp">#include &lt;err.h&gt;</span> <span class="cp">#include &lt;libgen.h&gt;</span> <span class="cp">#include &lt;fcntl.h&gt;</span> <span class="cp">#include &lt;limits.h&gt;</span> <span class="cp">#include &lt;paths.h&gt;</span> <span class="cp">#include &lt;kvm.h&gt;</span> <span class="cp">#include &lt;sys/param.h&gt;</span> <span class="cp">#include &lt;sys/sysctl.h&gt;</span> <span class="cp">#include &lt;sys/wait.h&gt;</span> <span class="cp">#include &lt;sys/user.h&gt;</span> <span class="kt">void</span> <span class="nf">start_leds</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span> <span class="cm">/* Ici on execute /usr/sbin/gioctl -q gpio0 led3 (on|off)</span> <span class="cm"> * suivant la parité du conteur statique &#39;i&#39;</span> <span class="cm"> * 60 fois avec une pause d&#39;une seconde. */</span> <span class="k">static</span> <span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="k">switch</span><span class="p">(</span><span class="n">fork</span><span class="p">())</span> <span class="p">{</span> <span class="k">case</span> <span class="o">-</span><span class="mi">1</span>: <span class="n">err</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="s">&quot;fork&quot;</span><span class="p">);</span> <span class="k">break</span><span class="p">;</span> <span class="k">case</span> <span class="mi">0</span>: <span class="n">execl</span><span class="p">(</span><span class="s">&quot;/usr/sbin/gpioctl&quot;</span><span class="p">,</span> <span class="s">&quot;gpioctl&quot;</span><span class="p">,</span> <span class="s">&quot;-q&quot;</span><span class="p">,</span> <span class="s">&quot;gpio0&quot;</span><span class="p">,</span> <span class="s">&quot;led3&quot;</span><span class="p">,</span> <span class="p">(</span><span class="n">i</span><span class="o">%</span><span class="mi">2</span><span class="p">)</span> <span class="o">?</span> <span class="s">&quot;on&quot;</span> <span class="o">:</span> <span class="s">&quot;off&quot;</span><span class="p">,</span> <span class="p">(</span><span class="kt">char</span><span class="o">*</span><span class="p">)</span><span class="nb">NULL</span><span class="p">);</span> <span class="n">err</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="s">&quot;execl&quot;</span><span class="p">);</span> <span class="k">break</span><span class="p">;</span> <span class="nl">default:</span> <span class="n">wait</span><span class="p">(</span><span class="nb">NULL</span><span class="p">);</span> <span class="k">break</span><span class="p">;</span> <span class="p">}</span> <span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="n">i</span><span class="o">++</span> <span class="o">&lt;=</span> <span class="mi">60</span><span class="p">)</span> <span class="k">return</span> <span class="n">start_leds</span><span class="p">();</span> <span class="k">return</span><span class="p">;</span> <span class="p">}</span> <span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">argv</span><span class="p">[])</span> <span class="p">{</span> <span class="n">kvm_t</span> <span class="o">*</span><span class="n">kd</span><span class="p">;</span> <span class="kt">char</span> <span class="n">berr</span><span class="p">[</span><span class="n">_POSIX2_LINE_MAX</span><span class="p">];</span> <span class="k">struct</span> <span class="n">kinfo_proc</span> <span class="o">*</span><span class="n">p</span><span class="p">,</span> <span class="o">*</span><span class="n">procs</span><span class="p">;</span> <span class="kt">int</span> <span class="n">n</span><span class="p">,</span> <span class="n">j</span><span class="p">,</span> <span class="n">k</span><span class="p">,</span> <span class="n">found</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="kt">char</span> <span class="o">**</span><span class="n">pargv</span><span class="p">;</span> <span class="k">if</span> <span class="p">(</span><span class="n">argc</span> <span class="o">&lt;</span> <span class="mi">2</span><span class="p">)</span> <span class="n">errx</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="s">&quot;Usage check_proc procs ...&quot;</span><span class="p">);</span> <span class="cm">/* On accède aux données du kernel qui tourne actuellement (NULL) */</span> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="p">(</span><span class="n">kd</span> <span class="o">=</span> <span class="n">kvm_open</span><span class="p">(</span><span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">O_RDONLY</span><span class="p">,</span> <span class="n">berr</span><span class="p">)))</span> <span class="n">errx</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="s">&quot;%s&quot;</span><span class="p">,</span> <span class="n">berr</span><span class="p">);</span> <span class="cm">/* On demande la liste des processus, kinfo_proc est décrite</span> <span class="cm"> * dans sys/sysctl.h sur OpenBSD et sys/user.h sur FreeBSD.</span> <span class="cm"> * Il nous la donne dans un tableau continu de pointeurs de</span> <span class="cm"> * taille qu&#39;on récupère dans &#39;n&#39;. */</span> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="p">(</span><span class="n">procs</span> <span class="o">=</span> <span class="n">kvm_getprocs</span><span class="p">(</span><span class="n">kd</span><span class="p">,</span> <span class="n">KERN_PROC_ALL</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">n</span><span class="p">)))</span> <span class="n">err</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="s">&quot;kvm_getprocs: %s&quot;</span><span class="p">,</span> <span class="n">kvm_geterr</span><span class="p">(</span><span class="n">kd</span><span class="p">));</span> <span class="k">for</span> <span class="p">(</span><span class="n">k</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">k</span> <span class="o">&lt;</span> <span class="n">argc</span><span class="p">;</span> <span class="n">k</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span> <span class="k">for</span> <span class="p">(</span><span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">p</span> <span class="o">=</span> <span class="n">procs</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">,</span> <span class="n">p</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span> <span class="cm">/* On accède à la liste des arguments du programme qui a</span> <span class="cm"> * généré le processus courant. */</span> <span class="n">pargv</span> <span class="o">=</span> <span class="n">kvm_getargv</span><span class="p">(</span><span class="n">kd</span><span class="p">,</span> <span class="n">p</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="n">pargv</span> <span class="o">&amp;&amp;</span> <span class="n">pargv</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">&amp;&amp;</span> <span class="n">strstr</span><span class="p">(</span><span class="n">pargv</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">argv</span><span class="p">[</span><span class="n">k</span><span class="p">]))</span> <span class="p">{</span> <span class="n">found</span><span class="o">++</span><span class="p">;</span> <span class="k">break</span><span class="p">;</span> <span class="p">}</span> <span class="p">}</span> <span class="p">}</span> <span class="k">if</span> <span class="p">(</span><span class="o">-</span><span class="mi">1</span> <span class="o">==</span> <span class="n">kvm_close</span><span class="p">(</span><span class="n">kd</span><span class="p">))</span> <span class="n">err</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="s">&quot;kvm_close&quot;</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="n">found</span> <span class="o">!=</span> <span class="n">argc</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="n">start_leds</span><span class="p">();</span> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> <span class="p">}</span> </pre></div> <p>Et l'exécution, on veut tester si un processus du nom de 'dhcpd' tourne sur le système, si ce n'est pas le cas on lance le clignotement de la led pendant une minute :</p> <div class="codehilite"><pre># gcc -o check_proc check_proc.c -lkvm # ./check_proc dhcpd </pre></div> <p>Le mien s'exécute dans un cron toute les minutes :</p> <div class="codehilite"><pre>* * * * * /root/bin/check_proc named dhcpd adsuck ntpd </pre></div> Alix fail et OpenWrt http://blog.philpep.org/post/Alix-fail-et-OpenWrt http://blog.philpep.org/post/Alix-fail-et-OpenWrt Mon, 08 Feb 2010 14:46:46 GMT <p>Ce week end j'ai essuyé pas mal d'échecs en tout genres, j'ai une superbe <a href="/tag/alix">alix</a> qui tourne sur <a href="/tag/OpenBSD">OpenBSD</a> et j'ai une carte wifi en minipci dessus qui marche passablement mal sur OpenBSD (tous les modes ne marchent pas et beaucoup de pertes de paquets quand ça marche).</p> <p>Du coup je me mis en tête le fait que ça tournera mieux sous un autre OS, j'ai donc essayé dans l'ordre <a href="/tag/FreeBSD">FreeBSD</a>, Debian et <a href="http://openwrt.org">OpenWrt</a>. Aucuns n'a su faire tourner ma carte même avec les derniers drivers, j'avais même pas d'interface, comme quoi le support matériel sur OpenBSD est pas aussi mauvais qu'on le pense.</p> <p>Donc si quelqu'un à réussi à faire tourner convenablement la carte <a href="http://linitx.com/viewproduct.php?prodid=11331">Engenius NMP-8602+ 400mW a/b/g miniPCI</a> sur un OS libre merci de me faire signe.</p> <p>J'ai donc remis OpenBSD dessus et enlevé la carte wifi (si quelqu'un est intéressé je suis prêt à la céder d'ailleurs, toute neuve jamais servie :&gt;)</p> <p>J'ai quand même beaucoup joué avec le boot pxe sur sortie série Linux/BSD donc je suis bien rodé là dessus maintenant. Et surtout j'ai découvert OpenWrt, une toute petite distribution linux pour l'embarqué, faite à la base pour flasher les firmware proprio sur les routeurs du marché elle tourne aussi bien sur tout autre matériel et c'est un projet très dynamique et original. L'installation par pxe est super simple, il suffit de compiler un <a href="http://en.wikipedia.org/wiki/RAM_disk">ramdisk</a> et de démarrer dessus.</p> <div class="codehilite"><pre>$ ls -l /usr/local/pxe/ total 1796 -rw-r--r-- 1 phil phil 1786396 Feb 7 15:41 openwrt-x86-vmlinuz -rwxr-xr-x 1 root wheel 16466 Feb 6 21:31 pxelinux.0 drwxr-xr-x 2 root wheel 512 Feb 7 15:41 pxelinux.cfg $ cat /usr/local/pxe/pxelinux.cfg/default # Simplement spécifier la vitesse du port série # 38400 ici serial 0 38400 0 console 0 label linux kernel openwrt-x86-vmlinuz append init=/etc/preinit console=tty0 console=ttyS0,38400n8 reboot=bios </pre></div> <p>Après c'est du pxe classique, tftp et dhcpd et ça démarre :</p> <p><img alt="openwrt" src="/static/pub/openwrt.png" /></p> <p>Après il suffit d'envoyer l'image sur le disque dur (soit la votre, soit celle qui est distribuée) :</p> <div class="codehilite"><pre>root@Solo:/# wget http://downloads.openwrt.org/kamikaze/8.09.2/x86/openwrt-x86-squashfs.image root@Solo:/# dd if=openwrt-x86-squashfs.image of=/dev/hda </pre></div> <p>Et <em>c'est tout</em> !</p> <p>À coté de ça vous avez une interface de configuration web convi, un petit sshd <a href="http://matt.ucc.asn.au/dropbear/dropbear.html">dropbear</a> et pleins de packages disponible (très orienté réseau bien sûr). Ça doit être encore plus réjouissant quand on flashe un routeur wifi proprio :)</p> <p>Mais bon, alix mérite qu'on l'exploite plus que ça, j'aime bien l'interface web mais j'aime mieux éditer mon <a href="/tag/Packet%20Filter">pf.conf</a> avec <a href="/tag/vim">vim</a>.</p> Controler les leds sur ALIX 2D3 http://blog.philpep.org/post/Controler-les-leds-sur-ALIX-2D3 http://blog.philpep.org/post/Controler-les-leds-sur-ALIX-2D3 Mon, 02 Nov 2009 21:30:58 GMT <p>Il y a 4 leds sur le devant, la première est réservée par l'alimentation et la dernière par la carte minipci, mais les deux autres sont à disposition pour nos amis scripteur. Ces deux leds se contrôlent sur les broches 25 et 27 du gpio.</p> <p>Il faut les activer avant que securelevel passe à 1. Dans <code>/etc/rc.securelevel</code> :</p> <div class="codehilite"><pre># Configuring the leds echo -n &quot;Configuring the leds : &quot; /usr/sbin/gpioctl gpio0 25 set out led2 /usr/sbin/gpioctl gpio0 27 set out led3 </pre></div> <p>Un petit reboot, et vous pouvez controler vos leds (q = quiet) avec :</p> <div class="codehilite"><pre>gpioctl -q gpio0 led2 off gpioctl -q gpio0 led2 on </pre></div> <p>A vous de scripter ce que vous voulez derrière, style un script qui fait clignoter la led si la passerelle est accessible etc.</p> <ul> <li><a href="http://blog.lekermeur.net/?page_id=565">Exemple de script</a></li> </ul> Install OpenBSD 4.6 sur alix 2D3 http://blog.philpep.org/post/Install-OpenBSD-4.6-sur-alix-2D3 http://blog.philpep.org/post/Install-OpenBSD-4.6-sur-alix-2D3 Mon, 26 Oct 2009 01:22:48 GMT <p>Je viens d'acquérir une <a href="http://www.pcengines.ch/alix2d3.htm">carte ALIX 2D3</a> pour m'en servir comme routeur et pour faire tourner certains services critiques à la place de mon serveur qui pourrait décider de tomber en panne un jour. Cette machine n'ayant pas de cartes graphique il y a deux méthodes pour installer un OS sur la carte flash :</p> <ul> <li>Installer un OS depuis un autre ordinateur en y branchant la carte flash.</li> <li>Boot par PXE (réseau) et communication via le port série.</li> </ul> <p>Si comme moi vous n'avez aucuns adaptateur pour brancher la carte flash sur une autre machine il faut le faire en PXE, vous allez voir que même si ça parait compliqué c'est (après coup) assez facile à faire.</p> <p>Nous allons installer <a href="http://www.openbsd.org">OpenBSD</a> 4.6 par PXE depuis une machine FreeBSD 7.2 mais n'importe quelle autre machine pourvue d'une interface réseau ferra l'affaire (je vous laisse le soin de trouver la documentation approprié pour votre OS).</p> <p>Déjà il faut activer le boot PXE dans le bios de la carte alix, donc il vous faudra un cable null-modem (et pas un mini gender changer comme j'ai eu le malheur de faire). Si vous n'avez pas de port série, il vous faut un adaptateur série/USB. Ensuite pour causer au port série j'ai utilisé <a href="http://www.freshports.org/comms/picocom/">comms/picocom</a>, lançons le avec la vitesse indiquée dans <a href="http://www.philpep.org/pub/alix2.pdf">la doc</a>.</p> <div class="codehilite"><pre>picocom -b38400 -fx /dev/ttyU0 </pre></div> <p>Pendant le memcheck tapez sur <code>s</code> pour afficher l'état du bios. Ensuite <code>e</code> pour activer le boot PXE et <code>q</code> pour enregistrer et quitter.</p> <p>Pour booter sur le réseau il faut trois choses :</p> <ol> <li>Un serveur dhcp</li> <li>Un serveur tftp</li> <li>Que alix et le serveur soient branchées ensembles.</li> </ol> <p>Pour le branchement je me suis pas trop cassé la tête vu que les interfaces de la freebox sont sur le même layer. Il suffit donc de brancher alix sur la freebox (avec l'interface à coté de l'alimentation, je ne sais pas si les autres sont capables de démarrer en PXE).</p> <p>Ensuite installez le serveur dhcp, moi j'ai utilisé <a href="http://www.freshports.org/net/isc-dhcp30-server">net/isc-dhcp30-server</a>. Ça se configure dans <code>/usr/local/etc/dhcpd.conf</code></p> <div class="codehilite"><pre>ddns-update-style none; shared-network LOCAL-NET { # Mon DNS cache, utilisez ceux de votre FAI si vous n&#39;en avez pas option domain-name-servers 192.168.0.3; # On attribue une adresse sur le réseau de la freebox subnet 192.168.0.0 netmask 255.255.255.0 { # C&#39;est la freebox qui sert de routeur pour l&#39;instant option routers 192.168.0.254; filename &quot;pxeboot&quot;; range 192.168.0.200 192.168.0.202; next-server 192.168.0.2; # IP sur serveur de boot PXE default-lease-time 86400; max-lease-time 90000; } } </pre></div> <p>Et maintenant le serveur tftp, juste une ligne à décommenter dans <code>/etc/inetd.conf</code> :</p> <div class="codehilite"><pre>tftp dgram udp wait root /usr/libexec/tftpd tftpd -l -s /tftpboot </pre></div> <p>Maintenant il faut mettre les bons fichiers au bon endroit :</p> <div class="codehilite"><pre>mkdir /tftpboot &amp;&amp; cd /tftpboot ftp ftp://ftp.fr.openbsd.org/pub/OpenBSD/4.6/i386/pxeboot ftp ftp://ftp.fr.openbsd.org/pub/OpenBSD/4.6/i386/bsd.rd </pre></div> <p>Maintenant démarrez votre serveur de boot PXE :</p> <div class="codehilite"><pre>echo dhcpd_enable=\&quot;YES\&quot; &gt;&gt; /etc/rc.conf echo inetd_enable=\&quot;YES\&quot; &gt;&gt; /etc/rc.conf /usr/local/etc/rc.d/isc-dhcpd start /etc/rc.d/inetd start </pre></div> <p>Relancez picocom et redémarrez votre alix. Elle va chercher un serveur DHCP, donc si elle ne trouve pas le votre mais plutôt celui de la freebox, désactivez le dhcp de la freebox momentanément.</p> <p>Ensuite vous voyez le prompt de boot OpenBSD qui echoue parce qu'il ne trouve pas de fichier <code>bsd</code> sur le serveur tftp. Et heureusement parce qu'on a des options à passer au boot (remarque: on aurrait pu les mettre dans /tftpboot/etc/boot.conf, mais je connais pas parfaitement la syntaxe de ce fichier). Il faut lui dire qu'on est sur un terminal série et lui donner la vitesse de celui ci :</p> <div class="codehilite"><pre><span class="n">boot</span><span class="o">&gt;</span> <span class="n">stty</span> <span class="n">com0</span> <span class="mi">38400</span> <span class="n">boot</span><span class="o">&gt;</span> <span class="n">set</span> <span class="n">tty</span> <span class="n">com0</span> <span class="n">boot</span><span class="o">&gt;</span> <span class="n">bsd</span><span class="o">.</span><span class="n">rd</span> </pre></div> <p>Là il va chercher le bsd.rd et démarre l'installateur OpenBSD et vous pouvez suivre <a href="http://www.openbsd.org/faq/fr/faq4.html#Install">la documentation</a>.</p> <ol> <li>Remarque0 : Au moment où j'écris ces lignes la doc d'install n'est pas à jours pour OpenBSD 4.6 , en fait l'installateur est beaucoup plus simple maintenant.</li> <li>Remarque1 : Au moment où il pose la question "Change the default console to com0?" répondez oui, ça évitera de le faire plus tard.</li> </ol> <p>Voilà, sinon j'en suis très heureux de cette petite alix qui me sert maintenant de routeur, j'ai mis un proxy http (privoxy) transparent pour filtrer les pubs sur le web, déplacé le serveur DNS dessus en cas de panne de mon autre machine, un <a href="/tag/Packet%20Filter">pf</a>, un dhcpd etc .</p> <p>Enjoy.</p>