Une autre solution c'est d'avoir une machine allumée 24h/24 avec wifi et lien filaire vers le switch, c'est la solution que j'ai retenue. Sauf que faire un bridge wlan0 <=> eth0 c'est pas si simple que ça en a l'air, il y a bien une solution avec ebtables, mais avec ma carte wifi et son driver proprio ça ne fonctionne pas, le lien wifi boucle entre connexion et déconnexion.
J'ai donc cherché à faire autrement, le NAT j'aime pas trop parce que ça m'obligerais à avoir deux réseau puis a pusher la nouvelle route sur tous mes réseaux (vpn etc). J'ai donc trouvé une solution avec un proxy arp.
C'est assez simple:
iface eth0 inet static address 192.168.31.253 broadcast 192.168.31.255 netmask 255.255.255.0 # Empèche ifup d'ajouter la route 192.168.31.0/24 sur eth0 up ip route del 192.168.31.0/24 dev eth0 # On doit avoir une route pour chaque machine derrière le switch # Ici 192.168.31.3 up ip route add 192.168.31.3/32 dev eth0 iface wlan0 inet static wpa-ssid rhizome # J'aime mon ssid :) wpa-psk SECRET address 192.168.31.253 broadcast 192.168.31.255 netmask 255.255.255.0 gateway 192.168.31.1
Et activer le proxy arp dans /etc/sysctl.conf
net.ipv4.conf.all.proxy_arp=1
Ensuite, comme je suis feignant, j'aimerais bien que ma machine 192.168.31.3 obtienne son IP par dhcp, il suffit d'utiliser dhcprelay:
apt-get install isc-dhcp-relay
Le script post-inst nous demande l'IP du serveur dhcp et voilà.
Pour aller encore plus loin dans l'automatisation, j'aurais aimé rajouter les routes sur eth0 automatiquement,
j'ai trouvé une solution très moche en coupant mon /24 en deux /25 et d'utiliser l'option dhcp agent.circuit-id
pour allouer l'adresse IP dans un des deux blocs suivant si le dhcp-relay a été utilisé, au final c'était vraiment
trop moche alors je l'ai pas fait.
Pour expérimenter différents setup, j'ai utilisé un script permettant de simuler un environnement réseau avec User Mode Linux et des switchs virtuels avec vde.
J'ai commité mes tests sur github.
git clone git://github.com/philpep/network-lab.git cd network-lab git checkout -b lab-arp-proxy-dhcp origin/lab-arp-proxy-dhcp cd lab-arp-proxy-dhcp ./setup
Ce billet concerne l'installation de NetBSD 5.1 (la dernière), sur une SGI Indy. Coté exotisme on est comblé :)

>> hinv System: IP22 Processor: 100 Mhz R4000, with FPU Primary I-cache size: 8 Kbytes Primary D-cache size: 8 Kbytes Secondary cache size: 1024 Kbytes Memory size: 64 Mbytes Graphics: Indy 8-bit SCSI Disk: scsi(0)disk(1) SCSI Disk: scsi(0)disk(2) Audio: Iris Audio Processor: version A2 revision 4.1.0
Pour commencer, impossible d'y brancher un écran à moins d'avoir un connecteur vidéo DB13W3, la machine est pourvue de deux ports série mini din 8 et elle démarre dessus quand il n'y a pas de clavier branché. Très bien, mais si comme moi on a pas de cable Mini DIN 8 vers série (9 ou 25 broches) alors il faut sortir les bobines de fil et s'en faire un, le grand Internet fourmille de doc à ce sujet, moi j'ai trouvé ce schéma très parlant (s/mac/indy):

