lundi, mars 21, 2011

Serveur NFS v4 avec FreeBSD

NFS v4 possède quelques avantages bien sympa: En plus de la possibilité de s'appuyer sur kerberos, il utilise un seul port TCP (très pratique lorsqu'il se trouve derrière un firewall).
Cet exemple montre sa mise en place, et les problèmes rencontrés pour un fonctionnement sans l'authentification kerberos avec FreeBSD (8.1 et 8.2).
On commence par lire nfsv4(4), qui nous indique que pour activer le serveur NFS v4 il faut:

1. Ajouter 3 lignes dans le /etc/rc.conf:
nfs_server_enable="YES"
nfsv4_server_enable="YES"
nfsuserd_enable="YES"

2. Créer un fichier nfs-stablerestart (en root):

install -o root -g wheel -m 600 /dev/null /var/db/nfs-stablerestart

Maintenant on passe à la lecture du exports(5) qui, pour NFS v4 est un peu plus complexe.
Mon but est de partager le dossier /home/olivier en lecture seule, le fichier exports se résume donc à 2 lignes:
V4: /
/home/olivier -ro 127.0.0.1

Puis je lance les services:
/etc/rc.d/nfsd start
Starting mountd.
Starting nfsd.

/etc/rc.d/nfsuserd start
Starting nfsuserd.


Aucun message d'erreur, ça semble bon, maintenant affichons la liste des exports:
showmount -e
Exports list on localhost:

