lalahop
Categorie: Administration système

Tout est dans le titre : l'installation de cups-pdf avec apt-get sous Debian Wheezy se bloque/gèle/freeze/hang sur la ligne "Reloading Common Unix Printing System: cupsd.". Le même problème peut survenir lors de la désinstallation de cups-pdf.

Un ps aux | grep dpkg permet de constater qu'il y a un processus "/bin/sh /var/lib/dpkg/info/cups-pdf.postinst" qui tourne. Comme par hasard, quand on kill se processus, l'installation continue. Certes elle échoue mais elle continue.

En décortiquant ce script, on observe l'utilisation de lpstat. OK, on se documente sur le bouzin et on essaye nous même, en ligne de commande, "lpstat -h localhost -r" : aucun retour ...

Hum ... que donne "lpstat -h 127.0.0.1 -r" ? "scheduler is running" ...

Hum ... problème de résolution des noms locaux ... On vérifie le contenu de /etc/hosts : il contient bien une association localhost <=> 127.0.0.1. Il contient évidement le même type d'association pour IPv6 ...

Hum ... donc s'il ne résout pas les noms locaux, un "lpstat -h nom_de_la_machine -r" va échouer ... Même pas ... Donc c'est bien un soucis interne à lpstat.

La solution est évidente (mais pas forcement propre, je n'ai aucun avis sur la question) : on modifie /var/lib/dpkg/info/cups-pdf.postinst pour remplacer toutes les occurrences de localhost (même celles qui ne sont pas utilisées comme paramètre d'un lpstat).

Tant qu'à faire, pour s'éviter des problèmes lors de la déinstallation/suppression de cups-pdf, on modifie les scripts /var/lib/dpkg/info/cups-pdf.postprerm et /var/lib/dpkg/info/cups-pdf.postpostrm de la même manière.

Ensuite si ce n'est pas déjà fait, on kill le processus /bin/sh /var/lib/dpkg/info/cups-pdf.* qui bloque l'installation/désinstallation de cups-pdf.

Enfin, on lance juste dpkg --configure -a et l'installation/déinstallation de cups-pdf se termine sans problèmes.

Piwik : importer depuis les logs

Si vous avez la main sur votre serveur, Piwik met à votre disposition un script Python qui vous permet d'importer les statistiques (visites, pages vues, ...) depuis les logs de votre httpd (support Apache, Nginx, IIS et tous les autres vi vous spécifiez les regex qui vont bien). Piwik agit comme Webalizer AWStats.

Table des matières

Avantages/Inconvénients