On se connecte donc et on tombe sur le bios (qui n'a rien à envier à nos bios x86 de 2011), on en profite pour récupérer l'adresse ethernet de la machine:
System Maintenance Menu 1) Start System 2) Install System Software 3) Run Diagnostics 4) Recover System 5) Enter Command Monitor Option? 5 >>> printenv eaddr eaddr=08:00:69:06:f4:9b
Je suppose que vous savez configurer un serveur tftp/dhcp/nfs. Moi j'ai fait ça sur une machine Debian sauf le serveur dhcp qui est mon routeur FreeBSD:
sudo apt-get install tftpd-hpa bsdtar nfs-kernel-server mkdir ~/indy wget ftp://ftp.fr.netbsd.org/pub/NetBSD/NetBSD-5.1/sgimips/installation/netboot/diskimage.tgz wget ftp://ftp.fr.netbsd.org/pub/NetBSD/NetBSD-5.1/sgimips/binary/sets/kern-GENERIC32_IP2x.tgz bsdtar xvzf kern-GENERIC32_IP2x.tgz (sudo mkdir root; cd root; sudo bsdtar xvzpf ../diskimage.tgz) #/etc/default/tftpd-hpa TFTP_DIRECTORY = "/home/phil/indy" #/etc/exports (gruiiik gruiiik) /home/phil/indy/root/ 192.168.31.0/24(rw,no_subtree_check,all_squash,anonuid=0,anongid=0) sudo exportfs -r #dhcpd.conf host indy { hardware ethernet 08:00:69:06:f4:9b; fixed-address 192.168.31.8; option tftp-server-name "192.168.31.3"; # le serveur tftp (debian) next-server 192.168.31.3; # le serveur nfs (debian) filename "netbsd"; # le nom du kernel à loader en tftp option root-path "/home/phil/indy/root";# path racine nfs }
On retourne configurer notre bios de l'indy:
>> setenv SystemPartition bootp(): >> setenv netaddr 192.168.31.8 >> boot
Mince ça ne marche pas, on fouille partout sur internet pour trouver des infos, puis on finit par lancer un tcpdump pour voir que c'est au niveau tftp que ça coince. Ensuite on lit la doc d'install NetBSD et on y trouve ceci:
Note that some older bootproms have an interesting bug in reading the kernel via TFTP. They handle the port number as a signed entity, and can thus not connect to ports >32767. You can work around this problem on the TFTP server (given that it is a NetBSD host) by using ``sysctl'' to set ``net.inet.ip.anonportmin'' and ``net.inet.ip.anonportmax'' to more suitable values. For example: # sysctl -w net.inet.ip.anonportmin=16384 # sysctl -w net.inet.ip.anonportmax=32767
Pour faire la même chose avec linux:
echo "16384 32767" | sudo tee /proc/sys/net/ipv4/ip_local_port_range
L'installation de NetBSD se passe sans problème. Sauf à la fin où il faut se mettre dans un shell pour taper ces quelques commandes, sans quoi on ne pourra pas démarrer sur le disque
cd /usr/mdec ./sgivol -w boot /usr/mdec/ip2xboot sd0 # => yes reboot
Tout est dans la doc d'install, et ça marche(tm). Moi par exemple j'ai installé NetBSD sur le premier disque (sd0):
>> setenv systempartition scsi(0)disk(1)rdisk(0)partition(8) >> setenv osloadpartition scsi(0)disk(1)rdisk(0)partition(8) >> setenv osloadfilename netbsd >> setenv osloadoptions auto >> setenv osloader boot
Pour les curieux, voyez le dmesg de la machine.
À vous de compiler tout et n'importe quoi, juste pour le plaisir de dire "Hey mec, c'est pas portable ton code là !" :-)
]]>Seulement, l'IDE officiel d'arduino m'a vite gonflé, je suis très réticent à prendre en main de nouveaux logiciels, surtout quand ils sont graphiques, c'est plus fort que moi, trop de boutons et autres ClickClickClick ça me file des ... boutons. J'ai donc essayé de coder pour arduino en utilisant mon IDE habituel, c'est à dire vim et make, voilà la manip (pour une machine debian)
# La lib arduino http://arduino.cc/en/Main/Software (ici linux x86_64) wget http://arduino.googlecode.com/files/arduino-0022-64-2.tgz -O - | tar xvzf - # Le travail est déjà tout fait ici: http://mjo.tc/atelier/2009/02/arduino-cli.html wget http://mjo.tc/atelier/2009/02/acli/arduino-mk_0.6.tar.gz -O - | tar xvzf - sudo mkdir -p /usr/local/bin sudo install -m 755 -o root -g root arduino-mk-0.6/ard-parse-boards /usr/local/bin/
Ensuite copiez le fichier arduino-mk-0.6/Arduino.mk dans votre projet et incluez le dans un Makefile:
TARGET = hello # Le nom du programme final (doit correspondre à un fichier hello.pde) ARDUINO_DIR = /path/to/arduino-0022 BOARD_TAG = uno # Voir Arduino.mk pour toutes les cartes supportées ARDUINO_PORT = /dev/ttyACM0 AVR_TOOLS_PATH = /usr/bin AVRDUDE_CONF = $(ARDUINO_DIR)/hardware/tools/avrdude.conf AVRDUDE = $(ARDUINO_DIR)/hardware/tools/avrdude include Arduino.mk # Petit alias perso, make com lance cu sur le bon port avec un baud de 9600 com: cu -l $(ARDUINO_PORT) -s 9600
Ne pas oublier les outils indispensables:
sudo apt-get install gcc-avr binutils-avr avr-libc libyaml-perl cu
Pour compiler c'est make et pour envoyer le code sur la carte make upload.
>>> import datetime >>> bool(datetime.time(0, 0)) False # Pour lever toute ambigüité quand on veut tester si # une variable est à None: if machin is not None: blah() # au lieu de if machin: blah()
Le coup de minuit n'est qu'un exemple parmis d'autres, c'est la classe qui décide de ce qui est vrai et de ce qui est faux en implémentant __nonzero__().
]]>zfs, c'était pour moi l'occasion de tester zfs (send|recv) over ssh. L'idée c'est qu'on envoie les donnés de manière incrémentale entre un snapshot du jour et un snapshot de la veille. Ce que l'on gagne par rapport à des solutions comme rsync c'est de la rapidité et moins d'accès disques (zfs sait exactement ce qui a bougé entre deux snapshot), l'autre avantage c'est sur la machine de backup on a un snapshot par jour, on peut donc facilement retrouver des fichiers supprimés.
#!/bin/sh set -e # Used in ssh command, example user@host -p 2222 REMOTE_HOST="diophante" # Source zfs pool POOL_SRC="tank" # zfs sets to backup (relative to POOL_SRC) SETS="usr/local/vmail usr/local/data usr/local/pgsql/backups usr/home usr/local/git var/backups" # Destination pool POOL_DST="tank/backup/${REMOTE_HOST}" # We use ssh connection sharing SSH_ARGS="-o ControlPath=~/.ssh/%r@%h:%p" # zfs snapshot prefix => tank/foo@bck-2011-05-25 PREFIX="bck-" # Remote zfs command REMOTE_ZFS="ssh ${SSH_ARGS} ${REMOTE_HOST} sudo zfs" # Local zfs command LOCAL_ZFS="sudo zfs" # Launch master ssh for sharing connections ssh -MNn ${SSH_ARGS} ${REMOTE_HOST} & ssh_master_pid=$! for zfs_set in ${SETS} do # Test if destination exist ${LOCAL_ZFS} list -H ${POOL_DST}/${zfs_set} >/dev/null date_suffix="${PREFIX}`date +%F`" snap="${POOL_SRC}/${zfs_set}@${date_suffix}" old_snap=`${REMOTE_ZFS} list -Ht snapshot 2>/dev/null | grep "^${POOL_SRC}/${zfs_set}@${PREFIX}" 2>/dev/null| awk -F' ' '{ print $1 }' 2>/dev/null` if [ "${old_snap}" ] then if [ "${old_snap}" != "`echo ${old_snap} | head -n 1`" ] then echo "[!] Multiple zfs snapshot found: ${old_snap}" echo "[!] Consider changing PREFIX or fix the issue yourself" continue fi if [ "${old_snap}" = "${snap}" ] then echo "[!] ${snap} exists" continue fi fi echo ${REMOTE_ZFS} snapshot "${snap}" ${REMOTE_ZFS} snapshot "${snap}" if [ "${old_snap}" ] then extra_args="-i ${old_snap}" else extra_args="" fi echo ${REMOTE_ZFS} send $extra_args "${snap}" '|' ${LOCAL_ZFS} recv -F "${POOL_DST}/${zfs_set}" ${REMOTE_ZFS} send $extra_args "${snap}" | ${LOCAL_ZFS} recv -F "${POOL_DST}/${zfs_set}" if [ "${old_snap}" ] then echo ${REMOTE_ZFS} destroy "${old_snap}" ${REMOTE_ZFS} destroy "${old_snap}" fi done kill $ssh_master_pid
Le script est aussi disponible sous forme de gist github.
Sur mes deux machines j'ai un user backup qui peut exécuter zfs avec sudo, l'user backup sur la machine de backup peut accéder en ssh à l'user backup (vous suivez ?) sur la machine à sauvegarder au moyen d'une clé ssh dédiée sans mot de passe.
Le script se lance donc sur la machine de backup (en ayant pris soin de créer tous les sets zfs qu'on va sauvegarder). La première fois il va transférer le set en entier, et les jours suivants il va envoyer de l'incrémental, il faut au minimum un jour entre chaque backup mais rien ne vous empêche de mettre l'heure dans le nom du snapshot.
Commentaires, patchs bienvenus.
PS: Ça fait 6 mois que j'ai pas posté sur ce blog, c'est parce que je travaille et même si je trouve encore un peu de temps pour faire mon propre code c'est moins le cas quand il faut le décrire ici. Par contre je maintient une liste de posts à faire sur ce blog, je rattraperais mon retard bientôt.
]]>J'y décris un peu ce qui se passe dans les trois serveurs que j'administre, pour moi, pour les amis, pour des logiciels libres comme wmfs et pour les causes que je défends avec une association, le cerf de grésigne et un miroir wikileaks.
En modifiant ma map nagios j'ai réussi à faire quelque chose de pas mal pour mieux visualiser la chose :