Rien :-(
Et aucun message dans les logs indiquant une erreur dans le fichier exports.

On va quand même essayer:
mount -o nfsv4 localhost:/home/olivier /mnt/
nfsv4 err=10029
mount_nfs: /mnt, : Input/output error

Le message d'erreur le plus intéressant ici est le «nfsv4 err=10029», je n'ai pas trouvé grand chose sur le net concernant ce message, sauf une petite note dans le draft nfsv4:

NFS4ERR_SYMLINK (Error Code 10029)
The current filehandle designates a symbolic link when the current operation does not allow a symbolic link as the target.

Je n'avais pas fait attention à un détail du exports(5):
«The pathnames must not have any symbolic links in them»

Et sur FreeBSD le dossier /home est un lien symbolique qui pointe sur /usr/home.
On corrige donc le fichier /etc/exports:
V4: /
/usr/home/olivier -ro 127.0.0.1

Et on demande à mountd de charger ce nouveau fichier:
/etc/rc.d/mountd reload

Vérifions si c'est mieux 
showmount -e
Exports list on localhost:
/usr/home/olivier                  127.0.0.1

Cool, maintenant je vais pouvoir le monter (en localhost pour débuter):
mount -o nfsv4 localhost:/usr/home/olivier /mnt/
mount | grep olivier
localhost:/usr/home/olivier on /mnt (newnfs)


Parfait, maintenant on liste les fichiers sur du dossier /mnt
ls /mnt/
ls: /mnt/: Input/output error

Bon, ça ne fonctionne toujours pas :-(
Qu'est que ce bordel ?
Voici la commande qui donne un indice sur ce problème:
netstat -a | grep nfsd
tcp6       0      0 localhost.nfsd         localhost.18082        ESTABLISHED
tcp6       0      0 localhost.18082        localhost.nfsd         ESTABLISHED
tcp6       0      0 localhost.621          localhost.nfsd         TIME_WAIT
tcp6       0      0 *.nfsd                 *.*                    LISTEN
tcp4       0      0 *.nfsd                 *.*                    LISTEN
udp6       0      0 *.nfsd                 *.*
udp4       0      0 *.nfsd                 *.*

Et oui, je n'ai autorisé que l'IP 127.0.0.1 à accéder à mon partage dans mon /etc/exports, et la commande mount localhost a utilisé l'IPv6 localhost (::1) pour s'y connecter.
On va donc forcer un montage en utilisant la pile IPv4:
umount /mnt/
mount -t nfs -o nfsv4 127.0.0.1:/usr/home/olivier /mnt/
ls /mnt
.complete                           .mailrc                                
.cshrc                              .profile                                   
.history                            .rhosts                              
.lesshst                            .shrc                                                    
.lftp                               .ssh                                
.login                              .viminfo                            
.login_conf                         .vimrc                              

Enfin, cela fonctionne en local :-)
Comme je veux le monter aussi en IPv6, j'ajoute donc ::1 à ma liste d'IP autorisées:
V4: /
/usr/home/olivier -ro 127.0.0.1 ::1

Maintenant que le montage local IPv4/IPv6 fonctionne, on édite le /etc/exports pour y autoriser les subnets du LAN:
V4: /

/usr/home/olivier -ro -network 2a01:e35:aaaa:aaaa::/64
/usr/home/olivier -ro -network 192.168.100.0

Puis on recharge mountd et vérifie que le fichier exports a été correctement interprété:
/etc/rc.d/mountd reload
showmount -e
Exports list on localhost:
/usr/home/olivier                  2a01:e35:aaaa:aaaa:: 192.168.100.0

Note concernant un client sous Linux, la syntaxe de la commande mount est la suivante:
mount -t nfs4 server-name:/usr/home/olivier/ /mnt

Donc, à noter pour la configuration NFS v4:
  1. Ne pas oublier de créer le fichier /var/db/nfs-stablerestart
  2. Ne pas déclarer de chemin utilisant des liens symboliques dans le fichier exports
  3. Si showmount -e n'indique rien suite au rechargement de mountd, ce n'est pas la peine de continuer
  4. Attention aux doubles piles IPv4/IPv6, n'oubliez pas de déclarer aussi les IPv6 dans votre exports
  5. Ce n'est pas parce que le montage s'effectue que vous êtes autorisé

dimanche, mars 13, 2011

FreeBSD packages generator

  
Update (8 april 2011): There is a best method detailled here (in french)

Using up-to-date ports on my old workstations became more and more painful (more than 8 hours for compiling the latest LibreOffice).
Then I've decided to use my brand new server (used for generating BSD Router Project images and running BSDRP routing labs using virtualbox) as a FreeBSD packages generator.
But I've faced to a problem with the "make package-recursive" command on FreeBSD:
The port needs to be installed before generating the package! And I didn't want to install useless programs  (xorg, hal, etc…) on my server.
Then I've wrote small ugly script that:

  1. Generate a full new freebsd in a working dir (downloading FreeBSD base, src and lib32 sets).
  2. Update the local port tree
  3. Launch a chrooted portmaster into the working dir for generating the packages.

This script, package_gen.sh, is to be use like that:

Package generator usage:
./package_gen.sh COMMAND [familly/port-name] [build-option]
Where COMMAND can be:
 generate [familly/port-name] [build-option]
 upgrade [port-name] [build-option]
 replace familly/port-name familly/port-name
 delete [familly/port-name]
examples:
./package_gen.sh generate sysutils/tmux                         : Generate tmux package
./package_gen.sh generate editors/vim-lite -DWITHOUT_X11        : Generate vim-lite package without X11 stuffs
./package_gen.sh generate editors/libreoffice LOCALIZED_LANG=fr : Generate french libreoffice
./package_gen.sh upgrade                                        : Upgrade all packages previously generated
./package_gen.sh delete editors/vim-lite                        : Delete vim-lite
 


All generated packages are in /usr/ports/packages.

Once generated or upgraded, I upload them onto a web server using a small lftp script (-f option):


  set ftp:list-options -a
  set cmd:fail-exit true
  debug -o /home/USER/lftp_debug.log 3
  open -p 21 LOGIN:PASS@ftpperso.free.fr
  cd /packages/8.2/amd64/Latest
  lcd /usr/ports/packages/Latest
  mirror -eRL --only-newer --parallel=2 --verbose=4
  cd /packages/8.2/amd64/All
  lcd /usr/ports/packages/All
  mirror -eRL --only-newer --parallel=2 --verbose=4
 quit
 


This lftp script replaces symbolic links found in /usr/ports/packages by the real file.
Now, from my workstations, I can install up-to-date ported software with this command:

env PACKAGESITE=http://gugus69.free.fr/packages/8.2/amd64/Latest/ pkg_add -r openjdk6

You can use this package repository freely. I will try to kept it online (if my ISP accept this uses) and up-to-date.
But here are some information about theses packages:
  • FreeBSD amd64 8.2 only
  • www/firefox-i8n include only french language pack
  • emulators/qemu with kqemu support and GNS3 patch
  • java/jdk16 is compiled with IPv6 enabled