Quels sont les avantages par rapport au traqueur JS ?

  • L'information a déjà été produite par le démon http, pourquoi la produire à nouveau avec le traqueur JS ?
  • Vos visiteurs gagnent en temps de chargement (deux requêtes de moins).
  • Vous libérez votre serveur dans les moments de forte charge (quand il y a les visites quoi) et vous calculez vos stats dans un moment de faible charge (typiquement la nuit mais ce n'est pas toujours le cas).

Quels sont les inconvénients par rapport au traqueur JS ?

  • La doc nous dit plus complexe à mettre en place ... ça se discute.
  • Avec le traqueur JS, on ne comptabilise que les visites provenant d'humains + des quelques bots qui interprètent le Javascript. Avec les logs, on comptabilise tout. SI votre site est scanné par les bots, vos stats vont perdre énormément de leur fiabilité. C'est clairement le point noir de l'analyse de logs. Même sur un tout petit blog comme celui-ci les stats perdent de leur valeur car des robots scan en continue et tentent de poster des commentaires ...

Faire tourner les logs

Pourquoi

Il est nécessaire de faire tourner les logs de votre httpd avant de lancer le script d'import sur celui-ci car, dans le cas contraire, les visites seront dédoublées par Piwik. Comme un exemple vaut mieux qu'un long discours :
Exemple de statistique dédoublée

Notez le "2x" alors que la page n'a en réalité été visité qu'une seule fois dans cet exemple.

De plus, si vous ne faîtes pas tourner les logs, vous aurez une quantité toujours plus importante à parser : les logs de la veille + les logs d'aujourd'hui ...

Comment

Pour faire tourner les logs, nous allons utiliser logrotate. Pour cela, il suffit de créer un fichier /etc/logrotate.d/apache (vérifiez qu'il n'existe pas déjà, vous aurez juste à adapter weekly/monthly => daily) avec le contenu suivant :

/var/log/apache2/GGS/*.log {
        daily
        missingok
        rotate 365
        compress
        delaycompress
        ifempty
        create 640 root adm
        sharedscripts
	olddir /var/log/archives/apache2/GGS
        postrotate
                /usr/sbin/apache2ctl graceful > /dev/null
        endscript
}

Ainsi, dans cet exemple, les logs situés dans le dossier /var/log/apache2/GGS (pensez à adapter) seront tournés tous les jours, stockés dans /var/log/archives/apache2/GGS pendant 365 jours sous forme compressée à partir de la deuxième rotation.

Configurer l'import

Il suffit de créer un fichier dans /etc/cron/daily.d/ qui fera, ainsi, appel au script d'import une fois par jour :

#!/bin/sh
 
/usr/bin/python2.6 /var/www/piwik/misc/log-analytics/import_logs.py --url="http://stats.guiguishow.info" --idsite=3 `date +/var/log/archives/apache2/GGS/access.log-\%Y\%m\%d`

Les deux paramètres obligatoires sont url et idsite. Le premier permet d'indiquer sur quel domaine se trouve Piwik (pensez à utiliser https ou toute autre méthode de sécurisation du canal si les deux domaines ne sont pas sur la même machine). L'autre permet d'indiquer l'id du site concerné. Ce dernier peut-être récupéré dans l'interface de Piwik.

Vient ensuite le nom du log à parser. Chaque jour, logrotate placera, dans /var/log/archives/apache2/GGS, le log de la veille sous le nom access.log-date_du_jour.

Concernant le nom que vous donnerez à ce script, prenez en considération le fait que c'est run-parts qui est chargé, par cron, de l'exécution des scripts. Or, comme l'explique son man, run-parts lance les scripts par ordre lexicographique. Il faut que le script logrotate passe avant notre script pour produire le log que nous allons parser. Donc il faut donner un nom "plus grand" à notre script. Dans mon cas : piwik-import.

ÉDIT du 26/11/2012 à 04h45 : Comme le signale Antoine dans les commentaires, créer une deuxième entrée dans cron n'est pas la meilleure méthode. En effet, logrotate permet de lancer une ou plusieurs commandes après la rotation des logs avec la directive "postrotate". D'ailleurs, je m'en sert pour relancer Apache. C'est donc dans cette directive qu'il fait sens d'ajouter la commande de l'import piwik (/usr/bin/python2.6 /var/www/piwik/misc/log-analytics/import_logs.py ...). Fin de l'édit

Règler les problèmes

Log SSL : Fatal error: Cannot guess the logs format.

En effet, alors que je n'ai pas changé de format de log dans ma config Apache entre mon virtualhost http et mon virtualhost https, Piwik me crache cette erreur.

Pour résoudre ce problème, il suffit de forcer le format de log avec le paramètre "--log-format-name=ncsa_extended".

Les FAI n'apparaissent pas, ils sont tous marqués "IP"

D'après la documentation, les FAI sont déduis en effectuant une requête DNS inversée sur l'adresse IP du visiteur. Néanmoins, comme cela est consommateur de ressource, le script d'import désactive cette fonction par défaut.

Pour résoudre ce problème, il suffit d'activer la fonctionnalité avec le paramètre : "--enable-reverse-dns".

Bien entendu, et je parle surtout pour un chroot, il faut qu'Apache ait accès à une bibliothèque de résolution DNS et qu'il y ait un fichier resolv.conf dans le chroot.

La géolocalisation ne marche pas : le pays du visiteur n'apparaît pas !

La doc répond déjà à ça. Avec le traqueur JS, Piwik détermine la localisation grâce au header "Accept-Language" envoyé par votre navigateur. Avec les logs, cette information n'est plus disponible.

Pour résoudre le problème, il faut installer l'extension GeoIP de Piwik ainsi que l'extension PECL GeoIP (vous avez le choix mais cette extension est la plus adaptée pour l'analyse de log, selon la documentation).

Installation de l'extension PECL GeoIP

Pour l'installer sous Debian :

apt-get install php5-geoip

On modifie ensuite la configuration de PHP (/etc/php5/apache2/php.ini) pour y ajouter (on remplacera le chemin ...) :

geoip.custom_directory=/path/to/piwik/misc

On récupère la base de donnée de correspondance entre une IP et sa géolocalisation, on la décompresse et on la range où il faut sous le nom qu'il faut :

wget -c http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz
gunzip GeoLiteCity.dat.gz
mv GeoLiteCity.dat.gz /path/to/piwik/misc/GeoIPCity.dat
Installation du plugin GeoIP de Piwik

Attention, à partir de la version 1,9, ce plugin est inclu d'office, vous n'avez pas à l'installer ni à l'activer. Vous devez juste vérifier que c'est bien l'extension PECL qui est utilisée.

On télécharge, décompresse et on range au bon endroit :

wget -c http://dev.piwik.org/trac/attachment/ticket/45/GeoIP.zip?format=raw -O GeoIP.zip
unzip GeoIP.zip
cp -R GeoIP/ /path/to/piwik/misc/

Il ne reste plus qu'à aller dans l'interface de Piwik, rubrique Paramètres, rubrique Plugins et à activer Geolocation.

Il faut ensuite aller dans l'onglet Geolocation qui vient d'apparaître et vérifier que c'est bien l'extension PECL qui est utilisée.

Voilà, pour les prochaines visites, la géolocalisation fonctionnera.

Si vous voulez que les anciennes visites soient reconsidérées, il faut utiliser le script geoipUpdateRows.php en ligne de commande (php geoipUpdateRows.php). À partir de la version 1.9, il se trouve dans /path/to/piwik/misc/others/geoipUpdateRows.php . Si vous avez installé le plugin vous-même, il se trouve dans /path/to/piwik/plugins/GeoIP/geoipUpdateRows.php .

Il faudra ensuite vous connecter à votre base de données et supprimer toutes les tables commençant par "piwik_archive_". En actualisant l'interface de Piwik, vous devrez voir les pays de vos visiteurs.

Bien entendu, et je parle surtout pour un chroot, il faut qu'Apache ait accès à une bibliothèque de résolution DNS et qu'il y ait un fichier resolv.conf dans le chroot.

J'utilise WordPress et il y a plein de statistiques inutiles !

En effet, il y a des requêtes internes à WordPress (wp-cron), les requêtes liées à l'administration (wp-admin), ... Il est possible d'exclure des user-agents (--useragent-exclude) et des chemins (--exclude-path / --exclude-path-from) avec le script d'import.

Pour éliminer les requêtes concernant wp-cron et l'administration, quelque chose comme cela suffira : "--exclude-path=/wp-[ac]*"

J'utilise WordPress et je vois encore les requêtes concernant le flux RSS

C'est l'inconvénient du parsing de log : on voit tout. On peut néanmoins résoudre le problème mais cela se fait en deux temps.

Dans un premier temps, on filtre */feed*, ce qui permettra d'exclure les urls comme :

  • www.guiguishow.info/feed/
  • www.guiguishow.info/feed
  • www.guiguishow.info/2012/11/03/piwik-importer-depuis-les-logs/feed/ (très utilisé par les bots spammeurs pour vérifier si leur commentaire est posté).

Pour ce faire : "--exclude-path=*/feed*"

Vous allez vous apercevoir qu'il reste encore des visites avec comme chemin "?feed=rss2". Vous allez tenter de les exclure avec une regex mais cela ne fonctionnera pas.

Pour essayer de comprendre, j'ai étudié le code source et j'ai placé des affichages sauvages un peu partout pour voir les chemins traités à chaque étape. J'ai trouvé que ces URLs ne sont jamais passées dans le filtre "exclude". Même en fin de processus, au moment où les hits sont mis dans la queue finale avant envoi, elles n'apparaissent pas (hit.path n'est jamais égal à "?feed=rss2"). En revanche, le referrer de certaines requêtes correspondent avec la chaîne recherchée.

J'en deduis que, indépendamment du script d'import, si Piwik voit une url de votre site en referrer, il l'ajoute en hit même si aucune requpete n'y correspond. Ça parait logique : si cette url apparaît en referrer, alors le visiteur a consulté cette url auparavant. Bien sûr, ce raisonnement se heurte aux referrer modifiés volontairement.

La seule idée qu'il me vient est la suivante : par défaut, c'est-à-dire si vous n'avez pas activé l'option "--enable-http-redirects", les redirections HTTP (301, 302, autres 3xx sauf 304) sont exclues des logs. Nous allons donc rediriger /?feed=rss2 vers /feed/ que nous avons déjà exclu. La redirection ?feed=rss2 -> /feed/ sera ignorée et la consultation de /feed/ qui suivra sera tout aussi ignorée. Ainsi ces hits n'apparaîtront pas dans vos stats et votre visiteur sera redirigé de manière transparente.

Cela peut se faire avec un rewrite mais j'ai choisi de le faire avec la directive RedirectMatch disponible dans le mod alias. Il suffit de spécifier ça dans la configuration d'Apache :

RedirectMatch ^/?feed=rss2$ /feed/

Mais je vois encore mes visites sur les pages "normales"

Là encore, c'est l'inconvénient du parsing de log. Le cookie d'exclusion ne peut pas être utilisé puisqu'il n'apparaît pas dans les logs. L'exclusion de votre IP dans l'interface de Piwik ne fonctionne pas avec le script d'impot.

Si vous avez une IP fixe, on peut toujours imaginer un filtrage avec "grep -v" avant de passer le fichier de log ainsi traité au script d'import.

On peut imaginer une exclusion basée sur un user agent (--useragent-exclude) spécifique qu'une extension Firefox vous ferez prendre uniquement sur votre site.

Bref, on peut imaginer plein de choses mais il faut voir si c'est réalisable et si ce n'est pas utiliser un bazooka pour écraser une mouche 😉 .

Sources

Utiliser LXC sur un Kimsufi

Lorsque l'on veut compartimenter ses services sans trop d'impact sur les performances, on pense à la virtualisation par conteneurs. Souvent, on pense OpenVZ.

On peut se demander quelles différences existent entre OpenVZ et LXC. Comme je ne suis pas un expert, je me contente de reprendre les réponses que l'on peut lire n'importe où sur le web :

  • LXC n'a pas besoin d'un noyau spécial contrairement à OpenVZ.
  • LXC aurait une gestion du réseau beaucoup plus simple qu'OpenVZ.
  • OpenVZ a été supprimé des packages officiels Debian.

Je vous propose d'installer et d'utiliser LXC sur un Kimsufi d'OVH équipé d'une Debian stable 64 bits. Le sujet ayant été abordé de nombreuses fois, ce billet ne sera finalement qu'une compilation des différentes sources avec une correction de ce qui ne marche pas chez moi.

Table des matières

Installer LXC

Pour éviter quelques problèmes, nous allons installer la version 0.8 présente dans les backports pour Squeeze.

Pour utiliser les backports, il faut ajouter cette ligne à votre fichier /etc/apt/sources.list :

deb http://backports.debian.org/debian-backports squeeze-backports main

Installation :

apt-get update && apt-get -t squeeze-backports install lxc

Dans l'interface de configuration semi-graphique, laissez le répertoire proposé.

Compiler un noyau utilisant les cgroups + grsec

Le kernel compilé par OVH n'a pas le support des cgroups qui est requis par LXC.

Je pense qu'installer un noyau Debian standard (apt-get -t squeeze-backports install linux-image-amd64 linux-headers-amd64) doit résoudre le problème sans rien casser.

Mais ici nous voulons activer les cgroups et conserver grsec qui est activé sur les noyaux OVH.

Afin de réduire le temps de compilation, il faut envisager de compiler sur votre desktop, pas sur votre KS. Comptez 1h sur un KS 2G contre 15 minutes sur une machine récente ...

On vérifie que l'on a bien tous les outils nécessaires à la compilation :

apt-get install make gcc libncurses5-dev lzma dpkg-dev

On se prépare un dossier de travail :

mkdir /usr/src/kernel && cd /usr/src/kernel

On récupère les sources du dernier 3.2 :

wget -c https://www.kernel.org/pub/linux/kernel/v3.0/linux-3.2.31.tar.bz2

On les décompresse :

tar jxf linux-3.2.31.tar.bz2

On récupère le dernier patch grsec :

wget -c https://grsecurity.net/stable/grsecurity-2.9.1-3.2.31-201210111928.patch

On applique le patch grsec :

cd linux-3.2.31 && patch -p1 < ../grsecurity-2.9.1-3.2.31-201210111928.patch

On récupère la config OVH + grsec :

wget "https://www.dguillem.fr/dokuwiki/_export/code/public/ovh/kernel-3.2.13-grs-config?codeblock=0" -O ".config"

ÉDIT du 17/02/2014 à 11h10 : L'url ci-dessus est cassée. Je mets mon .config à votre disposition (3.2.45, amd64, grsec et les options nécessaires à LXC déjà activées, issu du lien ci-dessus) :

wget "http://www.guiguishow.info/wp-content/uploads/2014/02/config-linux-3.2.45-amd64-ovh-grsec-lxc" -O ".config"

Il marche bien avec la version 3.2.54 aussi ... normal, c'est du 3.2.X.
Fin de l'édit

ÉDIT du 24/05/2014 à 14h32 : Toujours valide pour la version 3.2.58. Il suffit de laisser les réponses par défaut pour les nouveaux choix. Fin de l'édit

ÉDIT du 23/07/2015 à 15h50 : Toujours valide pour la version 3.2.69. Il suffit de laisser les réponses par défaut pour les nouveaux choix. Mais pour ceux qui veulent directement le bon fichier :

wget "http://www.guiguishow.info/wp-content/uploads/2014/02/config-linux-3.2.69-amd64-ovh-grsec-lxc" -O ".config"

Fin de l'édit

On configure notre noyau :

make menuconfig

Dans l'interface semi-graphique, voici les options à activer en supplément :

General setup -> Control Group Support -> Memory Resource Controller Swap Extension
General setup -> Control Group Support -> Memory Resource Controller Swap Extension enabled by default
General setup -> Control Group Support -> Enable perf_event per-cpu per-conteneur group (cgroup) monitoring
General setup -> Control Group Support -> Group CPU scheduler -> CPU bandwidth provisioning for FAIR_GROUP_SCHED
General setup -> Control Group Support -> Group CPU scheduler -> Group scheduling for SCHED_RR/FIFO

General setup -> Namespace support -> User namespace
General setup -> Namespace support -> PID Namespaces
 
Networking support -> Networking options -> GVRP (GARP VLAN Registration Protocol) support

Device Drivers -> Network device support -> MAC-VLAN support
Device Drivers -> Network device support -> MAC-VLAN based tap driver
Device Drivers -> Network device support -> Virtual ethernet pair device
 
Device Drivers -> Character devices -> Support multiple instances of devpts

Security options -> Grsecurity -> Customize Configuration -> Sysctl Support -> Sysctl support
Security options -> Grsecurity -> Customize Configuration -> Sysctl Support -> Turn on features by default

Vous pouvez également donner un suffixe au nom de votre kernel afin de l'identifier. Cela se fait dans General Setup -> Local version - append to kernel release

lxc-checkconfig permet de vérifier que l'on a bien activé toutes les options requises par LXC :

CONFIG=/usr/src/kernel/linux-3.2.31/.config lxc-checkconfig

Normalement, vous devriez obtenir un "enabled" à chaque ligne. "File capabilities" peut être marqué comme "missing", ce n'est pas bloquant.

On lance la compilation :

make deb-pkg

Si vous compilez sur votre desktop, vous pouvez profiter du multithreading (sous Debian, il vous faudra alors le package supplémentaire gcc-4.7-plugin-dev) :

make deb-pkg -j <nombre de coeurs + 1>

En version automatique (et avec du bashisme inside ) :

make deb-pkg -j $((`nproc`+1))

Pour nproc, voir ici.

Une fois la compilation terminée, vous pouvez installer votre nouveau noyau :

cd .. && dpkg -i linux-image-3.2.31-grsec_3.2.31-grsec-1_amd64.deb linux-headers-3.2.31-grsec_3.2.31-grsec-1_amd64.deb

Note : si vous avez compilez sur votre desktop, pensez à transférer les deux paquets Debian sur votre KS via SCP ...

Normalement, votre kernel se placera en premier dans le menu de boot et donc, votre KS démarrera automatiquement sur votre kernel. Néanmoins, pour en être sûr, il suffit de désactiver l'entrée du menu boot créée pour le kernel OVH :

mv /etc/grub.d/06_OVHkernel . && update-grub2

Il ne vous reste plus qu'à faire démarrer votre KS sur votre kernel ...

reboot

Partitionner

Le but du jeu est de se créer une partition dédiée à nos conteneurs. Pour cela, nous allons prendre de l'espace sur la partition /home. Par la même occasion, nous allons augmenter la taille du swap.

Chacun ses goûts mais moi j'utilise parted :

apt-get install parted

Lister les partitions :

parted
(parted) print

Normalement, vous avez une première partition primaire en ext4 sur lequel se trouve Debian. La deuxième partition (la plus grande), est montée sur /home. La dernière, de 512Mo est le swap. Si ce n'est pas le cas, réfléchissez avant de continuer et remplacez mes commandes par les commandes adaptées à votre situation !

Nous allons :

  • Écraser la partition 2 pour en faire deux partitions : une pour stocker les conteneur, l'autre pour vos données.
  • Détruire le swap pour le recréer avec une taille de 1Go.

Suppression des deux partitions :

rm 2
rm 3

Création de la partition pour les conteneurs (environ 100Go) :

mkpart
primary
ext2 (entrée)
21,5GB
125GB

Création de la partition pour les données (le reste moins 1Go) :

mkpart
primary
ext2 (entrée)
125GB
999GB

Création du swap (-1 = tout l'espace restant)

mkpart
primary
ext2 (entrée)
999GB
-1

Le travail est finit, on quitte parted.

q

Formatage des partitions :

mkfs.ext4 -L CONT /dev/sda2
mkfs.ext4 -L DATA /dev/sda3
mkswap /dev/sda4

Nous allons corriger /etc/fstab :

/dev/sda2	/home			ext4	defaults,relatime		0	2

devient :

/dev/sda3	/home			ext4	defaults,relatime		0	2

Utilisation de LVM

Chaque système de fichiers de chacun de nos conteneurs LXC sera stocké dans un volume logique indépendant.

Création du volume physique :

pvcreate /dev/sda2

Création du groupe de volumes (appelez-le comme vous voulez, dans le cadre de ce billet, ça sera CONT ...) :

vgcreate CONT /dev/sda2

Création d'un premier volume logique destiné à notre premier conteneur (appelez-le comme vous voulez, dans le cadre de ce billet, ça sera CONT1 et adaptez la taille, pour moi, ça sera 25Go ...) :

lvcreate -n CONT1 -L 25G CONT

Formatage de ce premier volume logique :

mkfs.ext4 -L CONT1 /dev/CONT/CONT1

Préparation de LXC

Installation du nécessaire :

apt-get install bridge-utils debootstrap libvirt-bin

Ajout de deux lignes au fstab :

cgroup		/sys/fs/cgroup 		cgroup	defaults			0	0
/dev/CONT/CONT1	/var/lib/lxc/CONT1	ext4	defaults			0	2

Montage :

mkdir /var/lib/lxc/CONT1 && mount /dev/CONT/CONT1
mount cgroup

Lors de la création d'un conteneur, LXC vérifie que le dossier portant le nom de la machine n'existe pas. Or, comme nous voulons un volume logique/conteneur, nous sommes obligé de monter le volume logique avant la création du conteneur et donc ... le répertoire existe. De manière plus claire : LXC n'appréciera pas l'existence de /var/lib/lxc/CONT1. Il faut bypasser ce comportement en modifiant le fichier /usr/bin/lxc-create. Il faut répérer le code suivant :

if [ -d "$lxc_path/$lxc_name" ]; then
    echo "'$lxc_name' already exists"
    exit 1
fi

Et commenter, au minimum, la ligne contenant le exit.

Création d'un premier conteneur LXC

D'abord, désactivons temporairement certaines fonctions de grsec :

echo 0 > /proc/sys/kernel/grsecurity/chroot_deny_mount
echo 0 > /proc/sys/kernel/grsecurity/chroot_caps

Si vous ne le faites pas, alors, vous aurez une erreur de ce type lors du lxc-create :

W: Failure trying to run: chroot /var/cache/lxc/debian/squeeze_amd64.partial mount -t proc proc /proc

Le fichier /var/cache/lxc/debian/squeeze_amd64.partial/debootstrap/debootstrap.log contiendra une erreur de ce type :

mount: permission denied

Et dmesg vous retournera un message du type "use of CAP_SYS_ADMIN in chroot denied"

Création du conteneur :

lxc-create -n CONT1 -t debian

Vous voici dans une interface smi-graphique.
Preseed file : laissez vide
Debian Squeeze
64 bits PC

Archives : laissez comme ça
Miroir : ftp://mirror.ovh.net/debian/ (autant prendre le plus proche 😀 )
Laissez les autres miroires tels quels
Choisissez uniquement la distribution main
Packages : iputils-ping traceroute iptables wget nano rsyslog bash-completion (cela permet d'installer d'office les commandes ping/traceroute/iptables/wget/nano, d'avoir un rsyslogd comme démon de logging et d'activer un minimum d'autocompletion)
Mot de passe root : à choisir avec attention 😉

On n'oublie pas de réactiver les fonctionnalités de grsec :

echo 1 > /proc/sys/kernel/grsecurity/chroot_deny_mount
echo 1 > /proc/sys/kernel/grsecurity/chroot_caps

Configuration réseau

Pour cette partie, je vous renvoie sur un autre tuto dans lequel les différentes possibilités sont bien expliquées : Linux conteneurs sur KIMSUFI OVH.

Prêt pour le lancement

Il faut créer les fichiers spéciaux correspondant à chaque console virtuelle :

mknod -m 666 /var/lib/lxc/CONT1/rootfs/dev/tty1 c 4 1
mknod -m 666 /var/lib/lxc/CONT1/rootfs/dev/tty2 c 4 2
mknod -m 666 /var/lib/lxc/CONT1/rootfs/dev/tty3 c 4 3
mknod -m 666 /var/lib/lxc/CONT1/rootfs/dev/tty4 c 4 4
mknod -m 666 /var/lib/lxc/CONT1/rootfs/dev/tty5 c 4 5
mknod -m 666 /var/lib/lxc/CONT1/rootfs/dev/tty6 c 4 6

Si vous ne le faîtes pas, vous n'aurez pas de prompt avec lxc-console.

Pour que SSH fonctionne, il faut générer les clés du serveur :

ssh-keygen -t rsa -f /var/lib/lxc/CONT1/rootfs/etc/ssh/ssh_host_rsa_key
ssh-keygen -t dsa -f /var/lib/lxc/CONT1/rootfs/etc/ssh/ssh_host_dsa_key

Pour que le conteneur utilise le fuseau horaire local :

echo "Europe/Paris" > /var/lib/lxc/CONT1/rootfs/etc/timezone
cp /var/lib/lxc/CONT1/rootfs/usr/share/zoneinfo/Europe/Paris /var/lib/lxc/CONT1/rootfs/etc/localtime

Lancement

lxc-start -n CONT1 -d

Obtenir une console :

lxc-console -n CONT1

Éteindre le conteneur en douceur (la manière brutale se fait avec lxc-stop) :

lxc-halt -n CONT1

Connaître l'état du conteneur

lxc-info -n CONT1

Démarrage automatique d'un (ou plusieurs) conteneur(s)

Pour démarrer un ou plusieurs conteneur au boot, il suffit simplement de placer un lien symbolique pointant vers le fichier de configuration du(des) conteneur(s) à démarrer dans le dossier /var/lib/lxc/auto. Exemple :

ln -s /var/lib/lxc/CONT1/config /etc/lxc/auto/CONT1.conf

Et pour chaque nouveau conteneur ?

Pour chaque nouveau conteneur, il suffira de créer son volume logique, de le formater, de le monter et d'ajouter la ligne "kivabien" dans /etc/fstab.

Il faudra désactiver les 2 fonctionnalités de grsec, créer le conteneur (lxcreate quoi) et réactiver les fonctionnalités de grsec.

Il faudra configurer l'accès au réseau du conteneur puis il faudra faire les modifications pré-lancement (création des tty, génération des clés SSH, ...).

Tout cela doit s'automatiser facilement avec un script mais je n'ai pas étudié la question.

Note

Normalement, depuis sa version 0.8, LXC est capable d'automatiser la création et l'utilisation de volumes logiques. Ainsi, une commande comme celle-ci "lxc-create -t debian -n test -B lvm --vgname CONT --fssize 5G --fstype ext4" doit créer un conteneur et son volume logique associé. Mais la création échoue. Cela semble être un bug reproductible : http://www.mail-archive.com/debian-bugs-dist@lists.debian.org/msg1062961.html.

J'ai essayé de comprendre et sans être un expert, voici où j'en suis arrivé :
Dans le fichier lxc-debian, ligne 484, en plein dans la fonction Copy_system (), on copie un dossier de la forme /var/cache/lxc/squeeze_amd64 dans le dossier /var/lib/lxc/NOM_CONT/rootfs/squeeze_amd64. On essaye ensuite d'accéder à/ou de monter des dossiers de la forme /var/lib/lxc/NOM_CONT/rootfs/etc/apt/sources.d/debian/list. Mais il n'y a rien ici, tout est dans le dossier squeeze_amd64.

Ce problème n'est pas réparé avec la version de LXC présente dans le dépôt unstable. Je ne sais pas si la version actuelle (via git) corrige ce problème.

Si vous voulez absolument utiliser cette fonctionnalité, voilà une solution qui semble marcher :
Remplacer la ligne 484 de /usr/share/lxc/templates/lxc-debian par

cp -Ra "${_CACHE}/${_DISTRIBUTION}_${_ARCHITECTURE}" "${_ROOTFS}"/* || return 1

Procéder à la création normale du conteneur.

Modifier ensuite le fichier de configuration (ex : /var/lib/lxc/NOM_CONT/config) afin que le paramètre lxc.rootfs contienne la bonne valeur (/var/lib/lxc/NOM_CONT/rootfs). Si vous ne faîtes pas cela, alors vous aurez une erreur "unable to determine your tty name" lors du login via lxc-console.

N'oubliez pas d'ajouter une ligne dans /etc/fstab pour que le conteneur puisse démarrer tout seul. Exemple :

/dev/CONT/test	/var/lib/lxc/test/rootfs	ext4	defaults			0	0

Puis monter ce volume logique comme d'habitude. Vous pouvez ensuite utiliser lxc-start.

Cette méthode me paraît vraiment "bricolage". Je préfère créer/monter moi-même le volume logique ...

Sources

Domain Name System : Attaques et sécurisation

Aujourd'hui, je vous propose un long billet sur le DNS, DNSSEC et les attaques que l'on peut mener contre ce protocole et son extension de sécurité.

Ce travail a été réalisé conjointement avec Hamza HMAMA.

Pour lire la version HTML, il suffit de cliquer sur le lien "Lire la suite" (et/ou de poursuivre ci-dessous). Pour ceux qui préfèrent lire un si gros pavé en PDF, c'est par là : Domain Name System : Attaques et sécurisation.

Nous mettons également les sources LaTeX à votre disposition. Nous avons pris le plus de soin possible pour respecter les règles typographiques et l'esprit de LaTeX. Les seules erreurs restantes sont relatives à des underfull/overfull et sont causées par les URLs/Références. Si jamais notre code choque des gourous LaTeX, qu'ils n'hésitent pas à nous corriger. En attendant, ces sources LaTeX peuvent servir de base à d'autres projets. Sources.

Vous pouvez également récupérer les laboratoires Netkit (vous comprendrez la raison de leur existence en lisant le pavé). Ils peuvent servir pour des expériences DNS/DNSSEC. Labo DNS | Labo DNSSEC | Les deux.

Et pour terminer, vous pouvez également récupérer le visuel projeté durant notre soutenance et ses sources. Par contre, ne faites pas attention aux private jokes qui se sont incrustées. Support visuel soutenance | Sources LaTeX support visuel soutenance.

Si vous voulez tout récupérer (labos, sources, pdf) en un seul coup, c'est par là : DNS - Attaques et securisation - Pack all-in-one.

Le tout (les sources LaTeX, les pdf, les images, les labos Netkit, ...) est diffusé sous la licence habituelle de ce blog, à savoir : CC-BY-SA 3.0 France.

Lire la suite >>

En vrac

Ça commence à faire un petit moment que je n'ai rien posté. On va donc se faire un concentré d'astuces.

Table des matières

Copier/déplacer un dossier contenant beaucoup de petits fichiers

Quand vous tentez de déplacer un dossier qui contient vraiment beaucoup de petits fichiers (au hasard, le Buildroot complet d'OpenWRT), vous allez prendre du temps car le débit en écriture va s'effondrer à cause des petits fichiers. Pour peu que le support physique qui est en dessous soit un peu mou, la copie va vraiment s'éterniser.

On n'y pense pas assez souvent mais tar est notre ami. La création de l'archive (tar -cf destination.tar source/ ), même directement sur le support de destination sera largement plus rapide (on parle d'un gain de plusieurs dizaines de minutes dans mon cas). 7z s'est montré moins efficace. Pas contre, rien n'empêche de 7zippé une archive tar 😉 .

Dans le même ordre d'idée, un rm -rf dossier sera toujours plus rapide dans ces cas-là qu'une interface graphique.

Trier vos comptes de courrier sous Thunderbird/Icedove

La barre latérale gauche de Thunderbird vous montre vos comptes de courrier ainsi que leurs sous-dossiers. Si vous souhaitez trier l'ordre d'affichage de cette liste, il y a deux méthodes : le faire à la main dans le about:config ou le faire avec une extension.

Parmi les extensions existantes, ma préférence va à manually-sort-folders/manually-sort-folders qui fait juste ce qu'on attend d'elle.

Restreindre les droits de Wireshark

Pour utiliser Wireshark, il y a le bon vieux sudo que personne ne recommande et pour cause, lancer une GUI en root est une aberration car elle n'a pas besoin des droits acquis et qu'il s'agit donc d'un vecteur d'attaque supplémentaire. Il y a aussi la méthode qui consiste à exécuter seulement la dumpcap (la librairie de capture) en mode root en utilisant le setuid bit. C'est la méthode que j'ai toujours utilisée.

®om nous parle d'une autre méthode qui consiste à autoriser les membres d'un groupe d'utilisateurs bien défini à capturer les paquets.

Notez deux choses :

  1. On a déporté les droits d'une application sur un groupe : n'importe quelle application lancée par l'utilisateur faisant partie du groupe aura donc la possibilité de capturer le trafic réseau.
  2. Cette méthode permet de faire en sorte que la manipulation soit persistante : le setuid bit sur la dumpcap saute à chacune de ses mises à jour (sauf à utiliser dpkg-statoverride mais c'est une autre histoire).

Pensez à regarder les commentaires sous le billet de ®om pour y trouver d'autres manips sympas (capabilities ou le chaînage tcpdump/wireshark).

Ne pas être informé des mises à jour d'une extension WordPress

Quand une mise à jour pour un thème ou une extension que vous utilisez apparaît, WordPress vous le signale dans l'administration. C'est très bien. Sauf quand il confond une extension avec une autre. Non, Table of Contents Generator de Scott Yang n'est pas la même extension que Table of Contents Generator de Tim Carr (l'insertion d'une TOC ne se fait pas avec le même tag et il y a qu'un seul fichier dans la version de Scott Yang contre une multitude dans celle de Tim Carr, par exemple).

Jusqu'à peu, j'empêchais WordPress de m'informer d'une mise à jour de cette extension en modifiant son numéro de version dans le fichier source. Mais depuis peu, WordPress ne se laisse plus berner. J'ai donc recours à une extension qui bloque les notifications de mise à jour d'une extension en particulier. Parmi toutes les extensions disponibles pour ce travail, j'ai choisi Plugin updates blocker. Simple et efficace.

Attention toutefois à ne pas faire n'importe quoi : ce n'est pas une bonne idée de bloquer les notifications de MAJ de toutes vos extensions, par exemple. Entre autres, sachez que la non-mise à jour d'une extension peut entraîner des risques de compromission (sisi, ça c'est déjà vu). Mais quand l'extension dont vous désirez bloquer les notifications n'est plus maintenue depuis plus de 5 ans ...

Faire en sorte que les identifiants de Table of Contents Generator soient uniques

En effet, si vous utilisez un même titre dans deux de vos billets et que vous utilisez ToCG (de Scott Yang hein), vous aurez deux identifiants identiques. Exemple fictif : Pour deux titres "toto" dans deux billets différents, vous aurez http://www.guiguishow.info/2011/07/14/mon-super-billet/#toc-toto et http://www.guiguishow.info/2012/08/02/en-vrac-2/#toc-toto. Si les deux billets tombent sur la même page (index, catégories, archives, ...), cela posera quelques problèmes au navigateur, au validateur W3C et à l'utilisateur qui n'obtiendra pas ce qu'il voudra quand il cliquera sur le lien. En effet, un identifiant (ancre ou autre) doit être unique dans une page web.

L'idée est donc d'ajouter dans l'identifiant toc un élément variable et unique. L'ID du billet ? Dans l'exemple précédent, cela donnerait (toujours fictif) :http://www.guiguishow.info/2011/07/14/mon-super-billet/#toc-254-toto et http://www.guiguishow.info/2012/08/02/en-vrac-2/#toc-123-toto. Les identifiants seront uniques et plus aucune collision ne se produira si les billets tombent sur la même page.

Pour réaliser ce changement, il suffit de modifier une ligne de la méthode "get_tocid($text)" :
La ligne 26 :

return "toc-$tocid";

devient :

return "toc-$this->postid-$tocid";

Le code complet de la méthode devient donc :

function get_tocid($text) {
        $text = sanitize_title_with_dashes($text);
        $text = preg_replace('|%([a-fA-F0-9][a-fA-F0-9])|', '', $text);
        $tocid = $text;
        $count = 0;
        while (isset($this->tocmap[$tocid]))
            $tocid = $text.strval(++ $count);

        $this->tocmap[$tocid] = true;
        return "toc-$this->postid-$tocid";
}

La variable d'instance $this->postid est définie dans la méthode "the_posts($posts)".

À voir

Si vous ne vous êtes jamais penché sur eux, je vous conseille d'aller voir de plus près :

  • OpenStreetMap (OSM) : Projet de cartographie mondiale libre. Je ne trollerai pas sur "pas complet"/"plus complet que"/"collaboratif donc pas fiable" car la messe est déjà dite avec Wikipédia (dans le sens où Wikipédia a été reconnue aussi fiable que les encyclopédies classiques) et ce billet de SebSauvage. Et quand je vois les arnaques sur les GPS commerciaux (30 jours max après achat pour mettre à jour les cartes avec un soft non libre, une seule mise à jour dans les GPS bas de gamme, les GPS haut de gamme mise à jour "à vie" limitées, ...), je ne peux pas m'empêcher de penser que si je m'achète un GPS un jour, alors ça sera un modèle sur lequel je pourrais mettre les cartes OSM. En attendant, j'ai déjà effectué quelques modifications de la carte de ma ville et il faut reconnaître que c'est facile à faire et rapide même avec l'éditeur en ligne.
  • FRnOG : "Le FRench Network Operators Group (FRnOG) est un groupe d'échange d'informations qui rassemble des personnes intéressées par les domaines de la sécurité, la recherche et le fonctionnement d'Internet en France." Mélange entre information et troll, toute personne intéressée par le monde des réseaux se doit de suivre cette liste de discussion.

Quelques définitions basiques et simplifiées de termes employés chez les opérateurs

Quelques définitions à ceux qui débutent en "vrai" réseau ( 😉 ) car le net regorge de schémas et d'explication juste que des fois, il faut faire plus simple.

GIX | IX | IPX | Point d'échange : Lieu physique (généralement un datacenter) dans lequel des opérateurs s'interconnectent. Pour simplifier, il faut voir cela comme un gros switch sur lequel des opérateurs viendraient connecter un câble menant à leur réseau. Actuellement, beaucoup d'interconnexions se font sur Paris. Ce qui est une mauvaise chose puisque le trafic se concentre en un lieu avant d'être réparti localement. L'idéal serait de favoriser les GIX locaux entre plusieurs membres de la fédération.

Peering : Accord (souvent gratuit mais pas que) entre deux (ou plus) opérateurs pour s'échanger le trafic entre leurs réseaux de manière directe.
Avantages :

  • Optimisation : route plus courte donc on diminue la latence.
  • On gagne (un poil) en indépendance vis-à-vis de son transitaire : si le réseau de ce dernier tombe, on a encore nos routes vers les réseaux avec lesquels on a un peering.
  • On augmente les interconnexions existantes entre plusieurs points et donc, on augmente la robustesse de l'Internet.

Dans la vraie vie, les opérateurs imposent des politiques de peering plus ou moins débiles (quota, “jeCausePasAuxPetits”, …).
Attention : le peering n'est pas transitif. Si A peer avec B et B peer avec C, A ne peer pas avec C et A devra donc avoir un transitaire pour faire le trajet A <> C.

Transitaire : Opérateur qui donne accès à tous les réseaux qui composent Internet. Cet opérateur peut faire des peering, acheter des routes, … mais l'important est qu'il doit fournir un accès complet. La question bête qui peut venir à l'esprit est : mais si tous les transitaires fournissent toutes les routes vers n'importe où, comment en choisir un plutôt qu'un autre ? On tombe là dans des problématiques de qualité des routes proposées. Exemple : vous êtes en France et vous avez le choix entre le transitaire A et le transitaire B. A peer avec les réseaux importants français (FT, Free, peu importe) à Paris. B peer avec ces mêmes réseaux à Amsterdam. Vous comprenez que, dans votre cas, A > B.

Porte de collecte : Point de sortie d'un tunnel L2TP.

Tunnel L2TP : Permet de récupérer les abonnés au BAS (= concentrateur en sortie de DSLAM) et de les acheminer jusqu'au réseau de l'opérateur desdits abonnés quand l'opérateur ne dispose pas de ses propres installations au niveau physique et local. Il faut voir ça comme un câble virtuel amenant l'abonné jusqu'au réseau de l'opérateur.

Note : ce contenu est disponible sur le wiki de la FFDN tout simplement car je l'y ai mis. Mais comme j'aime bien la redondance, je recopie ici.

Les différentes approches de la collecte ADSL

Attention : Cette page se veut simple et non-exhaustive. Son but principal est de répondre à la question “Pourquoi un FAI de FFDN ne prend pas en charge l'abonné de son routeur jusqu'à son réseau ?”.

Quel est le but du jeu quand on est FAI ? Amener un abonné à votre service jusqu'à Internet. Plus précisément, jusqu'à votre réseau, qui, comme d'autres, compose Internet. Ce qui n'est pas forcement clair, c'est qu'il y a plusieurs niveaux. Du plus indépendant au plus dépendant. On ne parle ici que d'ADSL et donc de collecte ADSL. La fibre semble ouvrir de nouvelles opportunités.

Tout faire soit même (du routeur de l'abonné jusqu'à votre réseau opérateur)

Vous êtes financé par une jeune et riche Nigérienne qui vient d'hériter de ses parents ( 😀 ) ?

Alors vous installez des DSLAM dans les NRA dans lesquels arrivent les lignes des abonnés qui vous intéressent. Ensuite vous avez votre propre BAS (= un bête concentrateur) raccordé à votre DSLAM, votre propre lien en fibre optique jusqu'à un datacenter dans lequel vous installez votre cœur de réseau (le routeur qui parle BGP, entre autres) et depuis lequel vous donnez accès au net grâce à des peering et des transitaires.

L'indépendance est totale (sauf vis-à-vis du(des) prestataires qui vous fournissent des chemins vers le reste d'Internet). Cette solution est fortement onéreuse : coût du DSLAM et du BAS, location des lignes de vos abonnés à FT, “loyer” pour installer votre DSLAM et votre BAS, …

Plus raisonnable

Faire appel à un opérateur de collecte qui vous livrera, en L2TP, vos abonnés dans un datacenter. Reste à trouver celui qui fait ça à un niveau local sans passer par Paris. Il y a eu coût à prévoir qui n'est pas à la portée du premier FAI local en construction venu.

Être en marque blanche FDN. Cela est déjà expliqué ailleurs sur ce wiki 🙂 . Cela revient à de la collecte Parisienne à prix réduit.

Note : ce contenu est disponible sur le wiki de la FFDN tout simplement car je l'y ai mis. Mais comme j'aime bien la redondance, je recopie ici.

Interconnexion locale de FAI locaux

C'est quoi le VRAI Internet dont les membres de FFDN ne cessent de parler ?

En plus d'être neutre et libre, le vrai Internet est acentré. Si l'on crée un centre, on recréer le Minitel, pas de l'Internet. Donc il faut favoriser les points d'échanges locaux plutôt que de tout regrouper à Paris (en plus de favoriser des usages acentrés (pas de Facebook ou de MSN) mais c'est un autre sujet).

Pour l'exemple FICTIF, prenons 2 FAI de la fédération géographiquement proches : Ilico (Corrèze) et Aquilenet (Aquitaine). Il y a plusieurs moyens de s'échanger du trafic entre un abonné Ilico et un abonné Aquilenet :

  • Soit on demande à un opérateur tiers qui a le matériel au niveau local de la zone à couvrir de nous livrer le trafic en un point donné (notez que plusieurs opérateurs de collecte peuvent intervenir (= se chaîner) : Nerim passe à FDN qui passe à l'association locale, par exemple). La centralisation française fait que la livraison se fait généralement dans un datacenter de la région Parisienne. Donc, un abonné Ilico qui veut consulter un contenu hébergé par un abonné Aquilenet fera le chemin suivant : opérateur de collecte → porte de collecte Ilico → réseau d'Ilico (à Paris donc) → réseau d'Aquilenet (à Paris) → porte de collecte Aquilenet → opérateur de collecte.
  • Soit on fait de la collecte locale. Ilico récupère ses abonnés dans un datacenter à Brive et Aquilenet récupère les siens dans un datacenter à Bordeaux. En l'état, ça ne change rien au point précédent, il faudra emprunter des réseaux tiers pour faire Bordeaux → Brive. Mais si l'on fait un lien physique entre Brive et Bordeaux ? Le chemin devient opérateur de collecte → porte de collecte Ilico → réseau d'Ilico (à Brive donc) → réseau d'Aquilenet (à Bordeaux) → porte de collecte Aquilenet → opérateur de collecte. La distance est raccourcie. Remarquez également qu'un lien supplémentaire relie désormais Brive à Bordeaux : si Paris se fait bombarder, ces deux villes pourront encore communiquer. La liaison Bordeaux <> Brive peut se faire en fibre (on parle de 150€/mois) ou en WiFi (Plus d'infos).
  • Soit on fait la collecte de telle façon que les abonnés des deux FAI soient récupérés au même endroit (Bordeaux ou Brive donc) et les deux FAI installent leur cœur de réseau dans le même datacenter de la même ville.
  • D'autres solutions existent, c'était juste pour le cas d'école. D'ailleurs, il est donné au lecteur l'exercice de réfléchir à cette question : est-il pertinent de mettre un GIX entre 3 tout petits opérateurs comme dans l'exemple que nous venons de développer ? 🙂 /> (Indice : On est dans une question de charge des liens à comparer aux coûts de ces mêmes liens.)

Il ne s'agit pas d'un rêve : d'autres pays d'Europe sont moins centralisés (Plus d'infos). Les USA sont également décentralisés par construction (état fédéral et disposition géographique de la population). Des projets sont en cours pour construire des GIX locaux (Plus d'infos).

Note : ce contenu est disponible sur le wiki de la FFDN tout simplement car je l'y ai mis. Mais comme j'aime bien la redondance, je recopie ici.

Plutôt que de vous arrêter là, je vous invite à lire le reste du wiki de la FFDN ainsi que les contenus produits par ses membres.

NTP via DHCP sous Debian

DHCP permet de passer tout un tas de paramètres en dehors des traditionnels IP, masque, broadcast, gateway, hostname, serveur dns, ... Il permet également de passer l'IP d'un serveur de temps. Rappelez-vous, j'ai installé un serveur de temps sur mon routeur OpenWRT. Je suis donc un peu furax quand je vois mon Debian aller contacter le pool ntp.org pour se synchroniser.

L'étendue du problème est résumée ici : NTP - Configuration des clients chez L'Internet Rapide et Permanent. Pour résumer : le Network-Manager (NM) bypass les scripts dhclient.

Pour résoudre le problème, il suffit de placer un script dans le dispatcher du Network-Manager comme indiqué ici : network-manager: ignores /etc/dhcp3/dhclient-*-hooks.d. J'avais tenté de copier les scripts dhclient dans le dispatcher, sans effet (et pour cause, les variables contenant l'information ne sont pas les mêmes entre dhclient et NM).

Mais plutôt que de reprendre le script, je vous propose ce script fortement inspiré de celui proposé sur le bugreport de Debian :

#!/bin/sh -e
# Script to take DHCP configured NTP servers
# This heavily leverages the ntp script from dhclient-exit-hooks.d
 
if [ -z "$1" ]; then

    echo "$0: called with no interface" 1>&2
    exit 1;
fi
 
case "$2" in

    up|vpn-up)
 
	if [ -z "$DHCP4_NTP_SERVERS" ]; then

		logger "DHCP n'a retourné aucun serveur NTP."
		exit 1;
	else
		ntpdate $DHCP4_NTP_SERVERS
		if [ $? -eq 0 ]

		then
			logger "Synchronisation NTP effectuée."
			exit 0;
		else
			logger "Problème lors de la synchronisation NTP."

			exit 1;
		fi
	fi
	;;
    down|vpn-down)

	;;
    *)
	echo "$0: called with unknown action \`$2'" 1>&2
	exit 1

	;;
esac

Placez ce script dans le dispatcher NM (exemple : /etc/Network-Manager/dispatcher.d/02ntpdate) et votre ordinateur prendra le serveur NTP local pour synchroniser son horloge (si le serveur DHCP lui a bien communiqué ladite IP). La variable $DHCP4_NTP_SERVERS est fournie par NM.

ÉDIT du 17/02/2014 à 11h50 : Mouais, il y a mieux à faire ...
/etc/NetworkManager/dispatcher.d/01ifupdown exécute les scripts contenus dans les dossiers /etc/network/if-(up|down).d. /etc/network/if-up.d/ntpdate exécute /usr/sbin/ntpdate-debian. Par défaut, ce dernier script récupère la liste des serveurs NTP à utiliser dans /etc/default/ntpdate ou dans /etc/{ntp.conf,/openntpd/ntpd.conf} ou dans /var/lib/ntpdate/default.dhcp.

Il suffit donc de rajouter un bloc : si on récupère des adresses de serveurs NTP en DHCP, on les utilise, sinon on utilise ceux de /etc/default/ntpdate :

[...]
 
if [ -r /etc/default/ntpdate ]; then
        . /etc/default/ntpdate
fi
 
# VIA DHCP
NTPSERVERS=$(nmcli -f DHCP4 dev list | grep ntp_servers | cut -d '=' -f 2)" "$NTPSERVERS
 
[...]

Oui, si un fichier ntp.conf/openntpd/ntpd.conf existe, alors les paramètres obtenus via DHCP seront ignorés. Il suffit de mettre ce morceau de code après le check ntp.conf.

Oui, ça se repose sur Network-Manager.

« NTPSERVERS=[...]" "$NTPSERVERS » permet de garder les serveurs du pool ntp.org (ceux indiqués dans /etc/default/ntpdate) sous le coude au cas où le(s) serveur(s) NTP obtenu(s) avec DHCP ne soi(ent) pas disponibles ou erronés. Fin de l'édit

Et pour ceux que ça intéresse : Pour indiquer au dnsmasq d'OpenWRT de préciser le serveur NTP à utiliser via DHCP, il suffit de créer/modifier la variable "dhcp.lan.dhcp_option" d'uCi. Exemple :

uci set dhcp.lan.dhcp_option=42,192.168.0.254

/etc/init.d/dnsmasq restart

42 est le numéro d'option concernant NTP. L'intégralité des options (et le code associé) permissent par DHCP sont publiées dans le RFC 2132.

Vous pouvez spécifier n'importe quelle option (serveur TFTP + nom du fichier pour un boot PXE, par exemple) à dnsmasq de la même manière. Et si vous voulez combiner plusieurs options (ici TFTP et NTP), deux méthodes sont à votre disposition :

uci set dhcp.lan.dhcp_option="42,192.168.0.254 66,tftpsrv.lan 67,tftp.bin"

/etc/init.d/dnsmasq restart
 
ou
 
uci add_list dhcp.lan.dhcp_option=42,192.168.0.254
uci add_list dhcp.lan.dhcp_option=66,tftpsrv.lan
uci add_list dhcp.lan.dhcp_option=66,tftp.bin
/etc/init.d/dnsmasq restart