Ça fait maintenant deux ans que l'aventure a commencée, objectif auto-hébergement et auto-formation à l'administration systèmes. Je dois dire que ça a plutôt bien marché puisque l'infrastructure et mes connaissances n'ont cessés de progresser.
Il faut s'arranger pour que la machine cible puisse être sur le même lan que le serveur pxe. Moi mon laptop est en wifi, donc j'ai mis un cable entre les deux laptop un coup de forward iptables (mais c'est pas le sujet).
# Install dnsmasq
sudo apt-get install dnsmasq
# Creation du repertoire servi par le builtin tftp de dnsmasq
mkdir -p ~/pxe/pxelinux.cfg
cd pxe
# On fetch le kernel, le bootloader pxe et le ramdisk
export SITEFTP=ftp.fr.debian.org:/debian/dists/stable/main/installer-i386/current/images/netboot/debian-installer/i386
wget $SITEFTP/pxelinux.0
wget $SITEFTP/linux
wget $SITEFTP/initrd.gz
# Config du bootloader
cat > pxelinux.cfg/default << EOF
DEFAULT lenny
LABEL lenny
kernel linux
append vga=normal initrd=initrd.gz --
TIMEOUT 0
EOF
# Config dnsmasq
cat > /etc/dnsmasq.conf << EOF
interface=eth0
dhcp-boot=pxelinux.0
enable-tftp
tftp-root=/home/phil/pxe/
EOF
# Reload dnsmasq
sudo /etc/init.d/dnsmasq restart
Configurez iptables pour laisser passer bootpc, dns et tftp et hop install pxe en moins de 5 minutes et avec un seul soft.
]]>Alors je me dis qu'installer FreeBSD sur la partition libre depuis ma Debian testing avec zfs-fuse est possible. Évidement pas de chroot possible, mais y'a même pas besoin. Le plus dur ça a été de démarrer la FreeBSD avec grub2, mais je suis tombé sur la bonne doc. Voilà la manip sans attendre que qemu se lance.
On installe les petits (gros) tools qu'il nous faut (zfs-fuse est dans testing ou sid) :
sudo apt-get install bsdtar zfs-fuse lftp
On récupère une distribution binnaire de FreeBSD (ici 8.1-RELEASE i386)
mkdir ~/freebsd && cd ~/freebsd lftp -c "open ftp://ftp.fr.freebsd.org/pub/FreeBSD/releases/i386/8.1-RELEASE/; mirror base" lftp -c "open ftp://ftp.fr.freebsd.org/pub/FreeBSD/releases/i386/8.1-RELEASE/; mirror kernels" # Et si vous voulez les man lftp -c "open ftp://ftp.fr.freebsd.org/pub/FreeBSD/releases/i386/8.1-RELEASE/; mirror manpages"
Ensuite on crée sa pool zfs sur la partition cible (en forçant la version en 14, version de zfs sur FreeBSD)
sudo zpool create -o version=14 tank /dev/sda3 sudo zfs create tank/root # Ici on peut créer tous les datasets qu'il nous faut
On extract tout ça :
cd ~/freebsd/base && cat base.?? | sudo bsdtar --unlink -xpzf - -C /tank/root cd ~/freebsd/kernels && cat generic.?? | sudo bsdtar --unlink -xpzf - -C /tank/root/boot cd ~/freebsd/manpages && cat manpages.?? | sudo bsdtar --unlink -xpzf - -C /tank/root
Les finitions :
# On utilisera le kernel GENERIC sudo rmdir /tank/root/boot/kernel && sudo mv /tank/root/boot/GENERIC /tank/root/boot/kernel # On copie le cache zpool pour que la freebsd retrouve "tank" sudo cp /var/lib/zfs/zpool.cache /tank/root/boot/zfs/ # On évite un warning sudo touch /tank/root/etc/fstab # On se fait un rc.conf cat << EOF | sudo tee /tank/root/etc/rc.conf hostname="shen.philpep.org" keymap="fr.iso.acc" zfs_enable="YES" EOF # On met mountpoint / pour tank/root (comme ça tank/root/... se montera à partir de /) sudo zpool export tank sudo zpool import -R /mnt tank sudo zpool set mountpoint=/ tank/root
Et maintenant le plus dur, grub2 :
menuentry 'FreeBSD' {
insmod zfs
search -s -l tank
kfreebsd /root@/boot/kernel/kernel
kfreebsd_module_elf /root@/boot/kernel/opensolaris.ko
kfreebsd_module_elf /root@/boot/kernel/zfs.ko
kfreebsd_module /root@/boot/zfs/zpool.cache type=/boot/zfs/zpool.cache
set kFreeBSD.vfs.root.mountfrom=zfs:tank/root
}
Donc avec cette syntaxe on peut charger des modules au boot et écrire dans des variables sysctl (chose qu'on fait dans /boot/loader.conf avec le bootloader de FreeBSD).
Ça juste marche, et je trouve ça bien pratique, surtout qu'on peut se servir du pool zfs depuis Debian, et on peut aussi monter l'ext3 depuis FreeBSD.
EDIT: Je ne peut pas garantir que ce soit très fiable tout ça. Prudence donc. Si vous avez des problèmes au boot de FreeBSD (truc du style "alloc magic is broken") vous pouvez essayer de remplacer search -s -l tank par set root=(hd0,3) (avec la pool en /dev/sda3 chez moi).
top, j'ai remarqué que c'était bind qui prenait le plus de mémoire (loin devant postgresql et php-cgi).
Je me met donc à la recherche d'un serveur dns qui serait plus léger que bind et qui fasse aussi bien dns primaire et secondaire pour mes 5 petites zones et je me souviens avoir vu passer une news à propos de l'intégration récente de nsd dans OpenBSD-Current. Ni une ni deux je dégaine mon apt-get install nsd3 et après quelques jours d'utilisation j'en suis très content.
Ce qu'il faut savoir à propos de nsd :
Que du bon donc, laisser moi vous montrer un bout de config comme c'est simple :
server:
hide-version: yes
# Une config master avec deux slaves
zone:
name: "philpep.org"
zonefile: "master/philpep.org"
notify: 217.70.177.40 NOKEY
provide-xfr: 217.70.177.40 NOKEY
notify: 212.85.155.53 NOKEY
provide-xfr: 212.85.155.53 NOKEY
# Une config slave avec un master
zone:
name: "philpep.org"
zonefile: "slave/philpep.org"
allow-notify: 82.229.137.130 NOKEY
request-xfr: AXFR 82.229.137.130 NOKEY
# Apparemment nsd master ne gère que les transferts de zone AXFR (et pas IXFR)
# Ça n'a pas d'incidence l'un est testé puis l'autre si ça marche pas. Mais vous pouvez éviter
# un message de log en mettant AXFR dans request-xfr dans le cas d'un nsd master et slave.
Les zones sont strictement les mêmes que celles de bind.
Bien sûr il est possible de faire des config bien plus velues avec des clés pour faire des zones dynamiques, du chroot etc, voyez nsd.conf(5)
Il y a aussi un utilitaire bien convi pour controler le serveur : nsdc(8). Avant de démarrer le serveur pour la première fois, il faut compiler les zones avec nsdc rebuild.
J'ai trouvé nsd tellement pratique que je l'ai aussi installé en master sur mon serveur FreeBSD (dns/nsd), bind sert toujours pour le cache,récursion et mes zones en local, mais je vais certainement le remplacer par un djbdns ou un dnsmasq
Le script rc de nsd sur FreeBSD /usr/local/etc/rc.d/nsd est pas terrible, utilisez plutôt nsdc ou attendez que mon patch soit accepté :-)
/usr/src/tools/tools/nanobsd.sh des sources FreeBSD pour construire un système FreeBSD pour l'embarqué.
Dans le processus de création d'un tel système, il peut être utile de tester son système sans utiliser la carte flash. On peut adapter le système en le testant sur NFS et n'écrire l'image finale sur la carte flash que quand on a fini.
Il faut compiler le kernel avec support NFS et NFS comme système de fichier racine
options NFSCLIENT options NFS_ROOT
Avec l'option root-path on spécifie le path du montage nfs au client dhcp.
filename "pxeboot"; next-server 192.168.0.20; # le serveur tftpd option root-path "192.168.0.20:/usr/obj/nanobsd.solo/_.w; # le montage NFS
Le bootloader pxeboot est récuperé via tftp, lui même activé par inetd
tftp dgram udp wait root /usr/libexec/tftpd tftpd -l -s /tftpboot
On compile pxeboot avec un baud de 115200 sur la sortie série.
cd /usr/src/sys/boot make BOOT_PXELDR_ALWAYS_SERIAL=1 BOOT_COMCONSOLE_SPEED=115200 mkdir /tftpboot cp i386/pxeldr/pxeboot /tftpboot
Juste une ligne dans /etc/exports, 192.168.0.1 étant l'IP donnée par mon serveur dhcp à la machine cible.
/usr/obj/nanobsd.solo/_.w -alldirs -maproot=root 192.168.0.1
On active tout ça dans /etc/rc.conf
inetd_enable="YES" nfs_server_enable="YES" rpcbind_enable="YES" mountd_flags="-r" dhcpd_enable="YES"
Et on démarre les services :
/usr/local/etc/rc.d/isc-dhcpd start /etc/rc.d/inetd start /etc/rc.d/rpcbind start /etc/rc.d/nfsd start
Maintenant il faut modifier le système généré par NanoBSD car il s'attend à avoir la carte flash comme système de fichier.
J'ai juste crée une fonction dans ma config nanobsd (fonction à enlever quand on crée les images disques bien entendu) :
post_nfsroot {
rm ${NANO_WORLDDIR}/etc/fstab
rm ${NANO_WORLDDIR}/conf/default/etc/remount
echo "" > ${NANO_WORLDDIR}/conf/base/etc/fstab
}
late_customize_cmd post_nfsroot
Voilà, n'oubliez pas l'option -i pour gagner le temps de construction des images disques et bon debug :)