Les cours, c'est comme le sexe… c'est mieux en présentiel.
:D
Résumé : si t'utilises un Cisco ASA pour fournir un service de VPN TLS et que des utilisateurs GNU/Linux qui utilisent openconnect
rencontrent l'erreur « Server certificate verify failed: signer not found », vérifie que ton ASA envoie bien le certificat x509 intermédiaire en sus de son certificat client / feuille au client lors de l'échange TLS.
Nous utilisons notre Cisco ASA pour fournir un VPN TLS. Il se présente auprès des clients VPN avec un certificat x509. Le nôtre expire dans 24 jours. Donc on le renouvelle. Sauf que ça ne fonctionne pas : impossible de charger ce certificat dans ASDM. Aucun message d'erreur explicite.
Nous achetons nos certificats x509 en passant par un groupement d'organisations. Ce dernier a fait le choix de changer d'autorité de certification. Le certificat x509 de la nouvelle autorité encapsule une clé RSA de 3072 bits (contre 2048 bits pour l'ancienne) et il est signé en utilisant la fonction de condensation SHA-384 (contre SHA-256 pour l'ancien). J'imagine que l'une de ces propriétés ne convient pas à notre Cisco ASA dont le logiciel n'est plus à jour (son remplacement est en cours, mais ça traîne au-delà de nos prévisions pessimistes qui nous ont conduit à ne plus renouveler le support de l'ASA).
Pour dépanner, nous décidons d'utiliser un certificat Let's Encrypt. Car, au niveau technique c'est ce qu'on a toujours eu : RSA 2048 bits + SHA-256. De plus, c'est la manière la plus simple et rapide (pas de procédure d'achat à déclencher, on tire un certificat, on teste et on voit direct le résultat). Notre ASA accepte le certificat. \o/ Victoire ?
Sur un système GNU/Linux, nous conseillons le client VPN openconnect
, une implémentation libre pour plusieurs VPN TLS (Cisco, Juniper, etc.) qui s'intègre à GNOME network-manager. Depuis le changement de certificat x509, nos utilisateurs reçoivent une erreur :
$ sudo openconnect vpn.monorganisation.example
POST https://vpn.monorganisation.example/
Connected to 192.0.2.1:443
Négociation SSL avec vpn.monorganisation.example
Server certificate verify failed: signer not found
Certificate from VPN server "vpn.monorganisation.example" failed verification.
Reason: signer not found
To trust this server in future, perhaps add this to your command line:
--servercert pin-sha256:xAj8efLob9rYcspJ8p+2J+K9qTJlgsW1m300Ls+VyCs=
Enter 'oui' to accept, 'non' to abort; anything else to view: oui
Même erreur avec openconnect sur Android. Aucune erreur avec winwin + AnyConnect. Aucune erreur sur Apple (Mac OS, IOS), mais c'est normal : nous préconisons l'utilisation d'IPSec.
Qu'est-ce qui ne va pas ?
$ openssl s_client vpn.monorganisation.example:443
CONNECTED(00000003)
depth=0 CN = vpn.monorganisation.example
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 CN = vpn.monorganisation.example
verify error:num=21:unable to verify the first certificate
verify return:1
---
Certificate chain
0 s:CN = vpn.monorganisation.example
i:C = US, O = Let's Encrypt, CN = R3
---
Hum. Le VPN envoie uniquement son certificat (dit aussi certificat client ou certificat feuille). Celui-ci est signé par un certificat intermédiaire (dans le cas de Let's Encrypt, et jusqu'en 2025, il se nomme « R3 ») qui n'est pas communiqué par le serveur. Or, un certificat intermédiaire est jamais livré dans un catalogue / magasin des autorités de certification, car ce n'est pas son rôle. Donc, la bibliothèque TLS (OpenSSL pour openssl s_client
et GnuTLS pour openconnect
) échoue sur la vérification du certificat feuille.
Pour que le VPN ASA envoie aussi le certificat intermédiaire, il suffit d'ajouter ce dernier dans ASDM => « Configuration » => « Device Management » => « Certificate Management => CA Certificates ».
Plus d'erreur. \o/
$ openssl s_client vpn.monorganisation.example:443
CONNECTED(00000003)
depth=2 O = Digital Signature Trust Co., CN = DST Root CA X3
verify return:1
depth=1 C = US, O = Let's Encrypt, CN = R3
verify return:1
depth=0 CN = vpn.monorganisation.example
verify return:1
---
Certificate chain
0 s:CN = vpn.monorganisation.example
i:C = US, O = Let's Encrypt, CN = R3
1 s:C = US, O = Let's Encrypt, CN = R3
i:O = Digital Signature Trust Co., CN = DST Root CA X3
Pourquoi ça fonctionnait avec AnyConnect ? Peut-être que celui-ci désactive la vérification du pair lors de l'échange TLS ou qu'il est moins stricte, ce qui est une très mauvaise idée dans tous les cas.
Résumé : Let's Encrypt a remplacé son vieux certificat intermédiaire nommé « Let's Encrypt Authority X3 » par un nouveau nommé « R3 ». Si tu utilises une implémentation minimaliste d'ACME (genre acme-tiny) qui récupère uniquement le certificat de ton site web auprès de Let's Encrypt, il faudra changer toi-même le certificat intermédiaire dans tes serveurs TLS, sans quoi une partie des clients web ne pourra plus accéder à ton service.
Depuis plusieurs semaines, plusieurs flux RSS sont en erreur « 60 SSL certificate problem: unable to get local issuer certificate » dans mon agrégateur RSS.
Pourtant, j'accède sans problèmes à ces sites web avec Firefox.
J'essaye d'accéder aux sites web depuis le serveur qui héberge mon lecteur de flux RSS :
$ wget https://exegetes.eu.org
--2021-01-18 22:30:45-- https://exegetes.eu.org/
Résolution de exegetes.eu.org (exegetes.eu.org)… 2001:910:800::82, 80.67.169.82
Connexion à exegetes.eu.org (exegetes.eu.org)|2001:910:800::82|:443… connecté.
Erreur : le certificat de « exegetes.eu.org » n’est pas de confiance.
Erreur: The certificate of « exegetes.eu.org » doesn't have a known issuer.
Même problème avec cURL :
$ curl https://exegetes.eu.org
curl: (60) SSL certificate problem: unable to get local issuer certificate
Au moins, le problème ne dépend pas d'une bibliothèque TLS en particulier car wget
utilise GnuTLS alors que curl
utilise OpenSSL.
Ce n'est plus une erreur relative à PHP comme à l'époque où mon chroot Apache httpd empêchait PHP d'utiliser le magasin des autorités de certification du système. Chroot que j'ai viré depuis afin d'activer HTTP/2.
Sur mon ordinateur de bureau, wget
génère la même erreur.
Tous les sites web concernés utilisent Let's Encrypt malgré le danger que constitue sa force de frappe.
Creusons un peu :
$ openssl s_client -connect exegetes.eu.org:443
CONNECTED(00000003)
depth=0 CN = exegetes.eu.org
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 CN = exegetes.eu.org
verify error:num=21:unable to verify the first certificate
verify return:1
---
Certificate chain
0 s:CN = exegetes.eu.org
i:C = US, O = Let's Encrypt, CN = R3
1 s:C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
i:O = Digital Signature Trust Co., CN = DST Root CA X3
$ openssl s_client -connect jonathan.michalon.eu:443
CONNECTED(00000003)
depth=0 CN = jonathan.michalon.eu
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 CN = jonathan.michalon.eu
verify error:num=21:unable to verify the first certificate
verify return:1
---
Certificate chain
0 s:CN = jonathan.michalon.eu
i:C = US, O = Let's Encrypt, CN = R3
1 s:C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
i:O = Digital Signature Trust Co., CN = DST Root CA X3
$ openssl s_client -connect www.codelyoko.fr:443
CONNECTED(00000003)
depth=0 CN = www.codelyoko.fr
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 CN = www.codelyoko.fr
verify error:num=21:unable to verify the first certificate
verify return:1
---
Certificate chain
0 s:CN = www.codelyoko.fr
i:C = US, O = Let's Encrypt, CN = R3
Le testeur TLS de SSLLabs affiche « This server's certificate chain is incomplete […] Chain issues Incomplete, Extra certs ».
Les deux premiers cas sont identiques : le serveur présente le certificat x509 du site web (dit certificat feuille), signé par le certificat intermédiaire R3 de Let's Encrypt ainsi que le certificat X3 de Let's Encrypt signé par IdenTrust (DST). La chaîne de certification est cassée : site web - R3 !- X3 - DST. Comme le certificat intermédiaire R3 n'est pas disponible dans le magasin de certificats de Debian (et c'est normal, aucun certificat intermédiaire l'est), c'est game over.
Le dernier cas est encore plus simple : le certificat intermédiaire n'est pas communiqué par le serveur, seul le certificat feuille l'est. Comme R3 n'est pas présent dans le magasin des certificats des autorités de certification de Debian, c'est l'échec.
Que s'est-il passé ? Depuis le 20 décembre 2020, Let's Encrypt signe les nouveaux certificats de ses """"clients"""" avec son nouveau certificat intermédiaire nommé R3. Ce dernier remplace Let's Encrypt Authority X3 qui expire en 2021 (il a une durée de vie de 5 ans).
Tu vas me dire "ben oui mais l'API de Let's Encrypt retourne, en plus du certificat client, le nouveau certificat intermédiaire (R3), donc tout devrait fonctionner". Oui, sauf si un site web utilise un outil minimaliste de renouvellement automatique des certificats. Exemple : jonathan.michalon.eu utilise acme-tiny qui récupère uniquement le certificat client, charge à l'utilisateur de configurer un certificat intermédiaire indépendemment.
Pourquoi cela fonctionne avec Firefox et Chromium, alors ? Quand tu accèdes à un site web avec une chaîne valide, Firefox enregistre le certificat R3 et, du coup, est capable de le resortir pour compléter le maillon manquant quand un site web a une chaîne incomplète. Cela se fait sans que le certificat R3 apparaisse forcément dans le catalogue des certificats… Pour valider cette hypothèse, il suffit d'utiliser un vieux profil qui a jamais connu R3 et d'aller directement sur un site web défectueux : une erreur s'affiche. En allant sur un site web qui utilise R3 dans une chaîne complète puis en retournant sur le site web défectueux, plus aucune erreur s'affiche.
Sur l'iDRAC d'un serveur Dell, je veux récupérer l'état d'un composant en utilisant le protocole SNMP. Dell complète les bases de données standardisées interrogeables en SNMP avec la sienne (ce qu'on nomme un module MIB, l'ensemble des bases de données agrégées sous forme arborescente est nommée MIB).
Première question : comment connaître l'OID (l'identifiant unique) d'un objet défini dans un module MIB afin de le consulter en SNMP ?
Généralement, chercher le nom de l'objet sur un moteur de recherche web suffit. Dans mon cas, chercher « systemStateIDSDMCardDeviceStatusList » conduit à des résultats fort bien présentés : oidref et observium.org. L'OID est 1.3.6.1.4.1.674.10892.5.4.200.10.1.61
Mais si l'on veut trouver par nous-même, au cas où une MIB ne soit pas aussi bien indexée ?
Le début d'un OID est normalisé : .1.3.6.1. .1.3.6.1.2.1 pour la très populaire MIB-II. .1.3.6.1.4.1 pour les sociétés commerciales privées. Mais la suite dépend de Dell (dans mon cas).
On peut télécharger la MIB et l'étudier avec un éditeur de texte. On cherche notre objet par son nom (« systemStateIDSDMCardDeviceStatusList » dans mon cas). On lit « ::= { systemStateTableEntry 61 } ». Cet objet a donc l'ID 61 relativement à l'objet « systemStateTableEntry ». On remonte l'arborescence : l'objet « systemStateTableEntry » a l'ID 1 relativement à l'objet « systemStateTable » qui, lui-même, a l'ID 10 relativement à l'objet « systemStateGroup » qui a l'ID 1.3.6.1.4.1.674.10892.5.4.200. L'OID absolu que nous cherchons est donc 1.3.6.1.4.1.674.10892.5.4.200 + .10.1.61 + .1 soit 1.3.6.1.4.1.674.10892.5.4.200.10.1.61.1. Pourquoi j'ai ajouté un « 1 » à la fin ? Car c'est comme ça que l'on consulte la case d'un tableau en SNMP.
Et si l'on n'a pas envie de s'embêter avec ce que je viens de raconter ? On utilise le logiciel snmptranslate
de la trousse à outils net-snmp (nom du paquet Debian : snmp). Tout est dans la documentation, mais je vais répéter :
snmptranslate -Dinit_mib .1.3 2>&1 | grep MIBDIR
. Sous Debian, il y a des chemins dans /usr/share (si l'on dépose une MIB dedans, le dossier ne sera pas supprimé quand on supprimera le paquet snmp…) et ~/.snmp/mibs ;mkdir -p ~/.snmp/mibs
;snmp-mibs-downloader
car tous les modules MIB ne sont pas libres. Les MIBs seront téléchargées durant l'installation du paquet ;snmptranslate -IR -On IDRAC-MIB-SMIv2:systemStateIDSDMCardDeviceStatusList
.
Deuxième question : comment charger / ajouter une MIB à snmpget
/ snmpwalk
afin d'utiliser le nom d'un objet pour y accéder ?
Nous venons de faire cela pour répondre à la question précédente.
Nous pouvons récupérer la valeur d'un objet à partir de son nom : snmpget -v2c -c <COMMUNAUTÉ> <nom_DNS_iDRAC> IDRAC-MIB-SMIv2:systemStateIDSDMCardDeviceStatusList.1
(là non plus, on n'oublie pas le « .1 » final afin d'entrer dans la case du tableau).
On peut toujours récupérer la valeur de l'objet à partir de l'OID qu'on a trouvé ci-dessus : snmpget -v2c -c <COMMUNAUTÉ> <nom_DNS_iDRAC> 1.3.6.1.4.1.674.10892.5.4.200.10.1.61.1
.
Et si l'on veut que snmpget
/ snmpwalk
résolvent le nom d'un OID pour nous ? snmpwalk -m +IDRAC-MIB-SMIv2 -v2c -c <COMMUNAUTÉ> <nom_DNS_iDRAC> 1.3.6.1.4.1.674.10892.5.4.200.10.1
. Et si préciser « -m +IDRAC-MIB-SMIv2 » est trop pénible, tu remplaces la ligne « mibs : » par « mibs +IDRAC-MIB-SMIv2 » dans /etc/snmp/snmp.conf
.
Je suis passé de la version 10.4 à la 10.7 de Debian GNU/Linux. Depuis, Chromium ne fonctionne plus : l'affichage se fige totalement quelques secondes après son démarrage.
Solution ? Désactiver l'accélération graphique.
Comment faire ?
chromium --disable-gpu
;Résumé : présentation rapide de Dell IDSDM (système d'exploitation d'un serveur sur deux cartes SD redondées), du processus de résolution d'une banale panne de carte SD, des manières de superviser l'état des cartes SD et du module IDSDM en ligne de commande et à distance, et des limites de la techno (faux positif, remplacer une carte SD nécessite d'éteindre le serveur et de redémarrer iDRAC, logistique pour remplacer régulièrement les cartes SD, peu de documentation). Une petite anecdote mettant en exergue la démesure de la logistique de Dell sera narrée.
Notre supervision râle : l'un de nos hyperviseurs ne remonte plus d'info. Ping OK. Impossible d'établir une connexion SSH. Les machines virtuelles hébergées dessus fonctionnent toujours sans problème. Impossible de piloter les machines virtuelles (allumer/éteindre, console, migrer sur un autre nœud du cluster) depuis les autres hyperviseurs du même cluster.
Dans la salle serveurs (mais la console iDRAC aurait affiché la même chose), l'écran affiche une palanquée d'erreurs d'écriture puis de lecture sur dm-0 (probablement le device virtuel associé au conteneur LVM (LV) qui contient la racine du système).
iDRAC confirme : les deux cartes SD sont mortes. La première est morte le 13/12/2020, l'autre le 08/01/2021.
Ha, oui, on utilise la techno Dell Internal Dual SD Module (IDSDM). Un module (une carte électronique fille branchée sur la carte mère du serveur, voir la page 2 du whitepaper de Dell), deux cartes SD, les écritures se font sur les deux cartes SD et les lectures sur celle du premier slot tant qu'elle est opérationnelle (comme du RAID 1), et l'on installe un système d'exploitation dessus. Le système voit les cartes SD comme un disque dur SATA (/dev/sdX).
L'intérêt ? Séparer le système d'exploitation des VMs sans pour autant immobiliser 2 slots pour disques dur (afin de faire un RAID 1 pour le système), ce qui réduit l'espace de stockage disponible pour les machines virtuelles. Il y a 10 slots sur un serveur 1U donc 10 disques durs maximum dont 1 est perdu si l'on fait du RAID 5 (c'est comme ça que ça fonctionne) et encore 1 si l'on veut du hot spare (disque de secours qui remplacera, sans intervention humaine, un disque défectueux), alors si l'on retire encore deux disques pour le système… Cependant, deux PV LVM sur une même grappe RAID produiraient environ le même résultat de séparation sans immobiliser deux slots.
Évidemment, et c'est un tort, nous avons mis en place aucune optimisation afin de limiter les écritures sur les cartes SD : ni log2ram (qui stocke les journaux en RAM et les écrit, par paquet, à intervalle régulier sur le support de stockage), ni option de montage « noatime », rien.
On vérifie la santé des deux autres hyperviseurs du même cluster. Ho, une carte SD sur les deux est morte dans un autre hyperviseur depuis le 28/12/2020. Le troisième hyperviseur est sain.
Appel téléphonique au support Dell. On nous dit que beaucoup de clients installent un système sur IDSDM (en même temps, quel vendeur dira que son produit est inutilisé ?!). Il y a rien d'anormal, qu'on nous dit, la durée de vie des cartes SD est de 2 ans et demi / 3 ans (pour info, nos serveurs sont en prod' depuis un peu moins de 2 ans). Lourde insistance du support pour remplacer les modules en sus des cartes SD… Soit.
Nous sommes vendredi midi. Nous sommes fermés le samedi. Nous avons contracté un support ProSupport H+4. Que va faire Dell ? Attendre que le manager revienne de la cafèt’ (sisi :D), trouver 2 modules et 3 cartes SD dans l'entrepôt situé dans la grande ville la plus proche de chez nous et une 4e carte SD dans l'entrepôt d'une autre grande ville. Deux camions de livraison sont partis de deux villes différentes pour nous livrer 4 cartes SD et deux bouts d'électronique en moins d'une après-midi ! Livraison à 18 h et 20 h. :O
Deux sentiments m'ont accompagné tout cet après-midi-là.
Bon ben on part sur la réinstallation de Proxmox sur notre premier hyperviseur.
Avant ça, on sort les cartes SD et on les tripote entre nos doigts comme la puce d'une carte bancaire muette. Dans le doute…
On tente de démarrer sur l'une des cartes SD : échec. Avec un autre ordinateur, on parvient à ouvrir le VG LVM mais impossible de monter le système de fichiers ext4 : impossible de lire le superblock, input/output error.
En revanche, la deuxième carte SD fonctionne : le serveur démarre ! Tout fonctionne comme avant. Pas d'erreur apparente.
On installe une carte SD neuve dans le deuxième slot. Durant la phase POST du BIOS (tu sais, quand il vérifie la RAM, quand il initialise le contrôleur RAID, etc.), il nous est demandé « SD Card x has been replaced and needs to be rebuilt. […] Press
Sur notre deuxième hyperviseur, il nous suffit de remplacer la SD défectueuse par une neuve et de valider la reconstruction lors du démarrage. Reconstruction qui, elle aussi, s'effectuera en tâche de fond.
On notera que nous avons fait le choix de ne pas remplacer les modules, car nous ne les pensons pas défectueux.
Nous avons également fait le choix de ne pas remplacer les cartes SD qui semblent être fonctionnelles afin que toutes les cartes SD ne tombent pas en panne en même temps.
Sur le premier hyperviseur, j'espère que nous n'avons pas recopié les erreurs d'une des vieilles cartes SD sur les neuves. Pour l'instant : RÀS.
Comment savoir quand la reconstruction d'une carte SD est terminée et que nous sommes revenus à l'état nominal ? D'après les documentations que l'on trouve sur le web, cela se passe dans le BIOS ou dans l'iDRAC, mais, pour que ce dernier mette à jour l'état des cartes SD, il faut le redémarrer… … …
Après 30 minutes, nous redémarrons iDRAC, et, en effet, tous les indicateurs présentés sont repassés au vert. Je parle du tableau de bord et de la section « Média amovible » dans le menu « Système » puis « Présentation générale » dans laquelle les items « SD » (ou « VFLASH SD »), « IDSDM SD1 » et « IDSDM SD2 » doivent être en « Status » OK et l'« État de la redondance » doit avoir la valeur « Total ». Note : sur l'item « SD » (ou « VFLASH SD »), la « Condition de la connexion » est toujours définie à « Absent », même sur un serveur tout neuf.
Les cartes SD sont des consommables qu'il faut changer régulièrement. Cela implique de les superviser. Dans notre supervision actuelle (on ne va pas aller manuellement consulter des interfaces web supplémentaires), ce qui implique des outils CLI (exit, donc, le lourdingue Dell OpenManage). Cette supervision s'effectue depuis iDRAC. C'est un peu chiant à trouver :
megacli
, que l'on utilise déjà pour superviser notre RAID, est inutile ;En plus d'être toujours aussi pénible à installer, RACADM propose rien de spécifique. On peut toutefois remonter l'info sur l'on cherche en analysant les journaux ;
Si l'on active IPMI dans iDRAC (avec la version 9, cela se passe dans le menu « Paramètres de l'iDRAC » => « Connectivité » => « Paramètres IPMI » => « Activer IPMI sur le LAN ») :
ipmitool -I lanplus -H <nom_DNS_iDRAC> -U <identifiant> sensor get SD
retourne rien d'exploitable (idem pour les capteurs « SD1 » et « SD2 ») ;ipmitool -v -I lanplus -H <nom_DNS_iDRAC> -U <identifiant> sdr list | grep -A 5 ': SD'
retourne un énigmatique « sensor reading : 0h » dont on ne trouve pas d'explication dans un quelconque document Dell, et comme il s'agit, a priori, d'une valeur spécifique à un constructeur, une extrapolation depuis d'autres documentations est risquée ;ipmitool -I lanplus -H <nom_DNS_iDRAC> -U <identifiant> sensor | grep '^SD'
affiche les valeurs « 0x0180 » (pour « SD1 » et « SD2 ») et « 0x0080 » (pour « SD ») dont quelques sites web obscurs nous assurent que ça veut dire que tout est OK… Cela se confirme vaguement en regardant l'état d'autres capteurs, mais rien est plus trompeur que l'auto-persuasion ;snmpget -v2c -c public <nom_DNS_iDRAC> .1.3.6.1.4.1.674.10892.5.4.200.10.1.61.1
retourne une valeur qui est documentée dans la MIB iDRAC-SMIv2 téléchargeable sur le site web de Dell (03 03 = les deux cartes SD sont OK, le premier octet étant la première carte SD, l'autre la deuxième). L'état du module IDSDM lui-même est disponible à l'OID .1.3.6.1.4.1.674.10892.5.4.200.10.1.59.1 (même codes retour). SNMP me semble être la moins mauvaise solution pour superviser IDSDM.Vince : on ne dit pas LA WiFi, c'est le Wi-Fi, c'est un mec, un vrai.
Stacy : d'où la panne une fois sur deux.
Résumé : si tu veux refuser l'évolution de ton abonnement à Internet très haut débit par câble que SFR te propose par courrier mais que l'URL donnée dans le courrier ne fonctionne pas, identifie-toi sur le site web de Red by SFR AVANT d'aller sur la page web dont le lien est mentionné dans le courrier. Si ça ne fonctionne toujours pas, tente de suivre ce lien (après t'être identifié) : https://www.red-by-sfr.fr/espace-client/options/resilier/option/OPT_TopageRED_FTM_O2. Si ça ne fonctionne toujours pas, tente de suivre le raisonnement exposé ci-dessous.
En décembre 2020, j'ai reçu le courrier suivant de Red by SFR :
Bonjour [ GuiGui ],
Que diriez-vous d'appeler vos proches sans compter, depuis votre ligne fixe vers leurs mobiles en France et vers les DOM ?
Bonne nouvelle : vous allez bénéficier d'une nouvelle offre RED Box incluant les appels illimités vers les mobiles en France métropolitaine et vers les DOM pour 3€ de plus par mois.(1)(2)
Votre nouvelle offre reste parmi les plus attractives du marché.
Et pour en profiter, rien à faire ! Vous en bénéficierez automatiquement, et toujours sans engagement, à partir de votre facture de janvier.
Bien sûr, vous conservez toutes les éventuelles options que vous détenez actuellement.
Vous préférez rester sur votre offre actuelle ? Pas de souci, dites-le-nous en vous connectant sur https://c.sfr.fr/ftm
À bientôt,
L'équipe RED by SFR
PS : Merci de ne pas tenir compte de ce message si vous avez un changement d'offre en cours.
(1) Conformément à l'article L224-33 du Code de la Consommation, vous pouvez résilier votre contrat sans frais et sans paiement des mois contractuels restant dus jusque dans un délai de quatre mois après l'entrée en vigueur de la modification.
(2) Appels illimités depuis le poste fixe branché sur la box vers les mobiles en France métropolitaine et vers les DOM (Guadeloupe, Réunion et Guyane française, hors Mayotte), hors numéros courts et spéciaux et services de radiomessagerie, appels vers plus de 250 correspondants différents dans le mois : facturés au prix d'une communication vers les mobiles en France métropolitaine. 3H maximum par appel puis facturé au prix d'une communication vers les mobiles en France.
On notera que tout est confus :
Je tente d'aller sur la page web https://c.sfr.fr/ftm mentionnée dans le courrier. Ça ne fonctionne pas (je ne sais plus ce qui s'est affiché).
Je m'identifie, je vais dans mon espace client, je clique sur le bouton « voir tout » de la rubrique « Offre & équipements ». Je me retrouve dans l'onglet « Mon offre » (URL : https://www.red-by-sfr.fr/espace-client/parc/offer ) et je vois rien pour refuser la nouvelle offre. La seule chose que je peu résilier, c'est une option Débit+ qui a aucun rapport.
Je cherche un peu partout dans mon espace client, je trouve rien.
Je cherche sur le web, je tombe sur un message dans une causerie sur le forum de Red by SFR. Le lien proposé, https://c.sfr.fr/ftme, ne correspond pas : je n'ai pas une box ADSL et l'offre qui m'est proposée n'inclut pas des appels illimités vers des mobiles européens. Mais je clique quand même sur le bouton « Refuser cette nouvelle offre ». Forcément, j'atterri sur une page « Il y a un problème avec cette page - Nous sommes désolés, pour des raisons techniques, cette page est inaccessible. ». Je clique sur le bouton « Retour à mon offre ».
Je suis de nouveau dans l'onglet « Mon offre » de mon espace client. Enfin, je le crois, mais l'URL n'est pas la même (https://www.sfr.fr/espace-client/parc/offer maintenant contre https://www.red-by-sfr.fr/espace-client/parc/offer auparavant). Sur cette page, j'ai bien un petit encadré « Votre offre évolue À partir du mois prochain, vous allez bénéficier d’une nouvelle offre RED Box incluant les appels illimités vers les mobiles en France et les DOM pour 3€ de plus par mois. > Plus d'informations ». Je clique.
J'atterri sur https://www.red-by-sfr.fr/info-clients/votre-offre-fibre-evolue/. Cette fois-ci, l'offre correspond à celle décrite dans le courrier et elle concerne bien l'abonnement à Internet à très haut débit : « Découvrez les évolutions prochaines de votre offre RED Box Très Haut Débit(1) Sur votre facture du mois prochain, vous allez bénéficier d’une nouvelle offre RED Box incluant les appels illimités vers les mobiles en France et les DOM pour 3€ de plus par mois*. ». Je clique sur le bouton « Refuser cette nouvelle offre ».
J'arrive sur la page web https://www.red-by-sfr.fr/espace-client/options/resilier/option/OPT_TopageRED_FTM_O2. Je confirme mon refus et… « Votre demande de refus a bien été prise en compte. Aucune modification ne sera apportée à votre offre actuelle. ». Je prends une capture d'écran, on sait jamais.
J'apprécie (ironie) également le bouton « Me déconnecter » qui ne fonctionne pas : je suis renvoyé vers la page d'accueil (https://www.red-by-sfr.fr/) mais mon prénom est toujours affiché dans le menu et je peux revenir dans mon espace client sans communiquer à nouveau mon mot de passe. Même si ça a aucun rapport, j'ai bien décoché la case « Rester connecté » lors de mon identification.
Après coup, j'ai l'impression que s'identifier sur son espace client AVANT de se rendre à l'adresse https://c.sfr.fr/ftm (ou https://c.sfr.fr/ftme pour un abonnement ADSL) permet de refuser la nouvelle offre, mais je n'en suis pas certain : l'URL est différente ( https://www.red-by-sfr.fr/espace-client/options/resilier/option/OPT_TopageRED_FTM_O2 versus https://www.red-by-sfr.fr/espace-client/options/resilier/option/OPT_TopageRED_FTM_O2 ) et je ne peux pas reproduire mes manipulations (ce qui est logique : on ne peut pas refuser deux fois une même offre).
Le coup du SNI c'est assez bizarre en effet, c'est un classique du processus TLS non ?
Oui, depuis 2003.
En plus je croyais qu'il y avait un "fallback" vers un certificat unique (ce qui est mon cas) sans SNI...
Oui. openssl s_client -connect shaarli.guiguishow.info:443 -tls1_2 -servername 'bidule.guiguishow.info'
(un nom bidon dans le SNI) fonctionne. Même résultat avec d'autres serveurs web que le mien.
openssl s_client -connect dukeart.netlib.re:443 -tls1_2 -servername 'bidule.guiguishow.info'
ne fonctionne pas.
=> J'imagine qu'il y a quelque chose à activer dans Caddy. L'option default_sni par exemple.
Le réglage n'est peut-être pas au niveau de la config' TLS. Peut-être que tu n'as pas configuré de virtual host par défaut qui écoute pour tous les noms, par exemple ? En HTTP, tu rediriges tout nom qu'on te demande en HTTPS, même les trucs bidons (exemple ci-dessous), donc j'y crois pas, mais bon…
$ curl -D - http://testduke.example
HTTP/1.1 308 Permanent Redirect
Connection: close
Location: https://testduke.example/
Server: Caddy
Date: Sun, 03 Jan 2021 19:50:47 GMT
Content-Length: 0
Dommage pour Dillo et ça me fait relativiser certaines remarques de Bortzmeyer dans son dernier article sur le web compliqué...
Tout est toujours compliqué tant qu'on n'a pas approfondi / tenté la chose.
Tout ce qui est promu comme étant simple cache quelque chose, toujours.
En TLSv1.3, je peux pas changer l'ordre des //cipher suites// :
Sur mon Debian 10, Dillo utilise TLS 1.2 (quel que soit le serveur).
Ma remarque sur les suites de chiffrement est annulée par mon « édit » : ce n'était pas le bon diagnostic. :)
Depuis septembre 2019, je cuisine. Avant, j'avais jamais rien fait, pas même des pâtes (enfin si, j'avais fait quelques gâteaux avec ma mère dans mon enfance, mais c'est elle qui faisait le plus gros du boulot, tu vois l'genre).
Comment me suis-je nourri jusque-là ? Il y a eu maman. Ensuite, il y a eu les kebabs midi et soir durant des années consécutives. Il y a aussi eu les années consécutives de thon-œufs-chips en alternance (pour les œufs, j'utilisais un coquetier spécial four à micro-ondes). Sans compter les mois consécutifs de boîtes de conserve premier prix de raviolis-cannellonis-cassoulet-saucisses+lentilles consommées en boucle.
Tu l'auras compris, j'ai aucun goût, je prends aucun plaisir à manger, je mange parce que c'est vital, manger m'ennuie au plus haut point.
Alors pourquoi ai-je commencé à cuisiner ? Qu'est-ce que je sais faire ? Qu'est-ce qui m'a fait réduire la cadence ? Qu'est-ce que j'en retire ?
Le traquenard a commencé en 2018. Un collègue, fin gourmet de son état, me parle longuement des yaourtières. Juste des machines chauffantes pour tuer les bactéries et faire agir les ferments pour transformer du lait en yaourts. C'était bien vu : vanter le faire soi-même et la simplicité d'utilisation, ça m'a convaincu. Je me souviens même que je voulais faire les choses jusqu'au bout en utilisant du lait bio acheté en circuit-court… avant de piger que je ne vis pas dans un coin à vaches. J'ai acheté une yaourtière à 15 €. On a fait quelques séries de yaourts durant quelques mois au boulot et puis flemme… Je retiens de la yaourtière : utiliser du lait entier et des ferments (soit on en achète, soit on ajoute un yaourt du commerce au lait).
Ensuite, toujours en 2018, ce fut le retour à la boulangerie entraîné par les collègues. Avec mes parents, tous les jours, on achetait notre pain « bien cuit » (ouais, c'était notre truc) dans la boulangerie artisanale du quartier. Mes parents avaient une profonde détestation du pain industriel de supermarché. Je suis retombé dedans. Boulangeries artisanales du quartier. Pain aux céréales, pain au curcuma, épeautre, pain complet, baguette tradition, pain multigraines, pain de campagne, etc. Aucun effort à fournir, la boulangerie est sur le chemin pour aller chercher de quoi manger le midi avec les collègues. Ho, bien sûr, je suis conscient des douilles qui peuvent survenir sans que je le sache même dans une boulangerie artisanale : farines et levures standardisées parmi une toute petite sélection, pâtisseries voire baguettes industrielles surgelées livrées par des sociétés commerciales comme Coup de pâtes, etc., mais bon…
Et puis, il y a eu les appels du pied répétés des collègues. Je suis jamais resté aussi longtemps salarié d'une même organisation, donc, forcément, ça crée des liens, ça développe la confiance, ça s'entre-interroge sur le mode de vie des uns et des autres et ça formule des propositions, des petits défis, etc. Une personne en particulier m'a rassuré, boosté, expliqué, et accompagné, merci à elle.
J'ai commencé par les classiques pâtes et riz.
Puis j'ai voulu refaire ce qui a fait mon enfance : nuggets de poulet (industriels), riz au curry + échalotes, Ebly, omelette de patates (surgelées puis vraies patates), œufs (plat, coque, et dur), steak haché, haricots verts (boîte de conserve), garniture de céleri (en boîte de conserve, et ce n'est pas des cœurs de céleris), salsifis, patates sautées, patates vapeur, lentilles, semoule (pour couscous, pas la semoule fine pour faire des gâteaux !), purée (industrielle, en flocons), flans à la vanille ou au chocolat (industriels, en poudre), raviolis-cannellonis-cassoulet-saucisses+lentilles en boîtes de conserve (c'est meilleur à la casserole qu'au four à micro-ondes), alouettes à la provençale aka paupiettes de bœufs (cuisinée avec l'aide d'une amie).
J'ai tenté quelques trucs : raviolis "frais" achetés au marché couvert (en fait, il s'agit de bouffe industrielle. Quand je commandais plus que la quantité disponible sur le présentoir, on me vendait un sachet entier de 1 kg venu de la réserve, donc j'ai vu la marque), galettes de pommes de terre précuites du marché couvert (idem, c'est de l'industriel), steak haché d'une boucherie bio du marché couvert (on sent la différence de goût par rapport à du Bigard :O et ce n'est pas une remarque positive, mon palais n'est pas prêt), escalope de poulet dans la même boucherie.
C'est aussi là que j'ai fréquenté Biocoop.
Ça a duré 4-5 mois, puis j'ai voulu me recréer des habitudes… Alors ça a été nuggets de poulet industriels chaque midi et des raviolis du marché couvert chaque soir. Puis galettes de pommes de terre chaque midi et œufs au plat chaque soir. Je suis toujours sur ça. Depuis 1 an, donc.
J'ai pris des notes pour quelques-unes des recettes ci-dessus, mais je ne saurai plus refaire spontanément la plupart d'entre elles aujourd'hui.
Qu'est-ce qui m'a fait lever le pied / découragé ?
La première chose qui m'a rebuté, c'est la complexité.
Les trouzemilles variétés de patates (Monalisa, patates de consommation à chair tendre), de curry (Balti, Madras, Kerrie Mild, etc.), d'oignons (cévennes, rouge, jaune, blanc, etc.), etc. Lait entier ou demi-écrémé ? Pasteurisé ou stérilisé UHT ? Sel ou fleur de sel ? Céréales complètes ou semi-complètes ? Pour chaque aliment, t'as trouzemilles choix auxquels je comprends absolument rien. Ça rend pénibles les courses.
Durée de cuisson de chaque produit ? Durée de conservation de chaque produit ?
Ça en fait, des choses à mémoriser…
Je te parle même pas des circuits d'approvisionnement. Bio ne veut pas dire sain (des chips bio, ça reste un aliment qui fait exploser le taux de sel dans ton corps, des céréales de petit déj' bio, ça reste un produit qui fait exploser le taux de sucre, une galette de patates du marché couvert, ça reste un aliment très gras, etc.), ni circuit court ni équitable (Biocoop, c'est une centrale d'achat comme une autre, donc y'a nécessairement un rapport de force avec les producteurs, et comme c'est opaque, il faut croire Bioccop sur parole quand ils disent qu'ils sont gentils).
Sans compter le faux comme la revente, dans le marché couvert, de produits industriels achetés en gros (raviolis, galettes de pommes de terre, etc.).
Sans compter le manque d'information : quelle farine est à l'œuvre dans ce pain artisanal ? Problème du gluten qui transforme le pain en non-sens alimentaire. Quels sont les ingrédients qui composent ce plat préparé du marché couvert ? Sel récupéré à la dynamite ou gratté mécaniquement au fond de l'eau ou récupéré manuellement en surface ? Etc. Faut avoir le cran de demander au commerçant, qui va soit te sauter à la gorge, soit embrouiller le novice que tu es, soit les deux.
Au final, j'ai l'impression de faire des efforts pour apprendre ensuite qu'ils sont vains voire contre-productifs. C'est super démotivant.
Évidemment, chacun a sa façon de cuisiner. Untel dit que mettre un peu de vinaigre blanc dans l'eau des œufs durs accélère la coagulation si jamais la coquille se fissure. Unetelle dit que c'est vain. Unetelle te dit qu'après utilisation, elle met du vinaigre blanc dans la poêle afin de dissoudre les sucs et rendre le nettoyage plus aisé. Tu essayes et… ça ne fonctionne pas. Difficile de se construire un avis éclairé.
Évidemment, y'a trouzemilles tutoriels sur le web et, évidemment, ils sont contradictoires entre eux (sur le temps de cuisson, par exemple) quand ils ne sont pas inutiles par leur imprécision (quel temps de cuisson ? Quel résultat stoppe la cuisson ?).
C'est un point commun avec l'informatique : énormément de tutoriels faux / vaseux. La différence, c'est que je détecte plutôt bien les tutoriels et informations vaseuses en informatique. J'ai une culture générale qui me permet de me faire un avis, de savoir que ce tuto ne peut pas aboutir ou qu'il aura telles conséquences néfastes ou qu'il est inutile de configurer ce composant car il n'est plus utilisé de nos jours, etc.
En cuisine, je comprends rien. Je ne comprends pas ce qu'on cherche à faire, le résultat à obtenir. Je ne comprends pas ce qui a fait la réussite d'une recette genre qu'est-ce qui fait que mes œufs au plat collent à la poêle ou non ? Y'a tellement de paramètres : quantité d'huile, température de la poêle, etc. Je ne pige pas les concepts de base comme le rôle de chaque aliment dans une recette (œuf = liant, tel autre aliment = émulsifiant, etc.), ou l'entre-croisement des différents modes de cuisson (genre j'ai cru piger qu'une poêle sans couvercle est une cuisson grille alors qu'avec un couvercle ça devient une cuisson vapeur ?) ou quand il convient d'utiliser tel mode de cuisson plutôt qu'un autre. Bref, je patine, je percute pas où je vais, quel événement marque l'aboutissement d'une étape de la préparation (battre des œufs, stopper la cuisson, etc.) ?, etc.
Cette expérience en cuisine m'a rendu encore plus intransigeant envers les personnes qui se plaignent que "c'est compliqué t'es trucs d'ordinateur !". Tes trucs de cuisine là, ça l'est tout autant, connard ! Pourquoi je devrais m'impliquer, faire des efforts et pas toi, connasse ?! Ces mêmes personnes qui exigent la plus grande indulgence quand tu leur expliques un concept relatif de près ou de loin à un ordinateur, mais qui n'hésitent pas à te chier à la gueule tout en t'humiliant bien comme il faut quand tu pines pas un truc relatif à la cuisine en mode "hahaha, quoi, tu ne sais pas ça ?!", "c'est quand même pas difficile !". Ben non, je ne sais pas, et alors ?
Sur ce point, je remercie beaucoup une collègue qui a pris le temps de m'expliquer les choses, de me rassurer, de m'initier. Je suis témoin que ça lui a coûté masse de temps de travail. D'abord, elle m'a expliqué qu'il ne peut pas s'passer grand-chose de mal avec une plaque de cuisson à résistances électriques (ouais, j'ai peur du feu, et notamment d'huile versée par mégarde sur le feu genre ustensile pas nettoyé, huile qui coule sur les parois de la poêle, etc.). Ensuite, elle m'a donné les premières recettes et les premiers temps de cuisson. J'ai lu les notices sur les produits, mais c'est souvent imprécis voire manquant. Plus tard, elle a répondu LMGTFY à mes demandes de recette tout en reconnaissant que son expérience lui permettait de détecter les recettes bidonnes, les temps de cuisson abusés, de trancher les recettes contradictoires, etc. Enfin, elle m'a incité à toujours plus voler de mes propres ailes, à avoir confiance, à y aller au ressenti, etc. Je me suis jamais senti humilié, et c'est cool, car c'est une condition nécessaire de l'apprentissage.
Ça m'a fait réfléchir : ça demande masse de temps, d'efforts (sans garantie) et de bienveillance, de guider quelqu'un dans ce qu'on croit être la bonne façon de faire. Ça explique pourquoi les alternatives (informatiques ou non) sont si lentes à prendre : une personne après l'autre, lentement, avec des rechutes.
Ça, c'est clairement un frein pour moi : le temps exigé par la cuisine.
Il faut faire les courses. Afin de me motiver à cuisiner, je m'étais fixé des contraintes cools genre acheter bio et/ou circuit-court. Comme on l'a vu dans la section précédente, ce n'est pas simple, mais, en plus, aller au marché en sus du Biocoop en sus du supermarché (car, comme j'suis un humain totalement élevé par l'industrie agro-alimentaire, je ne trouve pas tout ce que je veux au marché et à Biocoop), ça prend masse de temps : on part sur 3-4 h par semaine pour faire le tour des 3 lieux contre 45 min - 1 h pour aller au seul supermarché !
Il y a la préparation de la bouffe genre éplucher et couper les patates, égoutter les haricots verts en conserve, etc. et la cuisson. Avec ma plaque de cuisson, on parle de plus de 12 minutes pour faire bouillir de l'eau dans une casserole de 16 cm de diamètre ! Après, il faut attendre 7 minutes afin que les pâtes cuisent ! On est donc sur un total de 17 minutes pour faire de simples pâtes au beurre ! Je te parle même pas des raviolis du marché couvert pour lesquels on atteint 25 minutes au total… Et encore moins des lentilles (on est au-delà des 40 minutes). Mes collègues disent de faire d'autres trucs en parallèle, mais je n'y parviens pas : j'ai toujours peur de la catastrophe ou de rater le moment ou de… Surtout, je n'aime pas me faire interrompre dans une activité comme la lecture d'un article de presse ou la correspondance avec un ami.
Peut-être que je pourrais abandonner ma plaque de cuisson à résistances électriques pour autre chose, mais quoi ? La rapidité des plaques à induction m'a bluffé, mais elles sont incompatibles avec l'un de mes dispositifs médicaux. Cuisinière au gaz ? Pas la place, pas d'arrivée de gaz de ville, flemme de me trimballer des bouteilles. Sans compter ma peur du feu (là, les débordements d'huiles, qui arrivent très fréquemment avec moi, ne pardonneront plus).
Et puis il y a la vaisselle… Je la faisais jamais avant, je ré-utilisais la même assiette en boucle sans la nettoyer. L'écologie avant tout (sarcasme) ! Au début de mes aventures culinaires, je ne nettoyais pas l'huile qui restait au fond de la poêle, jusqu'à ce que mes collègues fassent un lobbying de folie sur la dangerosité de la chose sur la santé… Il faut donc nettoyer les ustensiles, la plaque (car, forcément, je fais toujours tomber quelque chose dessus…), le plan de travail (je n'ai pas de hotte aspirante, donc la graisse se dépose bien comme il faut sur le mur…), etc. Ça prend un temps et une énergie de fou.
Je ne sais pas comment font les gens. Vraiment. Moi, à la fin d'une journée de travail, je suis mort, mais vraiment. Préparer à manger, cela épuisait ma dernière réserve d'énergie, alors nettoyer la cuisine… Impossible… Faire la vaisselle juste après la cuisson est une mauvaise idée : la bouffe sera froide et je ne supporte pas ça. La faire après manger : les taches se seront déjà partiellement incrustées. Sans compter ma fatigue / flemme. Sans compter le pic de sommeil après l'ingurgitation de bouffe. Plein de fois, j'ai oublié de bonne foi de faire la vaisselle : je suis parti me coucher, épuisé, en l'oubliant, tout simplement. Le lendemain, forcément, la graisse s'est incrustée, il faut frotter d'autant plus, ça demande encore plus d'énergie… que je n'ai pas, donc je nettoie de moins en moins au fil du temps qui passe.
Plusieurs collègues m'ont expliqué que, pour tenir, il ne faut pas cuisiner à tous les repas, il faut cuisiner en plus grande quantité et mettre de côté. Je n'aime pas la nourriture froide, donc ça signifie que je devrais la faire réchauffer… soit au four à micro-ondes (et donc pourquoi s'faire chier à cuisiner, autant rester sur les plats préparés) soit en utilisant des ustensiles… qu'il faudra donc nettoyer…
Comme pour toute autre activité, je cherche à tirer un profit du temps passer à cuisiner.
Me faire plaisir ? J'ai jamais éprouvé de plaisir en mangeant. Je mange parce qu'il le faut, point. Me préparer à manger a rien changé à cet état de fait. Et l'action de faire soi-même n'est pas satisfaisante en elle-même, d'autant que j'arrive en fin de chaîne vu que j'utilise masse de produits transformés (riz, pâtes, galettes de patates, etc.).
Manger plus sainement ? J'ai un doute.
Rien dit que j'utilise moins de sel que dans un plat préparé, par exemple. Rien dit que je consomme des produits sains. Des nuggets de poulet industriels, consommés dans un kebab ou à la maison, ça reste du minerai de viande, c'est-à-dire du rebut de peau, tendons, etc. Rien dit que j'utilise moins de matières grasses non plus. J'ai même l'impression d'utiliser masse d'huile afin que l'aliment (notamment les œufs au plat, que je n'aime pas être percés par autre que mon couteau lorsque je m'apprête à les manger) ne collent pas à la poêle.
C'est d'autant plus vrai depuis que j'utilise une poêle en inox. Ben, ouais, il paraît que le Téflon c'est très vilain pas beau, donc une amie m'a offert une poêle en inox. Il faut dire aussi que, par manque d'entretien (voir section précédente), le fond et les parois de ma poêle en Téflon étaient recouverts d'une couche noire. Probablement de l'huile carbonisée et séchée. Vu que le côté récurant d'une éponge ne parvenait pas à retirer la couche, je l'ai grattée avec un couteau et j'ai dérapé, ce qui fait penser à cette amie et à mes collègues que j'ai égratigné le Téflon, ce qui est dangereux pour la santé, paraît-il. En attendant, il me faut masse d'huile pour faire des œufs au plat ou des galettes de patates dans cette poêle en inox…
Du coup, si cuisiner me prend masse de temps sans m'apporter ni plaisir ni me pourrir moins la santé, ça réduit quand même vachement l'intérêt de cette activité.
Je pense que ce mot résume bien mon état d'esprit vis-à-vis de la cuisine : désintérêt.
Même en pratiquant tous les jours pendant 4-5 mois, je n'ai pas mémorisé les temps de cuisson, les gestes, la durée de conservation réelle des aliments (parce que les dates affichées sont quand même bien du pipeau…), le calendrier saisonnier, etc.
Un collègue m'explique longuement la différence entre pasteurisation du lait et stérilisation UHT (je crois que la stérilisation est plus rapide mais qu'elle tue aussi des protéines de lait bonnes pour la santé), entre le sel et la fleur de sel (je ne sais plus la différence), les céréales complètes ou non (je crois qu'on conserve l'enveloppe des complètes, enveloppe qui contient des fibres et autres trucs sympas), la composition du curry (c'est un mélange d'épices d'où il existe plusieurs types de curry, mais j'imagine qu'il doit y avoir des épices communes à tous les types afin de donner la couleur et le goût approximatif), etc. et j'oublie tout…
Essayons de positiver : j'ai compris les expressions « surveiller comme le lait sur le feu » et « soupe au lait ». \o/ Le lait passe très rapidement de l'état calme / stagnant à l'état "j'ai débordé partout".
C'est peut-être pour ça que j'ai le sentiment de patauger, de rien comprendre, etc. : sans intéressement, rien est faisable.
Parlons un peu des trucs "drôles" qui me sont arrivés durant mes premiers pas en cuisine.
Je ne vais pas évoquer ma coupure au doigt avec un couteau à pain qui dérape ni celle en ouvrant une boîte de conserve ni mes mini-brûlures à répétition avec une poêle, car ça arrive aux meilleurs.
Un jour, en début d'aprem, un collègue me dit que je pue la friture. Je réponds que je me suis fait des galettes de patates le midi. Sujet clôt. Il revient à la charge un autre jour. Je ne porte pas les mêmes habits que depuis ma dernière préparation de popote. :O Ce n'est pas normal, tout ça, qu'il me dit. Un autre collègue approuve : il osait rien dire, mais je sens comme si je vivais dans un kebab. Ha. En discutant, ils comprennent que je mettais beaucoup trop d'huile dans la poêle (je faisais en sorte qu'un mince filet recouvre tout le fond et que la galette baigne dedans) et que je nettoyais jamais l'huile qui traînait au fond. Ma réaction ? « Bah on m'a dit de mettre de l'huile, je mets de l'huile moi ! :D ». Plus de remarque après avoir réduit la quantité d'huile. :D
Je veux me préparer de la semoule. Comme ça, pour manger en sus d'un bout de viande. Je respecte les proportions d'eau et de semoule indiquées sur la notice, mais la semoule ne gonfle pas. Je tente au four à micro-ondes. Toujours pas. Je remets pour un tour. Odeur bizarre. J'avais mis un couvercle en verre sur le bol. Une vis fixait l'embout (pour le saisir) au couvercle. Forcément, elle a chauffé et elle a fait fondre l'embout autour d'elle… Au final, j'avais acheté de la semoule fine. Celle-ci permet de confectionner des gâteaux, mais elle n'est pas l'équivalente de la grosse semoule, dite « à couscous » que l'on peut aussi manger comme plat principal (comme je le fais). Ça m'aura rappelé de faire attention au moindre détail de ce que l'on met dans un four à micro-ondes…
Il y a aussi eu un nettoyage foireux de ma plaque de cuisson à résistances électriques. Elle est extrêmement sale, donc je la nettoie avec du dégraissant en frottant avec insistance et véhémence. Sans que j'y prenne garde, le cadre se déclipse à l'arrière et une légère pente (ou descente, en fonction du point de vue) se forme. L'eau s'écoule, suit le câble électrique, remonte jusqu'à la plaque et… court-circuit, donc disjoncteur général désarmé… en pleine nuit. Au final, rien de grave : réarmer le disjoncteur, attendre 24 h que la plaque sèche, et tout re-fonctionne.
J'ai commencé à cuisiner (hors four à micro-ondes et mettre du thon dans une assiette avec de l'huile d'olives et du vinaigre, quoi) à partir de septembre 2019.
J'ai cuisiné varié pendant 4-5 mois avant de laisser tomber et de basculer dans des routines malsaines : nuggets de poulet industriels le midi + raviolis du marché couvert le soir puis galette de patates le midi + œufs au plat le soir. Je suis toujours dans cette deuxième routine tout en nettoyant très insuffisamment mes ustensiles. Comme mes anciennes routines alimentaires, rien de neuf.
Ce qui m'a le plus découragé, c'est le temps et l'énergie que cuisiner prend sans que j'y prenne plaisir ni que ça signifie que je mange plus sainement. Comme je ne prends pas plaisir à manger, je ne prends pas plaisir à cuisiner (je pense), ce qui n'aide sûrement pas à mémoriser les gestes, les temps de cuisson, etc. ni à comprendre ce que fait vraiment une recette (pourquoi cet assemblage précis d'aliments ?), ce qui ne simplifie pas les choses.
Après avoir regardé au fond de moi, j'en ai déduit que j'ai cuisiné afin d'en causer avec les collègues. Causer de trucs d'informatique ou de droit ou d'actualité, ça a jamais pris, alors que tout le monde parle cuisine. Ça faisait un sujet de conversation et d'intérêt. Mais, comme il n'existe pas une infinité de plats qui me plaisent un minimum, le sujet s'est tari, donc je n'avais plus intérêt à cuisiner, d'où j'ai laissé tombé pour du rapide et routinier.
Je ne conçois pas de pistes d'améliorations. :- Je pourrais réduire le temps des courses en achetant tout au supermarché plutôt que de cumuler marché + Biocoop + supermarché, mais la cuisson et la vaisselle prennent beaucoup plus de temps et d'énergie que les courses. C'est ça, le vrai point bloquant, à mon avis.
Puisque je n'aime pas manger, j'ai toujours dans ToDo, et ce depuis plusieurs années, de tester le subtitut alimentaire Soylent ou autres produits équivalents. Mais il faut commander via le web, c'est chiant et tout… Flemme. Et ça paraît tellement vaseux…
Depuis février 2018 (environ), je n'ai plus de téléphone portable. Enfin…
En 2018, mon téléphone mobile restait à la maison, mais il était allumé en permanence.
Depuis début 2019, il est dans un coin, batterie retirée.
Pourquoi me passer d'un smartphone ? Quels bénéfices ? Quelles limites ?
Je n'avais pas de téléphone fixe. Je n'utilise pas la ligne SIP fournie dans mon abonnement à Internet + téléphone + TV + … Je n'avais pas de ligne SIP sur mon ordinateur.
Mon téléphone mobile était toujours en silencieux (ni sonnerie ni vibreur).
J'utilisais peu de logiciels : ni réseaux sociaux, ni application de ma banque, ni jeux vidéos, ni service de diffusion de musique ni… L'écrasante majorité d'entre elles réclame des permissions inutiles et démesurées, fliquent leurs utilisateurs, tout ça pour être uniquement une encapsulation d'un site web qui fonctionne pourtant très bien depuis un navigateur web mobile. Un tel logiciel rend plus difficile le blocage des pisteurs et autres merdes présentes sur l'écrasante majorité des sites web.
Conséquence de ce qui précède : je ne vais pas parler des applications mobiles conçues pour piéger les utilisateurs dans différents biais cognitifs comme la peur de rater un événement, la récompense aléatoire procurée par le déroulement d'une timeline, les notifications incessantes pour garder le chaland en ligne, etc. Bref, de l'addiction et du détournement de l'attention. J'ai toujours désactivé les notifications de mon client emails, de mes différentes messageries instantanées, etc.
De même, j'ai jamais ressenti l'angoisse bien moderne d'être à court de batterie.
J'ai la flemme de remplacer mon téléphone défectueux.
En effet :
J'ai acheté d'occasion ce téléphone en mai 2017 et il était déjà foutu en 2018 !
Pour bien faire, il faudrait donc que je cherche un téléphone compatible LineageOS (c'est important, je veux avoir un minimum de contrôle, même si, en vérité, c'est la puce GSM qui commande, pas le CPU principal) avec une batterie amovible (c'est très important) d'occasion. Peu de modèles. Aller sur Le Bon Coin ou autre. Trouver un vendeur dans l'coin. Prendre rendez-vous. Se déplacer. Galérer à installer LineageOS. Un système pas à jour. Etc. Trop chiant, ça sera sans moi, merci.
Sans compter qu'aucun ordiphone répond à tous mes critères : logiciel libre jusqu'au bout (Replicant) ? Logiciel libre modéré (LineageOS, /e/) ? Logiciel libre et un minimum de contrôle matériel (Librem encore au stade expérimental, le mort-vivant Neo9000) ? Qu'apporte la possibilité de désactiver physiquement la puce GSM par rapport à une batterie amovible ? Matériel prétendument éthique (il y a que quelques mines de métaux rares autour de la planète, donc…) et facilement réparable (Fairphone) ?
Si tu crois percevoir un petit côté écolo dans ce qui précède, détrompe-toi : il est là uniquement pour masquer ma flemme.
Bref, le remplacement de mon ordiphone actuel a un coût, il faudrait que ce remplacement amène des bénéfices afin que le ratio bénéfice / coût soit positif et que je me motive à me sortir les doigts. Or, il y a aucun bénéfice. C'est ce que je vais détailler.
Très peu de personnes me contactaient par téléphone. En fait, il y avait mes parents et deux amis.
Je ne souhaite plus échanger avec mes parents car ils s'en foutent de ce que je raconte. Je pourrais leur dire que je me suis fait violer par un manchot unijambiste atteint du sida lors d'un déplacement pro en Afrique du Sud qu'ils me répondraient "ha, c'est bien ! Sinon, le voisin, ce con, tu sais pas ce qu'il a fait l'autre jour ?!". Ou alors ils parlent au chien. Ou alors je suis censé règler leur problème du moment parce que je « comprends les choses » (bizarrement, c'était pas le cas quand j'étais ado :)))) ). Merci, la vie du chien ou du voisin ou cracher sur l'état du monde sans être force de proposition m'intéresse assez peu.
Quant à mes amis, ils connaissent mon adresse emails. Le fait qu'ils veulent me causer uniquement quand ils sont aux chiottes ou dans les transports en commun (c'est le cas d'un des deux), c'est-à-dire pour "rentabiliser" des moments creux de leur vie, donne une idée de l'importance que j'ai à leurs yeux. De même, les conversations étaient très superficielles. Merci, mais non merci.
Dans ce contexte, un téléphone a un intérêt très réduit.
Le téléphone est un moyen de communication synchrone, ce qui impose la disponibilité simultanée des parties prenantes (dans la théorie, le SMS est asynchrone, dans la pratique, une réponse rapide est souvent exigée). Or, ce n'est pas à toi de décider de ma disponibilité. J'aime prendre du temps pour moi. Pour lire. Pour écrire. Pour rêvasser. Bref, pour me concentrer, faire avancer des choses et prendre du temps pour ma pomme. Je n'ai pas envie que tu foutes tout en l'air pour m'expliquer que ta vie c'est de la merde (je suis au courant, c'est le cas de toutes les vies). D'autant que je suis hyper lent pour reprendre mon activité, encore plus si ce que tu m'as dit me fait cogiter (ce qui est souvent le cas).
C'est pour cela que je ne veux pas non plus de téléphone fixe.
L'ordiphone avait un aspect hypnotique : bien qu'il était en silencieux, je regardais souvent si quelqu'un m'avait écrit / téléphoné. Peur de rater un truc ? Conséquence du dressage des darons pas contents quand on ne répond pas ? Trouver une échappatoire à une activité ennuyeuse ? Un peu de tout ça.
À chaque fois que l'écran indiquait un SMS ou un appel manqué, je ressentais une petite angoisse. Quelle merde allait encore me tomber dessus ? Quel service allais-je devoir encore rendre ? Qu'est-ce qui n'allait pas chez quelqu'un que j'apprécie (empathie) ? Je suis bien content de m'être débarrassé de cela. Les emails (hors listes de diffusion) me font également cet effet-là, mais comme j'en reçois quasiment aucun, c'est gérable.
J'arrive à conceptualiser deux solutions :
Ce qui m'intéresse, ce n'est pas d'échanger compulsivement mais intensément. Je veux échanger sur le temps long : « tu voulais faire ça, telle activité, tel projet, ça en est où ? T'as buté sur quoi ? ». C'est de l'expérience des autres que l'on apprend comment fonctionnent les choses (genre l'amie qui a rejoint une CAE afin de lancer son activité qui nécessite de respecter trouzemilles contraintes réglementaires…), que l'on découvre de nouvelles possibilités, que l'on rêve, que l'on envisage de nouvelles choses pour sa vie, etc.
Or, j'ai l'impression que ce type d'échange n'est pas le plus représentatif de ce qui se raconte par téléphone / SMS. Je trouve que le format "simple et court" des SMS est aussi peu adapté à cet usage que le format Twitter : le moyen de communication conditionne le message. Avec un appel, un SMS, une messagerie instantanée, on a tendance à se focaliser sur le présent, sur la contrariété du moment. Je constate que je parviens à faire abstraction de pas mal de choses lorsque j'écris un email ou un shaarli ou une lettre.
Ne parlons même pas de la frime permanente sur les réseaux d'asociaux.
J'ai l'impression que cela nous rend fainéants : nous peinons à lire de gros pavés et encore plus à en écrire. Mais peut-être que ça met en lumière un phénomène qui a toujours existé mais qu'on ne pouvait voir (à l'époque des Grecs ou de Rousseau une infime portion de la population savait écrire et avait la possibilité de s'émanciper du travail pour la rente) ?
Depuis mi-octobre 2020, je dois saisir un code reçu par SMS afin d'entrer dans mon espace sur le site web de ma banque. Demain, ça sera l'application mobile obligatoire pour ce faire. Je détecte cette tendance à l'application mobile un peu partout : carte vitale dématérialisée, carte de transports en commun dématérialisée, espèces dématérialisées, réservation des machines dans une salle de sport, etc.
Et ça, ça me donne envie de lutter contre la société qui va me chasser, me mettre à l'écart (car oui, rêve pas, ami libriste : ça sera un ordiphone verrouillé avec les services Google / Apple). J'aime avoir l'esprit de contradiction, encore plus pour que demeure vivante une alternative en attendant que les consciences se réveillent et/ou que les choses soient bien faites. On est à l'ère du tout-numérique dématérialisé pouet-pouet ? Je réclame du papier, du concret, du palpable. On peut solliciter n'importe quelle société commerciale ou administration par Twitter / email ? J'utilise des LRAR. Le nombre de distributeurs de billets diminue d'année en année ? Je tire encore plus d'espèces. Tant que ce n'est pas une privation douloureuse, je ne vois pas de problème.
Qu'est-ce que « les choses bien faites » selon moi ? Ne pas faire chier. Exemples : osef de valider le titre de transport à chaque voyage, on fait un vrai service public de transport urbain puis on arrête de compter ; Former à l'usage des gestionnaires de mots de passe et au phishing plutôt que de mettre en œuvre de la double authentification à la con. En matière de téléphonie : avoir plus de fabricants, imposer le découplage matériel / logiciel, imposer la vente de systèmes respectueux de l'utilisateur, lever les contraintes réglementaires sur les puces GSM, imposer une durée de vie minimale (avec mises à jour), etc.
Le contre-argument qui revient le plus, c'est : « OMG, mais comment tu gères les urgences ?! »
Simple : je n'ai pas d'urgences. Je n'ai pas d'astreintes professionnelles. Je n'ai pas fait l'erreur de forniquer avec une femelle en chaleur (de mes observations, il ne se passe pas une semaine sans qu'un parent se fasse téléphoner pour venir récupérer son lardon à la crèche / école parce que ceci ou cela). Je n'échange pas avec des proches mais si c'était les cas, je leur donnerai un conseil : si t'as besoin de soins immédiats, téléphone au SAMU / pompiers, pas à moi ! Si t'as besoin de protection, téléphone aux flics, pas à moi ! Tout le reste peut attendre.
Et si c'est une urgence dans la rue ? La loi de Murphy s'applique : la seule fois où ça m'est arrivé (grand-mère s'est cassée le bras en tombant dans la rue), je n'avais pas mon téléphone mobile. On trouve toujours un passant ou un commerçant qui veut bien prêter un téléphone (dans l'temps, il y avait les cabines téléphoniques, mais c'est plus d'actualité et elles étaient éparses).
Et si je suis en balade au milieu de nulle part ? Tant pis, pas la peine d'être un flippé de la vie, il faudra improviser, se débrouiller, être patient, etc. Inutile de se faire peur en exagérant un risque quasi nul…
On est dans une société de l'urgence, dans laquelle tout doit être fait rapidement, dans laquelle il faut se tenir à disposition d'autrui en permanence. Je dis stop. Mon agenda, ma temporalité m'appartient. Ma priorité, c'est moi. Le reste vient après. Beaucoup essayent de faire croire que leur gueule est prioritaire (genre le père qui te téléphone et râle que tu ne répondes pas car t'es dans les transports en commun, « un téléphone mobile c'est fait pour être joignable en permanence »). Pas grand chose est réellement urgent, il faut juste péter un coup.
J'avoue que j'ai encore beaucoup de mal à ne pas faire chier inutilement ceux qui ont un téléphone mobile. Là pour poser une question à un collègue alors qu'on est en pause et que ma question est tout sauf urgente, c'est juste moi qui en fait une urgence car je travaille actuellement dessus et j'aimerais bien torcher le sujet. Là pour prévenir un autre collègue durant notre pause qu'il y a tel évènement cet aprem donc qu'il faudra surveiller telle fragilité de l'infrastructure. Là pour demander des précisions à un collègue sur la commande de bouffe dont je suis l'intermédiaire. Tout ça peut attendre ou on peut faire sans (genre tant pis le collègue aurait eu du ketchup au lieu de sauce blanche, ça passe).
Le deuxième contre-argument est : « OMG, mais comment tu gères l'organisation / annulation d'une activité entre potes ? Surtout que t'as pas Facebook… ».
Simple : j'ai très très peu de potes en local et d'activités en dehors du taff. Et ça me va très bien.
Les personnes qui mettent des dizaines de minutes à concevoir de jolis plans "on se retrouve ici à telle heure, ha non ici en fait car y'aura les bouchons, ha non là en fait car il faut aussi qu'on passe chercher machin et…" qui fonctionnent jamais et qui sont changés à la dernière minute me gonflent au plus au point. J'ai pas envie d'assister à la réflexion, dis-moi où on se retrouve et tiens-toi-y, point.
J'ai l'impression que, sous prétexte d'avoir prévenu au dernier moment, les téléphones mobiles permettent de blanchir les retards à un rendez-vous, et, de ce fait, les multiplie. Je n'ai pas besoin d'un téléphone pour constater ton retard, je le constaterai, merci bien, et me prévenir au dernier moment, quand je serai déjà parti de chez moi, est inutile.
Je ne suis pas à ta disposition. Et quand je vois l'effet que provoque cette phrase sur mon interlocuteur, je me dis qu'il faut continuer dans cette voie-là, car beaucoup de personnes semblent prendre pour acquis que tout le monde doit être aux petits soins pour elles.
J'ai aussi arrêté le téléphone mobile afin de ne pas rejoindre le rang des connards (et connasses, la connerie est également répartie entre les sexes) qui :
Oui, au moins trois de ces comportements existent sans téléphone qui est alors une simple possibilité supplémentaire de faire chier son monde.
Oui, je suis d'accord qu'il faut éduquer les cons ou les fuir, avec ou sans ordiphone, mais c'est pas simple : ils sont nombreux + il vaut mieux mesurer 1 m 90 et être tout en muscles + on connaît tous des cons qu'on apprécie malgré tout.
Néanmoins, quand il y a autant de personnes concernées, toutes étant loin d'être connes et malpolies, j'ai du mal à croire que le smartphone n'influe pas sur les processus cognitifs.
Pour être en capacité de recevoir un appel / SMS, un téléphone mobile doit être connecté aux antenne-relais de l'opérateur mobile. Afin d'assurer le service durant un déplacement éventuel, il se connecte à plusieurs antennes. L'opérateur mobile sait donc où se trouve tel téléphone à telle heure, c'est de la simple triangulation. La conservation de cette information fait partie de ses obligations légales.
De même, les services Google déduisent la position d'un téléphone mobile à partir des réseaux Wi-Fi, ses voitures de cartographie (Street View) ayant scannées sans autorisation lesdits réseaux et conservé leur position GPS…
Les opérateurs de téléphonie doivent conserver le journal des SMS et des appels (qui téléphone à qui, quand, à quelle fréquence, combien de temps). Obligation légale. Reste à s'assurer qu'ils ne l'utilise pas à des fins marketing (vu que les mêmes veulent attenter à la neutralité du net afin d'engranger quelques dizaines de millions d'euros de bénéfices sur un bénéfice qui s'élève déjà à quelques milliards) ou pour d'autres motifs discutables.
À côté de ça, on a la mesure d'audience des panneaux publicitaires et les commerçants qui veulent nous renifler le cul dans la rue (exemple du projet de traçage Wi-Fi à Rennes) et dans leur magasin afin de toujours mieux nous fourguer leur merde.
Un smartphone correctement configuré permet également de maintenir une personne sous l'emprise d'une autre. Parent / enfant. Mari / femme. Localisation. Activation à distance du micro et écoute discrète. Un régal. Sans aller jusque-là, j'ai vécu le père+mari possessif auquel il faut toujours répondre, annoncer son heure de retour à la maison, gaffe au retard (t'as parlé avec qui ?), etc. Je sais que ce n'est pas drôle : t'as toujours l'impression d'être suivi / espionné. C'est d'ailleurs ce qui m'avait fait arrêter d'utiliser mon premier téléphone mobile, quand j'étais ado.
Néanmoins, cette fois-ci, j'ai l'impression que, si le flicage a été l'une des raisons pour ne plus apporter mon smartphone partout avec moi en 2018, il n'est plus mon moteur actuel. J'aspire plutôt à une tranquillité décrite dans les sections précédentes.
Le non argument qui revient est que je lutte contre l'air du temps, que l'Histoire montre que l'humain a toujours voulu propager l'information toujours plus vite : écriture, imprimerie, télégraphe, téléphone, internet, mobilité, etc.
Je pense surtout que le lien social est indispensable, y compris pour se raconter des conneries (rumeurs, trucs sans intérêts, etc.). Or, nos modes de vie et l'organisation actuelle de nos sociétés (emploi salarié 7 h par jour avec des collègues imposés, métropolisation, commercialisation de tout échange, etc.) ont amoindri sa qualité. Dans ce monde inconfortable, avoir nos amis et nos proches dans notre poche nous rassure, nous fait nous sentir moins mal… au détriment d'une lutte pour changer ces choses déplaisantes. Damasio nomme ça le techno-cocon : la prison si douillette qu'on s'y complaît.
Je pourrais me plaindre des connards qui te téléphonent pour te vendre de la grosse merde, mais je dois reconnaître qu'Éric Dampierre m'a rarement téléphoné sur mon 06… Pas suffisamment pour que je m'en souvienne, en tout cas. De toute façon, je ne réponds pas aux numéros inconnus.
Haha, tu m'as pris pour qui ?! Non, j'en ai rien à foutre des ondes des téléphones, le Wi-Fi des reptiliens du FBI de la terre plate m'a fait pousser une deuxième teub, donc j'en redemande.
Ne plus avoir mon téléphone sur moi à longueur de journée pendant 10 mois en 2018 a été extrêmement facile. Je traitais les SMS et les appels le soir. Aucun problème. Aucun impact. Aucun manque.
La première année sans téléphone du tout, 2019, a été plutôt facile. Le plus pénible a été de prendre des rendez-vous : se déplacer pour prendre un rdv, c'est chronophage, chiant, et fatiguant. Surtout quand tu veux prendre rendez-vous avec des professionnels qui ne communiquent pas (pas de site web) et qui ne sont pas à leur poste toute la journée / aux horaires habituels. Rien d'insurmontable, mais quand même, j'avoue que le gain de temps dégagé par la prise de rendez-vous par téléphone est très satisfaisant.
La deuxième année sans téléphone, 2020, a été compliquée. Elle a commencé par un enchaînement de problèmes médicaux. À ce moment-là, dans la douleur, tu oublies bien vite ton éthique, de te déplacer pour prendre rendez-vous, etc. Elle s'est terminée par la nécessité de saisir un code reçu par SMS afin d'entrer dans mon espace sur le site web de ma banque. Avant de céder, j'ai adressé une LRAR à ma banque afin de savoir si un dispositif de connexion alternatif existe : rien avant mi-2021. Au milieu, le développement d'une amitié m'a rendu moins strict, j'ai accepté qu'on se téléphone pour fixer des rendez-vous, du problème du jour, tout ça… J'ai également recommencé à solliciter mes collègues en étant absent de mon bureau. Cette mauvaise manière n'avait donc pas disparu.
Durant cette deuxième année, j'ai donc utilisé les téléphones fixes de mon travail. L'avantage, c'est que l'opérateur ne sait pas qui est derrière un numéro. J'administre notre serveur de téléphonie, donc je serai au courant d'une éventuelle demande d'association entre un numéro de téléphone + une date et une identité. Et si j'utilise le téléphone des salles de réunion, je suis quasiment intraçable. :)
Quand mon usage du téléphone pour émettre des appels s'est intensifié, j'ai souscrit une ligne SIP chez OVH que j'utilise sur mon ordinateur avec le logiciel Linphone. Pourquoi ne pas utiliser la ligne SIP de mon abonnement à Internet + téléphone + TV ? Car j'ai plus confiance en tonton Oles qu'envers les opérateurs téléphoniques dominants pour ne pas utiliser mes factures téléphoniques à des fins commerciales / pour pondre des bénéfices. Je ne suis pas aussi serein qu'avec un Fournisseur d'Accès à Internet associatif, mais c'est mieux que les opérateurs mobiles.
Contrairement à mon 06, je parviens très bien à lancer Linphone seulement quand j'en ai besoin. \o/ D'un autre côté, vu le peu d'occurrences, c'était pas difficile…
Si l'on résume la section précédente, les éléments perturbateurs qui m'ont fait utiliser mon téléphone en 2020 ont été (liste non ordonnée) :
Je reconnais aussi que quelques facilitateurs m'ont évité d'utiliser mon smartphone :
Après trois ans sans smartphone, je constate que je n'en ai pas besoin, sauf pour accéder à mon espace sur le site web de ma banque. Je constate que son absence a rien changé à ma vie, pas de manque, rien. En même temps, je n'étais pas drogué aux applications qui captent l'attention en permanence.
En revanche, je suis sceptique sur la possibilité de se passer d'un téléphone (tout court). J'y suis parvenu totalement une année, pas une deuxième. Si j'y parviens approximativement pour l'instant, je note que c'est la conséquence d'une vie solitaire. Dit autrement : je ne suis pas sûr que ça tiendra dans le temps.
Je vais continuer à laisser le smartphone à la maison, ça c'est certain. Il m'est d'aucune utilité à l'extérieur, sauf pour me fliquer.
Je vais devoir trouver un compromis sur l'utilisation du téléphone. Remplacer mon smartphone par une ligne SIP serait la meilleure idée (pas de SMS, appels sortants uniquement ou créneau téléphonique prévu, meilleure confiance envers OVH), mais ma banque ne le permet pas (un numéro de mobile doit impérativement être renseigné dans le dossier client afin de saisir un bénéficiaire de virement bancaire).
Du coup, il faudra réfléchir à un usage modéré de mon smartphone. Bloquer les gens avec qui je ne veux pas échanger afin de ne pas """"angoisser"""" / cogiter lorsque je reçois un groupe de SMS différés alors que je veux accéder au site web de ma banque (Free permet cela. On peut même bloquer toutes les communications sur des créneaux horaires / des jours) ? Réserver des créneaux pour causer par SMS / tél ? Cumuler échanges courts sans intérêt ("comment ça va ?") et échanges sur le long terme par emails / lettres ?
Je pourrais aussi mélanger smartphone (pour la banque) et ligne SIP pour le reste afin d'espérer un meilleur respect de ma vie privée.
J'ai lu 3 livres autour de ce sujet : Libérez-vous de votre smartphone, Cyberminimalisme et La civilisation du poisson rouge.
Le dernier se focalise essentiellement sur les mécanismes de captation de l'attention des réseaux d'asociaux et autres applications.
Le deuxième se concentre sur le numérique en général, il ne comporte pas spécialement de conseils concernant le téléphone (à part de ne pas en donner aux ados, de mettre le téléphone fixe de la maison dans une pièce à forte affluence afin que tout le monde surveille tout le monde, ce que je n'approuve pas).
Le premier est aussi orienté sur le détournement de l'attention par les réseaux d'asociaux. Les conseils sont bateaux : désinstaller les applications inutiles, désactiver toutes les notifications inutiles, suivre les usages des applis, posséder un téléphone sans appli, etc.). La description de ce que Korben ressentait (le trop-plein, l'angoisse, la pression) avant de freiner son utilisation de son smartphone est intéressante.
J'ai eu exactement le même message d'erreur quand j'ai tripoté la configuration TLS de mes serveurs emails.
Je cite :
Pour illustrer ça, une petite anecdote. La CPAM envoie des informations à l'ensemble des assurés ("ce que nous faisons pour vous durant le Covid", "attention à la campagne de phishing en cours", etc.). Pour cela, elle a recours à un prestataire, Worldline. Dans le journal de mon Postfix, je lis l'erreur TLS library problem: error:14094438:SSL routines:ssl3_read_bytes:tlsv1 alert internal error:../ssl/record/rec_layer_s3.c:1544:SSL alert number 80. Sur le web, on trouve aucune aide. Je suis revenu progressivement en arrière dans ma configuration TLS. Au final, Wordline refuse que je priorise les algorithmes d'échange de clés qui ne sont pas basés sur les courbes elliptiques par rapport à ceux qui les utilisent. C'est compréhensible : l'utilisation des courbes elliptiques est un gain de performance, donc de temps. Comme la CPAM n'envoie pas d'emails tous les jours (et que les emails relatifs à une question posée via l'espace personnel emprunte un autre circuit), cette compréhension du problème m'a pris trois mois. Bref, ne fais pas n'importe quoi et surveille tes journaux pendant plusieurs mois.
=> Du côté de ton serveur web, dans la liste des suites de déchiffrement autorisées (« SSLCipherSuite », « ssl_ciphers » ou équivalent), t'as dû mettre EDH avant EECDH.
ÉDIT DU 31/12/2020 À 22 h 30 : un p'tit coup de Wireshark permet de constater que ton serveur ferme la connexion immédiatement après le Client Hello, ce qui signifie qu'il y a quelque chose qui lui déplaît. Si l'on regarde viteuf, on se rend compte que Dillo ne positionne pas le SNI. Si l'on utilise openssl s_client -connect dukeart.netlib.re:443 -4 -tls1_2 -noservername
pour vérifier, on tombe sur l'erreur que tu mentionnes « 139676830008448:error:14094438:SSL routines:ssl3_read_bytes:tlsv1 alert internal error:../ssl/record/rec_layer_s3.c:1544:SSL alert number 80 ». Pour moi, la faute est du côté de Dillo : ne pas implémenter SNI en 2020 est une hérésie. Je l'ai utilisé que 15 minutes, mais j'ai l'impression que tout est foireux dans Dillo : pas de SNI, vérification buguée du nom du serveur avec le CN du certificat x509, une fois sur deux reload ne reload pas le site web, absence d'ergonomie de la barre d'adresses… Waaaah waaaah waaaaaah ! FIN DE L'ÉDIT.
Résumé : sur un seul serveur GNU/Linux, comment surcharger l'emplacement du dossier personnel ($HOME) récupéré dans un annuaire LDAP ? Il ne faut pas ré-écrire la valeur de la variable $HOME avec PAM, car cela causera des dysfonctionnements des logiciels / commandes qui récupèrent l'emplacement du dossier personnel avec la fonction C getpwuid()
qui utilise NSS. Il faut jouer avec NSS / SSSD / NSLCD. Néanmoins, si les dossiers personnels sont situés dans plusieurs arborescences en fonction de l'identifiant de l'utilisateur, alors je n'ai pas trouvé de solution. Encore une fois, toute cette aventure permet de se remémorer les bases d'un système GNU/Linux.
D'une manière générale, deux espaces de stockage sont à la disposition de nos utilisateurs : leur dossier personnel ($HOME) et leurs données.
Nous avons également un serveur Debian GNU/Linux sur lequel tous nos utilisateurs peuvent se connecter en SSH et déposer des pages web (entre autres choses). Authentification LDAP. Sur ce serveur, c'est l'espace de stockage pour les données qui est monté en tant que dossier personnel, pas l'espace personnel. Pourquoi ?
Sur notre ancien NAS, les données étaient rangées de telle façon que le chemin est identique entre les données et le dossier personnel, seul le volume / partage change. Du coup, c'est bien les données, et non pas les homedirs, qui sont montées aux emplacements désignés par l'attribut LDAP « homeDirectory ».
Sur notre nouveau NAS, ce n'est pas le cas, car nous sommes limités par la grammaire des règles de tri automatiques (pour des raisons de performances) de notre nouveau NAS. Le dossier « données » d'un utilisateur est en fait un sous-dossier d'un dossier qui peut prendre le nom d'un hash ou celui du groupe auquel appartient l'utilisateur (son service, par exemple) ou l'année d'arrivée de l'utilisateur, etc. Les données ne sont pas toutes au même endroit. Les dossiers personnels le sont. Il n'y a plus équivalence entre le chemin du dossier personnel et le chemin des données. Il n'y a même pas le niveau hiérarchique (pas le même nombre de sous-dossiers depuis la racine) entre le homedir de deux utilisateurs.
Le chemin est prédictible à partir de l'identifiant de l'utilisateur.
Des liens symboliques ne sont pas la solution car tous les homedirs sont dans un même dossiers et les données dans X dossiers. Il faudrait donc autant de liens que d'utilisateurs, et faire vivre cette forêt de liens en tenant compte des arrivées et des départs des utilisateurs.
Comment faire pour continuer à monter les données personnelles à la place du dossier personnel avec notre nouveau NAS ?
La première idée est d'utiliser PAM afin qu'il surcharge la variable $HOME. Une recherche sur le web indique que cela se fait en modifiant le fichier /etc/security/pam_env.conf
. La doc' est ici.
Vu qu'il s'agit d'un fichier plat et non d'un script, ça ne répond pas au besoin par absence de gestion des différents emplacements du dossier personnel en fonction de l'identifiant.
De plus, pour que ça fonctionne, il faut faire un disgracieux cd ~
dans /etc/profile
.
On notera également que cette méthode ne bernera pas les environnements de bureau : les applications lancées par celui-ci risquent de ne pas avoir le bon $HOME. Dans mon cas, le serveur est uniquement accessible en SSH, donc ce point n'est pas limitant.
pam-script est un module pour PAM qui permet de lancer des scripts aux différentes étapes de PAM (authentification, ouverture de session, fermeture de session, etc.). On pourrait s'en servir pour surcharger la variable $HOME ?
Après test, je peux affirmer que non. Les variables définies / surchargées dans un script pam-script ne sont pas conservées. Même si l'on s'assure, via /etc/pam.d/common-auth
, de lancer pam-script en dernier afin de s'assurer qu'un autre module PAM n'écrase pas la variable.
PAM propose la fonction pam_putenv(). Écrivons un module PAM qui utilise cette fonction afin de surcharger la variable $HOME.
Mes dérives par rapport au tutoriel :
pam_putenv(pamh, "HOME=/home/testpam/bidule");
;libpam0g-dev
donc il faut qu'il soit installé ;gcc -fPIC -DPIC -shared -rdynamic -o pam_ignore.so pam_ignore.c
;/lib/security/pam_ignore.so
;session required pam_ignore.so
à la fin du fichier /etc/pam.d/common-session
. Il faut ajouter à la fin afin de s'assurer qu'un autre module n'écrase pas la variable $HOME.Pour tester, j'utilise su -
et su - <utilisateur_que_je_crée_pour l'occasion>
en ayant créé le dossier /home/testpam/bidule
au préalable :
$ su - testpam
Mot de passe :
$ pwd
/home/testpam
$ echo $HOME
/home/testpam/bidule
Cela fonctionne, mais il faut à nouveau user d'un disgracieux cd ~
dans /etc/profile
…
Même sans ça, je n'adopterai pas cette solution. Avec PAM, on peut se faire très mal niveau sécurité. Il faut vraiment savoir ce que l'on fait et tester tous les cas d'usage. Nous avons un petit système d'information, rien justifie une telle bidouille et sa complexité (écrire un module PAM pour un problème si banal, allô !). Il doit exister une réponse plus simple à notre problème.
Pourquoi faut-il ajouter cd ~
dans le fichier /etc/profile
pour que le shell se positionne dans le dossier que l'on définit dans $HOME ?
Quelque chose instancie notre shell dans le « vrai » dossier personnel sans tenir compte de notre falsification.
Pour tenter de l'identifier, j'ajoute le bout de code suivant dans la fonction « pam_sm_open_session() » de mon module PAM (il affiche un message + le dossier courant de travail) :
char cwd[PATH_MAX];
if (getcwd(cwd, sizeof(cwd)) != NULL) {
printf("Coucou depuis PAM : %s\n", cwd);
}
else {
perror("getcwd() error");
return 1;
}
Dans /etc/passwd
, je change le home directory de mon utilisateur de test pour un emplacement qui n'existe pas, « /home/testpamFAIL ».
$ su - testpam
Mot de passe :
Coucou depuis PAM : /home/guigui
su: warning: cannot change directory to /home/testpamFAIL: Aucun fichier ou dossier de ce type
Le déplacement dans le home directory se fait après l'exécution de PAM. Comment ? su -
doit probablement interroger NSS qui, lui, est configuré (/etc/nsswitch.conf
) pour consulter /etc/passwd
ou LDAP ou… Comment s'en assurer ?
$ whereis su
su: /bin/su /usr/share/man/man1/su.1.gz
$ strings /bin/su | grep -E '(getpwuid|chdir)'
getpwuid
chdir
La fonction de la libc getpwuid() récupère les infos d'un utilisateur via les bases de données (LDAP, /etc/passwd, etc.) configurées dans NSS.
La fonction chdir() change le dossier de travail d'un processus.
Ces deux fonctions sont mentionnées dans le code de su
. Ça ne prouve pas qu'elles sont appelées, mais avec le message ci-dessus, ça donne un sacré indice.
Et avec SSH, il se passe quoi ?
$ ssh testpam@::1
testpam@::1's password:
Could not chdir to home directory /home/testpamFAIL: No such file or directory
Coucou depuis PAM : /
Last login: Tue Dec 29 22:16:46 2020 from ::1
$
Le déplacement dans le dossier personnel se fait avant l'invocation de PAM. Un home directory positionné à « / » est caractéristique du comportement de sshd
en l'absence d'un homedir.
$ whereis sshd
sshd: /usr/sbin/sshd /usr/share/man/man8/sshd.8.
$ strings /usr/sbin/sshd | grep -E '(getpwuid|chdir)'
getpwuid
chdir
[…]
Could not chdir to home directory %s: %s
[…]
Avec ce message d'erreur mentionné dans le binaire, le doute n'est plus possible : c'est bien sshd
qui récupère le home directory via NSS et fait apparaître un shell dans cet emplacement.
Cela signifie qu'il est vain de modifier la valeur de la variable $HOME depuis PAM.
Il est tout aussi vain de chdir()
depuis PAM : ce n'est pas lui qui lance le shell, donc ça aura aucun effet.
Tous les logiciels qui utilisent la fonction getpwuid()
ne seront pas dupés par une surcharge de la variable $HOME. Genre ssh
pour récupérer sa configuration dans ~/.ssh/config, vim
pour choper .vimrc
, etc. Cela entraînera des dysfonctionnements. Or, il y a un petit paquet de logiciels courants en ligne de commande qui utilisent getpwuid()
:
$ for file in /usr/bin/*
> do
> strings $file | grep -q getpwuid && echo $file;
> done | wc -l
314
Conclusion : si l'on veut trafiquer / surcharger / faker l'emplacement du dossier personnel, il vaut mieux agir côté NSS.
Avec libnss-ldap (prise en charge de LDAP par NSS), on peut utiliser /etc/libnss-ldap.conf
(ou /etc/ldap.conf) pour substituer un attribut LDAP à un autre (« nss_map_attribute ») ou ré-écrire / surcharger la valeur d'un attribut LDAP (« nss_override_attribute_value »). Documentation.
On peut faire pareil avec SSSD (démon pour une authentification centralisée + mise en cache via un framework commun) : « override_homedir ». Les jokers (%u = identifiant, %d = domaine, etc.) autorisés sont précisés dans la doc'.
Idem avec nslcd (démon qui s'interface entre NSS et un serveur LDAP) : « map MAP ATTRIBUTE NEWATTRIBUTE ». Les jokers autorisés (plus nombreux que ceux de sssd) sont également précisés dans la documentation.
Toutes ces solutions ont le même défaut : elles autorisent quelques substitutions (jokers), mais ça ne permet pas de répondre à notre besoin d'une fluctuation de l'arborescence de stockage des homedirs en fonction de l'identifiant.
On pourrait remplacer (mapper) l'attribut LDAP « homeDirectory » par un autre attribut LDAP, mais il faudrait modifier notre nuée de scripts d'importation des comptes utilisateur depuis le logiciel RH. Tout ça pour un seul serveur… Démesuré + long à entreprendre + pénible à maintenir (une exception de plus…).
Au final, sur ce serveur, nous avons monté les dossiers personnels en tant que homedirs (nous ne montons plus les données personnelles à la place du homedir, quoi). Cela fait 6 mois que c'est en place et personne nous a signalé un conflit entre des fichiers de conf' Ubuntu et Debian.
J'ai découvert la grande flexibilité du module userdir d'Apache httpd : le site web d'un utilisateur n'est pas obligatoire situé dans son dossiers personnel. Ainsi, les sites web continuent à être stockées dans les données et nos utilisateurs peuvent y accéder depuis n'importe où en CIFS.
Un script lancé par pam-script crée un lien symbolique vers les données dans le dossier personnel et la doc' utilisateur a été mise à jour afin que les utilisateurs ne soient pas perdus.
Mon script pam-script crée aussi le dossier personnel s'il n'existe pas. Je n'utilise pas le module PAM pam_mkhomedir car il n'applique pas le umask qu'on lui donne en paramètre. De plus, PAM est exécuté avec les droits root, donc il tente de créer le homedir avec ces droits-là, et se fait refuser l'accès par le NAS (seul un utilisateur peut écrire). Mon script exécute un sudo -u "$PAM_USER" mkdir "$HOMEDIR"
.
Je retiens qu'il faut être prudent quand on joue avec pam-script car on peut ouvrir un serveur à tous les vents par mégarde et que la configuration par défaut empêche de changer un mot de passe (même root).
Merci Johndescs pour le coup de papatte. :)
Résumé : si, au boot d'une machine dont le support de stockage est totalement chiffré, cryptsetup
affiche l'erreur « error while loading shared libraries: libcryptsetup.so.4 » (variantes avec libgcrypt.so.20 et libgpg-error.so.0), vérifie que le paquet logiciel cryptsetup-initramfs
est bien installé et réinstalle-le le cas échéant.
Mes serveurs perso ont 315 jours d'uptime. Je décide de les redémarrer. Ça permet d'appliquer entièrement les mises à jour de sécurité et de se prémunir contre un redémarrage inopportun / forcé à un moment où on n'aura pas le temps de corriger un éventuel problème.
Sur celui dont tout le disque dur est chiffré (sauf /boot), je teste la passphrase, je vérifie que l'accès VNC distant est fonctionnel, je reboot
, et là, c'est le drame : /sbin/cryptsetup: error while loading shared libraries: libcryptsetup.so.4: cannot open shared object file : No such file or directory
. Une saisie correcte de la passphrase se termine en « cryptsetup failed, bad password or options? ».
Une recherche sur le web donne rien de satisfaisant.
Il s'agit d'un VPS OVH, donc je tente le mode rescue. Le mot de passe est envoyé par email. L'email de contact de mon compte OVH est géré par le serveur qui ne démarre plus… Néanmoins, le mot de passe du mode rescue est affiché sur la console VNC (KVM). \o/ Le clavier est en qwerty, donc je mets trop de temps à saisir le mot de passe, donc l'écran se rafraîchit et le mot de passe disparaît. Note pour la prochaine fois : prendre une capture d'écran du mot de passe. Je redémarre la machine avec ctrl+alt+suppr. Je me retrouve à nouveau sur le cryptsetup foireux. Je demande à nouveau de démarrer en mode rescue. L'interface web crache « Une erreur est survenue lors de la demande de réinitialisation du mot de passe. ». Plusieurs fois.
Je joue un peu avec l'accès VNC distant. J'atterris dans un initramfs. WTF ?! Je croyais que ce comportement avait pris fin en 2016, quand on avait estimé qu'il s'agit d'une faille de sécurité. Bon ben… tant mieux.
cryptsetup luksOpen /dev/sda2 sda2_crypt
crache directement l'erreur sus-mentionnée sans même demander la phrase de passe.
Sur une autre machine Debian 10 avec disque dur chiffré, apt-file search
ne trouve pas libcryptsetup.so.4 dans un quelconque paquet logiciel. Un sudo find / -iname 'libcryptsetup.so.4'
la trouve dans /usr/src/initramfs/lib/x86_64-linux-gnu/libcryptsetup.so.4. Si tu ne l'as pas, il faudra la récupérer dans le paquet logiciel distribué dans la version Stretch de Debian.
Je configure la pile IP. Le manager d'OVH ne semble pas exposer les paramètres (masque, routeur, etc.) donc je sors /etc/network/interfaces de mes sauvegardes. Je sors sur le net. \o/ Toutefois : pas de /etc/resolv.conf donc pas de résolution DNS.
Je récupère la bibliothèque de fonctions manquante avec wget
depuis l'un de mes serveurs web pour la mettre dans /lib/x86_64-linux-gnu
. Pas de DNS dans l'initramfs, donc, ça nécessite un serveur web avec un hôte virtuel qui écoute pour tous les noms possibles.
cryptsetup
se plaint désormais de l'absence de libgcrypt.so.20. Je la wget
. Désormais, l'objet de la plainte est libgpg-error.so.0. Je la récupère.
cryptsetup luksOpen /dev/sda2 sda2_crypt
fonctionnee. \o/
Je quitte initramfs (exit
), le serveur démarre. \o/
IPv6 ne fonctionne pas. C'est normal : j'ai monté l'interface dans initramfs eet je lui ai affecté une adresse IPv4, donc ifup
échoue et ne traite donc pas le bloc « inet6 » du fichier interfaces. Pour m'en assurer, je reboot
… tout en comprenant immédiatement ma connerie : je n'ai pas réparé l'initramfs, celui stocké sur le disque dur, donc ça ne va pas démarrer… Je recommence la configuration IP et le téléchargement des bibliothèques manquantes…
Les paquets logiciels libgpg-error0, libgcrypt20 et libcryptsetup12 (nouvelle version de libcryptsetup.so.4 arrivée avec la version Buster de Debian) sont installés (sinon je n'aurais pas pu tester la passphrase avant de redémarrer). Pour rappel : apt-file search
permet d'identifier le paquet logiciel qui contient un fichier précis.
Reconstruisons l'initramfs avec update-initramfs -uk 4.19.0-13-amd64
. Vérifions avec lsinitramfs /boot/initrd.img-4.19.0-13-amd64 | grep libcryptsetup
: aucun résultat, la bibliothèque n'a pas été incorporée à l'initramfs.
Je décide de réinstaller les paquets logiciels de la forme « cryptsetup » : apt-get install --reinstall cryptsetup cryptsetup-bin cryptsetup-run
. apt-get
m'informe que le paquet cryptsetup-initramfs (dont dépend le paquet cryptsetup) n'est pas installé et qu'il va l'installer. Ooook, tout s'explique !
Après l'installation de cryptsetup-initramfs, lsinitramfs
nous confirme que libcryptsetup.so.20 est bien présente dans l'initramfs. \o/
Un reboot
fonctionne parfaitement. \o/
Au final, à quelle ocassion le paquet cryptsetup-initramfs a-t-il été désinstallé ? Aucune idée, /var/log/dpkg.log
n'en dit pas un mot. libgcrypt20 et libcryptsetup12 ont été installées le 14/02/2020, date à laquelle j'ai mis à jour de Stretch à Buster. libcryptsetup4 a été supprimée ce jour-là. Le système a correctement redémarré le 16/02/2020, c'est /var/log/kern.log
qui l'affirme, mais un calcul "28/12/2020 - 315 jours d'uptime" permettait d'avoir une estimation.
Résumé : si t'as un site web de diffusion de vidéos qui utilise Django et videojs, que les vidéos sont longues à charger voire que les longues vidéos sont remplacées par une erreur « The quota has been exceeded », vérifie que ton frontal Apache httpd ne proxifie pas les requêtes HTTP portant sur les vidéos à l'application Django car ce dernier ne prend pas en charge le contenu partiel (entête HTTP « Range »). Profite-en pour surcharger la variable « DEBUG » dans settings_local.py, car elle veut True par défaut…
Nous avons un site web qui diffuse des vidéos. Il s'agit d'un logiciel Python Django derrière un serveur d'applications uwsgi derrière un frontal Apache httpd.
Quand une vidéo dépasse 20 mo (environ), elle n'est pas jouée et l'erreur « The quota has been exceeded » s'affiche à la place. Avec Firefox, car Chromium affiche rien. La console des outils de développement affiche « VIDEOJS: ERROR: (CODE:-3 undefined) The quota has been exceeded. Object { code: -3, type: "APPEND_BUFFER_ERR", message: "The quota has been exceeded.", originalError: DOMException } video.js:128:5 ».
Sur une vidéo plus petite, l'onglet réseau des outils de développement montre que le chargement de la page s'est effectué en 52 secondes, et qu'un fichier vidéo de 16 Mo a été récupéré. La lenteur est le deuxième problème signalé par nos utilisateurs. Forcément, si le navigateur web charge l'intégralité de la vidéo avec un débit pas top…
Sur le web, on trouve ces erreurs dans des tickets sans solution ici ou là.
La collègue développeuse change le code du logiciel pour que ffmpeg
découpe chaque vidéo en fragments (dit autrement : virer l'option « -hls_flags single_file »). Hop, plus d'erreur et la page web se charge en 600 ms. En parallèle, elle interroge les devs de l'application et la communauté : comme d'hab, personne a ce problème.
En fait, ce découpage des vidéos ne fonctionne pas avec Safari qui continue de lire en boucle les deux premières secondes de la vidéo comme quand les vidéos n'étaient pas découpées.
C'est ici que j'arrive. Je trouve bizarre que les vidéos longues ne fonctionnent pas chez nous alors que ça marche chez les autres utilisateurs du logiciel.
À ce stage on a éliminé l'applicatif des causes potentielles (sa configuration reste une cause potentielle).
Un collègue nous donne une piste : le serveur ne gère pas l'entête HTTP « Range » dans les requêtes, alors que les vidéos sont distribuées sous forme de listes de lecture (playlists) indiquant une série d'intervalles de deux secondes au sein d'un même fichier.
En effet, nos listes de lecture (générées par ffmpeg
) ressemblent à ça :
#EXTM3U
#EXT-X-VERSION:4
#EXT-X-TARGETDURATION:2
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-PLAYLIST-TYPE:VOD
#EXTINF:2.000000,
#EXT-X-BYTERANGE:178412@0
360p.ts
#EXTINF:2.000000,
#EXT-X-BYTERANGE:211312@178412
360p.ts
[…]
Fragments de deux secondes (EXTINF). Le premier fragment commence à l'octet 0 du fichier 360p.ts et occupe 178412 octets. Le deuxième commence à l'octet 178412 du fichier 360p.ts et occupe 211312 octets.
Un test avec curl
confirme cette analyse :
$ curl -s -o /dev/null -D - -r 1315624-1562279 https://monorganisation.example/media/videos/ef2218bee799524931d2af11aafc3933e5d7413da2989b70fc94a9941fcd50e1/666/720p.ts
HTTP/1.1 200 OK
Date: Wed, 30 Sep 2020 17:10:42 GMT
Server: Apache/2.4.25 (Debian)
Content-Language: fr
Last-Modified: Wed, 16 Sep 2020 14:19:04 GMT
X-Frame-Options: EXEMPT
Vary: Accept-Language,Cookie
Content-Type: video/MP2T
Content-Length: 16929400
Cache-Control: max-age=0, no-store
Accept-Ranges: bytes
Le serveur nous a répondu avec le code HTTP retour 200 au lieu du 216 Partial Content, ce qui signifie qu'il ignore l'entête « Range ». On notera également que la taille annoncée (« Content-Length ») est la totalité du fichier et que l'entête « Content-Range » (qui rappelle la plage demandée sur la taille totale) est absent. On notera que MDN se trompe : la présence de l'entête « Accept-Ranges » ne suffit pas pour garantir qu'un serveur web honore bien l'entête HTTP « Range ».
Je sèche : la prise en charge du contenu partiel par les serveurs web est vieille… C'est grâce à cela que les gestionnaires de téléchargement, qui ouvrent plusieurs téléchargements simultanés d'un même fichier sur des plages d'octets différentes et qui proposent la reprise d'un téléchargement interrompu, fonctionnent. C'est forcément géré nativement par Apache httpd. Une recherche web et un essai sur plusieurs de nos serveurs me confirment cela.
À ce stade, le serveur web est éliminé. Reste sa configuration.
Dans certains résultats de recherche, on préconise d'ajouter l'entête « Accept-Ranges » ou « Range » avec le mod_headers… Ça a aucun sens (à ce stade, le traitement de la requête est terminé, Apache httpd a déjà répondu qu'il ne prenait pas en charge « Range » + « Range » est un entête de requête, pas de réponse, et le navigateur web la positionne déjà et il n'est pas retiré en chemin…), et, de toute façon, ma collègue a déjà tout tenté avec l'ajout d'entêtes, me dit-elle.
Je teste avec curl
: nos autres serveurs Apache httpd prennent en charge « Range ». Ils sont en version 2.4.25, comme le serveur problématique. À l'exception de l'hôte virtuel, toute la configuration est celle par défaut de Debian.
Le serveur est récent donc on ne mitige pas la vulnérabilité CVE-2011-3192 puisqu'elle est corrigée dans le code depuis longtemps. De même, Debian n'incorpore pas une directive MaxRanges restrictive.
À ce stade, la configuration du serveur web est éliminée, à l'exception du virtual host.
L'application est livrée avec une configuration (hôte virtuel) nginx. Le chef de mon équipe avait demandé à la collègue (d'une autre équipe) d'utiliser Apache httpd au motif qu'on avait uniquement des httpd, qu'on n'avait pas le temps pour s'éparpiller et monter en compétence sur un autre logiciel, etc. Je trouve ça comique, le "si tu utilises nginx => pas d'aide de notre part ; si tu utilises apache => débrouille-toi pour faire l'intégration de l'appli". Je teste nginx et la configuration fournie par le projet sur le serveur de test : ça marche directement.
Si Apache httpd gère nativement le contenu partiel et si ça fonctionne de base avec nginx avec la configuration fournie par l'application, ça signifie qu'il y a une erreur dans la configuration de l'hôte virtuel pour Apache httpd conçue à partir de la conf' nginx fournie. Je relis, je compare avec la version nginx, et… bingo ! On a oublié d'exclure le chemin « /media » de la liste des chemins qu'il ne faut pas proxifier vers l'application Django.
Évidemment, il y avait aucun indice dans le journal Django. Quant à lui, le journal uwsgi mentionnait juste une requête reçue, qu'elle a été traitée en tant de temps, etc. Rien qui soit de nature à m'alerter.
Donc les requêtes sur les fichiers vidéos sont proxyfiées vers l'application Django. Le chemin vers lesdites vidéos est routé (on constate cela dans le fichier url.py du site web)… Mais Django ne prend pas en charge nativement le contenu partiel… Tout s'explique.
Au final, il faut ajouter ces directives dans l'hôte virtuel Apache httpd afin que toutes les requêtes portant sur /media (et en dessous dans l'arborescence) ne soient plus redirigées vers l'application web :
Alias /media /chemin/vers/les/medias
<Location /media>
ProxyPass !
</Location>
<Directory /chemin/vers/les/medias>
Require all granted
</Directory>
On recharge la conf' avec systemctl apache2 reload
, et hop, ça fonctionne :
$ curl -s -o /dev/null -D - -r 1315624-1562279 https://monorganisation.example/media/videos/ef2218bee799524931d2af11aafc3933e5d7413da2989b70fc94a9941fcd50e1/666/720p.ts
HTTP/1.1 206 Partial Content
Date: Wed, 30 Sep 2020 17:19:31 GMT
Server: Apache/2.4.25 (Debian)
Last-Modified: Wed, 16 Sep 2020 14:19:04 GMT
ETag: "1025278-5af6ef32e144b"
Accept-Ranges: bytes
Content-Length: 246656
Cache-Control: max-age=0, no-store
Content-Range: bytes 1315624-1562279/16929400
Content-Type: video/MP2T
Pour être exhaustif, /media est routé par Django uniquement si la variable de configuration « DEBUG » a la valeur « True ». C'est effectivement sa valeur par défaut dans le fichier settings.py. Nous ne la surchargeons pas dans le fichier settings_local.py. Il s'agit d'une erreur, désormais corrigée.
Au final, on a migré vers nginx afin d'être dans les pré-requis de l'application, ce qui permet de demander de l'aide plus facilement. De plus, une fonctionnalité de ce logiciel nécessite impérativement nginx (Apache httpd n'a pas d'équivalent), donc autant harmoniser la plateforme en installant nginx partout.
Je retiens assez peu d'éléments techniques. Je retiens surtout un défaut récurrent de notre organisation de travail. Notre équipe d'adminsys et notre équipe de devs auraient dû travailler ensemble sur ce point plutôt que de se renvoyer la balle "c'est ton périmètre, démerde-toi". Au final, c'est ce qu'on a fait car j'ai mis mon nez dedans, mais on a perdu du temps et de l'énergie (tenter de comprendre, modifier le code de l'application pour diviser les vidéos en fragments, ré-encoder les vidéos existantes, comprendre, retirer les patchs du code, ré-encoder les vidéos afin de virer les fragments, etc.). Après ça, la méta-équipe qui regroupe les deux sus-citées peut bien se nommer « devops » et notre DSI peut bien pavoiser partout qu'on est devops et faire des causeries sur le sujet. On n'est même pas au premier stade de la collaboration, celle, élémentaire, qui existe depuis bien avant le bullshit devops. Bien sûr, on me répondra que c'est facile de dégainer sur un seul exemple, ça veut rien dire, ce n'est pas représentatif, tout ça. Mais quand je dégaine plusieurs exemples, on me rétorque que je suis méchant, que j'accable les personnes. :))))
RabbitMQ est une dépendance d'un logiciel que nous utilisons, donc, forcément, j'ai dû regarder koi ke s'est. Ce shaarli a plus vocation à conserver ce que j'ai compris de RabbitMQ que de t'apprendre des trucs.
RabbitMQ est un courtier en messages (message broker). Il permet à des processus et à des logiciels distincts de s'échanger des messages à travers un réseau (oui, ça fonctionne aussi en local, mais bon…). Il permet de temporiser une communication (en attendant d'avoir de quoi la traiter) donc d'absorber des pics d'utilisation grâce une file d'attente, d'avoir plusieurs écrivains et lecteurs dans une même file d'attente, etc.
J'en retiens deux usages :
commande1 | commande2 && commande3
, en gros.Dans le passé, j'ai utilisé Apache Kafka (voir mes notes). Je retiens, que, comme d'hab', on peut contorsionner un logiciel afin qu'il fasse le même boulot qu'un autre, mais, en gros : Kafka = file d'attente durable / sécurisée + montée en charge facile par ajout de nœuds + stockage de flux (genre un NetFlow) plus que stockage de messages. RabbitMQ = protocole ouvert et normalisé AMQP dont RabbitMQ n'est qu'une implémentation (Kafka = protocole maison) + simplicité d'utilisation (pour les cas basiques).
J'ai un écrivain / producteur dans une file d'attente, et deux lecteurs / consommateurs de cette file d'attente. RabbitMQ attribue les tâches / messages en round-robin : une tâche pour le premier consommateur, une tâche pour le deuxième, une tâche pour le premier, etc. Cet algorithme ne tient pas compte de la charge effective de chaque consommateur : à certains moments, un consommateur avait X tâches en attente alors que l'autre consommateur faisait rien. J'ai rien trouvé permettant de changer l'algorithme de répartition (dispatching) de RabbitMQ.
Pour compenser, on peut configurer le prefect, c'est-à-dire le nombre max de messages non-acquittés que RabbitMQ envoie à un consommateur (ou à un ensemble de consommateurs). Cela se configure sur le consommateur. Ainsi, tant qu'un consommateur n'aura pas acquitté ses messages afin de retomber sous ce seuil, RabbitMQ distribuera la tâche à un autre consommateur. Si aucun consommateur est disponible, le nombre de messages « ready » (messages pas encore distribués) grossira. La documentation nomme ça « fair dispatch ».
Nos consommateurs sont des nœuds celery, un gestionnaire de tâches distribuées Python. Celery lit la file d'attente RabbitMQ et déclenche la fonction Python KiVaBien dans notre code Django. Pour régler le prefect, le paramètre à utiliser est « worker_prefetch_multiplier » donc la variable « CELERYD_PREFETCH_MULTIPLIER » dans /etc/default/celeryd
si l'on utilise le script d'init celery. Par défaut, la valeur est 4. Elle se multiplie par le nombre de threads d'un worker. Comme nous utilisons « worker_concurrency = 1 », le nombre maximal de messages non-acquittés par worker sera 4. Nous avons 2 machine d'encodage, donc 2 celery donc 2 workers, donc un maximum de 8 messages non-acquittés.
Attention : par défaut, celery acquitte le message / la tâche avant d'avoir effectué le boulot. Les tâches réservées (« prefetch ») viennent donc en sus des tâches acquittées qui sont en cours d'exécution (source 1, source 2). Dans mon cas, avec 1 worker, « worker_concurrency = 1 » et « worker_prefetch_multiplier = 4 », 5 tâches seront "en cours" : 1 en cours d'exécution et 4 en attente de traitement et d'acquittement.
Mais, tiens, comment supervise-t-on le nombre de messages dans une file d'attente RabbitMQ ? Cela donne une idée de la charge sur notre service et permet d'anticiper le nombre de consommateurs qu'il convient de lancer afin d'offrir un service acceptable.
Simple : sudo rabbitmqctl -p <virtual_host> list_queues name messages_ready messages_unacknowledged messages
.
On formate le résultat de sortie en récupérant le nom des files d'attente, le nombre de messages prêts, le nombre de messages non-acquittés et le nombre total de messages (ready+unack). Pour le reste : voir le manuel.
Les messages non-acquittés sont donc les messages que RabbitMQ a déjà distribué à des consommateurs qui n'ont pas confirmé les avoir traités (dans le cas de celery, par défaut, l'acquittement se fait même avant de bosser).
Les messages prêts sont ceux qui n'ont pas encore été distribués à des consommateurs par RabbitMQ par absence de consommateurs disponibles.
Comment voir le contenu (payload) des messages d'une file d'attente ? Il faut utiliser le plugin management. Il met à disposition une API sur laquelle tapent une interface web (qui affiche de zolis graphes de charge) et l'outil en ligne de commande rabbitmqadmin
.
Pour activer le plugin : rabbitmq-plugins enable rabbitmq_management
. Pour le désactiver : rabbitmq-plugins disable rabbitmq_management
.
Récupérer le contenu des messages :
rabbitmqadmin -V <virtual_host> -u <identifiant> -p <mdp> get queue=<nom_file_attente> count=<nombre_de_messages_qu'on_veut_voir> requeue=true
. Si tu as « Access refused: /api/queues/%2F/nom_file/get », c'est que t'as oublié de préciser le nom de l'hôte virtuel ou un couple identifiant/mdp valide (le mieux est de reprendre celui utilisé par ton application ;) ) ;Seuls les messages prêts (ready) sont concernés (les messages unacknowledged sont considérés comme ayant été consommés).
L'affichage se fait du plus ancien (le premier arrivé dans la file d'attente) au plus récent (le dernier arrivé).
Si l'on ne précise pas « requeue=true », les messages sont sortis de la file d'attente, donc ils ne seront pas traités par les consommateurs !
Si l'on ne précise pas « count=X », un seul message est affiché (le plus récent).
on peut cibler les descripteurs de fichier avec
-e write=<numero du fd>
T'es sûr de toi ? Je viens de tester avec un strace -e write=2 dmesg
sur un Debian 10 et ça ne fonctionne pas : ça affiche TOUS les appels système. Le manuel dit : 1) il faut utiliser -e write -e write=fd
; 2) ça ne focalise pas strace
sur les écritures dans un descripteur de fichier donné, ça dump tout ce qui est écrit via ce descripteur.
mais ça changera probablement rien à ton analyse :p.
Non. Mon problème est que le message d'erreur n'est plus affiché sur stderr dès que je passe l'option « -f » à strace
. Et strace
voit aucun write()
, writev()
ou autre.
Est-ce que la conclusion c'est pas un
grep -vxe 'Error: Terminated'
à la fin ? :D
J'aimerais bien m'être auto-aveuglé avec un grep -v
, mais ce n'est pas le cas. ^^
Résumé : quand elle est chaînée à un head -n 1
, la commande rabbitmqctl
affiche ce qu'on attend d'elle mais aussi une erreur « Error: Terminated ». Oui, head
termine son exécution dès qu'elle a affiché le nombre de ligne qu'on lui a demandé. Se faisant, elle n'écoute plus ce qui se raconte dans le pipe. L'écriture dans un pipe sans lecteur déclenche l'envoi d'un signal SIGPIPE à l'écrivain (rabbitmqctl
dans le cas présent).
Ce signal peut fermer le programme (traitement par défaut), déclencher un bout de code maison ou être ignoré (c'est le cas de rabbitmqctl
) et/ou déclencher un comportement pas vraiment prévu (c'est le cas de rabbitmqctl
).
On profite de l'occasion pour réviser l'utilisation de strace
(« -f » et « -e » et la différenciation entre une fonction de la libc et un appel système ‒ fork()
versus clone()
‒ sont les pièges habituels), les signaux Linux (leur héritage, leur traitement avec signal
/ sigaction
, la structure de données siginfo_t
, etc.), l'appel système write()
(qui permet d'écrire dans un fichier, comme la console), les compétitions entre processus (si rabbitmqctl
va assez vite, il peut terminer avant que head
termine, donc aucune erreur s'affiche), et les limites des outils de diagnostic (un signal émit durant un appel système est annoncé comme venant du processus qui a effectué cet appel, pas du noyau, strace -f
fait disparaître l'erreur donc impossible de la tracer…).
J'utilise RabbitMQ.
Pour regarder les entrailles de mon installation, j'utilise l'outil rabbitmqctl
. Exemple : rabbitmqctl -p <virtual_host> list_queues | head -n 3
.
Une fois sur deux, cette commande me retourne le résultat (la liste des files d'attente) ainsi que l'erreur « Error: Terminated ».
Aucune erreur est affichée si j'utilise grep
à la place de head
. Si je n'utilise pas la commande head
, je n'ai pas de problème.
La réponse est évidente : head
se termine (exit()
) dès qu'elle a affiché le nombre de lignes qu'on lui demande, donc le fichier « stdin » est fermé… Sauf que ce fichier est toujours le « stdout » de rabbitmqctl
. Si rabbitmqctl
tente d'écrire dedans avec l'appel système write()
, celui-ci lui enverra le signal SIGPIPE qui signifie, en gros "hého, il y a plus personne qui t'écoute !". rabbitmqctl
peut intercepter ce signal et afficher un message d'erreur.
Il n'y a pas de problème avec | grep
car grep
attend la fin du fichier (qu'il reconnaît car read()
retourne alors 0, voir man open
).
J'en parle à Johndescs qui, évidemment, doute : "ça ferait pareil avec d'autres programmes, genre dmesg
, ce qui n'est pas le cas".
Sortons strace
afin de tracer les appels système et leurs erreurs.
Évidemment, rabbitmqctl
se fork()
(et pas qu'un peu…), donc, la première fois, on voit rien. Relançons en demandant de tracer également les appels système des processus enfant : strace -f
.
Évidemment, les appels système sont très nombreux, donc on veut les filtrer avec « -e », mais, comme toujours, on ne filtre pas ce qu'il faut : rabbitmqctl
utilise writev()
, pas write()
…
Cette fois, on est bon :
# strace -f -e writev rabbitmqctl -p <virtual_host> list_queues | head -n 1
strace: Process 23884 attached
[…]
strace: Process 23982 attached
[…]
strace: Process 23990 attached
[…]
[pid 23990] writev(45, [{iov_base="\0\0\0+", iov_len=4}, {iov_base="\203D\2\1\0008\204h\4a\23gR\0\0\0\0A\0\0\0\0\1R\1r\0\3R\0\1\0"..., iov_len=43}], 2 <unfinished ...>
[pid 23982] writev(1, [{iov_base="Listing queues ...\n", iov_len=19}], 1 <unfinished ...>
[pid 23990] <... writev resumed> ) = 47
[pid 23982] <... writev resumed> ) = 19
Listing queues ...
[…]
[pid 23990] writev(45, [{iov_base="\0\0\0+", iov_len=4}, {iov_base="\203D\2\1\0008\204h\4a\24gR\0\0\0\0A\0\0\0\0\1R\1r\0\3R\0\1\0"..., iov_len=43}], 2) = 47
[pid 23982] writev(1, [{iov_base="celeryev.42165f0d-b15c-4667-8b57"..., iov_len=51}], 1) = -1 EPIPE (Broken pipe)
[pid 23982] --- SIGPIPE {si_signo=SIGPIPE, si_code=SI_USER, si_pid=23899, si_uid=114} ---
[…]
[pid 23982] +++ exited with 0 +++
Le processus numéro 23990 interroge le processus 23982 via un pipe (« writev(45,[…] » => fichier numéro 45 ;) ). Ce dernier réagit à l'ordre en écrivant directement sa réponse sur stdout (writev(1, [{iov_base="Listing queues … » => fichier numéro 1 = stdout, c'est la norme). Et il se mange bien un SIGPIPE.
Même chose pour dmesg | head -n 1
: dmesg
reçoit bien un SIGPIPE et se termine (ce qui est le traitement par défaut de la plupart des signaux).
Dans la trace strace
ci-dessous, notons que la structure de données « siginfo_t » associée à un signal nous informe que le signal SIGPIPE a été envoyé par un processus (« si_code=SI_USER ») dont le PID est « si_pid=23899 » et que ce dernier tourne avec les droits de l'utilisateur dont l'ID est « si_uid=114 ». 114 = UID de l'utilisateur rabbitmq sur mon système. 23899 = PID de la machine virtuelle Erlang (BEAM/erl, car RabbitMQ est codé en Erlang) qui fait tourner rabbitmqctl
, qui, d'ailleurs demande à ignorer le signal SIGPIPE (on verra ça plus bas).
Avec dmesg
, on constate que l'UID est celui de root et que le PID est celui du processus dmesg
lui-même. Même chose avec un simple programme C qui se fork()
et execvp()
seq
: le PID annoncé dans « si_pid » est celui du processus enfant.
Dans le cas d'Erlang, ce n'est pas étonnant que la machine virtuelle re-émette le signal à l'un de ses enfants, car elle est un intermédiaire entre lui et le noyau.
Dans le cas du programme C, on pourrait s'attendre à ce que le code du signal soit SI_KERNEL vu que write() est un appel système, donc normalement exécuté côté kernel, mais ce n'est pas le cas… C'est un peu comme la structure de données d'un SIGCHLD qui contient le PID du processus enfant qui a pris fin : ce n'est pas directement l'enfant qui envoie le signal (et « si_code » est cohérent puisqu'il vaut « CLD_EXITED »).
Mais, du coup, qui écrit le message d'erreur « Error: Terminated » ?
Impossible de le savoir : dès que j'utilise le paramètre « -f » de strace
, il ne s'affiche plus :
rabbitmqctl
pour lancer la machinerie Erlang, se termine avec un code retour 70. On le voit car son père (Bash, execvp()
par strace
afin d'exécuter rabbitmqctl
qui s'avère être un script) reçoit un signal SIGCHLD (ton enfant a terminé) avec « si_status=70 » dans la structure de données « siginfo_t »). Bash, le père, conserve ce code retour et termine avec un code retour 70.L'observation avec strace
n'est pas si neutre que cela ? Je suis très surpris…
Peut-être que le signal SIGPIPE est traité par rabbitmqctl
? D'ailleurs, si l'on regarde le journal strace
ci-dessus, on constate que le processus numéro 23982, qui s'est pourtant mangé le SIGPIPE, termine avec un code retour 0, ce qui n'est pas normal : essaye un kill -13
(SIGPIPE a le numéro de signal 13, voir man 7 signal
) sur un cat
ou un grep
: le code retour est 141. De même, quand un processus termine à cause d'un signal, non-traité strace
affiche « killed by
Pour traiter un signal, c'est-à-dire soit l'ignorer, soit déclencher une fonction, un développeur doit utiliser les appels système signal()
ou sigaction
. Avec un strace -f -e writev,signal rabbitmqctl […] | head -n 1
, on constate que plusieurs processus demandent à ignorer SIGPIPE. Mais pas le processus qui écrit sur stdout.
Peu importe : la gestion des signaux s'hérite : si un processus parent a ignoré un signal ou enregistré une fonction pour le gérer, alors toute sa descendance en bénéficie. L'héritage de la fonction de traitement s'arrête uniquement si le code est écrasé avec une fonction de la libc membre de la famille exec
(c'est logique : la fonction de traitement ne sera plus disponible puisque le code du programme est écrasé par un autre programme). Un signal ignoré cesse jamais implicitement de l'être. Là encore, c'est le manuel de signal()
qui nous le confirme : « A child created via fork(2) inherits a copy of its parent's signal dispositions. During an execve(2), the dispositions of handled signals are reset to the default; the dispositions of ignored signals are left unchanged. »
Comment visualiser la parenté avec strace
? Avec « -f », on a bien le PID qui s'affiche à gauche, mais on ne sait pas quel processus l'a enfanté. On pense à utiliser « -e fork », mais ça produit aucun résultat. Un lutin du web nous rappelle que fork()
n'est pas un appel système, mais aussi une fonction de la glibc qui, ces temps-ci, encapsule l'appel système clone()
. Debian utilise la glibc. Ça explique pourquoi strace
ne voit pas les fork()
. Hop, « -e writev,clone,signal » et l'on voit bien que le processus parent de celui qui écrit sur stdout ignore (« SIG_IGN ») le signal SIGPIPE, donc son enfant (celui qui écrit sur stdout et reçoit le SIGPIPE) l'ignorera aussi :
[pid 6686] rt_sigaction(SIGPIPE, {sa_handler=SIG_IGN, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f8a98c2b0e0}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
[…]
[pid 6686] clone(child_stack=0x7f8a561b7ff0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0x7f8a561b89d0, tls=0x7f8a561b8700, child_tidptr=0x7f8a561b89d0) = 6767
[…]
[pid 6767] writev(1, [{iov_base="celeryev.42165f0d-b15c-4667-8b57"..., iov_len=51}], 1) = -1 EPIPE (Broken pipe)
Je précise, même si c'est inutile, que le processus enfant n'a pas fait appel à l'appel système execve
(ni autre membre de la famille exec).
Donc le processus n'a pas de routine définie lorsqu'il se prend un SIGPIPE, donc ce n'est pas lui qui affiche « Error: Terminated ». Mais cela peut être son parent, la machine virtuelle Erlang ou un autre processus qui discute avec lui et qui se rend compte qu'il n'a pas fait son boulot.
dmesg
n'enregistre pas non plus de fonction pour traiter SIGPIPE et ne l'ignore pas non plus, d'où il est donc normal qu'il se termine sans rien afficher quand il se mange un SIGPIPE, car c'est le traitement par défaut de SIGPIPE.
On notera également qu'il y a une notion de vitesse : si rabbitmqctl
a le temps d'écrire ce qu'il veut avant que head
ne termine, alors aucun signal SIGPIPE est envoyé et donc aucune erreur est affichée.
On vérifie ça avec rabbitmqctl -p <virtual_host> list_queues | (sleep 2 && head -n 1)
: aucune erreur, jamais. En revanche, sleep 1
= erreur.
On peut aussi vérifier avec strace -e writev rabbitmqctl -p <virtual_host> list_queues | strace head -n 1
: on verra que head
close()
stdin avant que rabbitmqctl
termine ses writev()
.
On peut aussi reproduire ça avec seq 1 1040 | head -n 1
: aucune erreur. En revanche, seq 1 1041
, vlam, SIGPIPE. Normal : seq
écrit les nombres 1 à 1040 ainsi que le retour à la ligne entre chaque nombre dans un buffer. Ce qu'il faut écrire occupe 4093 octets au total, donc write()
écrit ça d'un coup d'après sa page de manuel, donc head
a encore rien reçu, donc il n'a pas pu fermer stdin et se terminer. En revanche, il faut plus que 4096 octets pour écrire les nombres de 1 à 1041, donc cela se fait en deux appels à write()
. Entre les deux appels, head
a fermé le fichier et s'est arrêté, donc le deuxième write()
déclenche un SIGPIPE.
Cela explique le côté aléatoire de mon problème (tantôt le message s'affiche, tantôt non). rabbitmqctl
affiche 4 lignes au total. Avec un head -n 4
, le message d'erreur apparaît jamais car rabbitmqctl
a toujours le temps d'effectuer ses opérations (demander à son enfant de bosser, l'enfant consulte ses registres et écrit sur stdout, etc.). Avec head -n 3
, il y a une race condition : parfois rabbitmqctl
arrive à être assez rapide, parfois non. Avec head -n 1
, rabbitmqctl
a aucune chance de gagner la compétition : il y a trop de boulot et de communication inter-processus à entreprendre.
Cela est confirmé par le manuel de write()
qui expose : « If write() is interrupted by a signal before it writes any data, it shall return −1 with errno set to [EINTR] ». Dans la discussion que j'ai déjà mentionnée, on lit également « EPIPE An attempt is made to write to a pipe or FIFO that is not open for reading by any process, or that only has one end open. […] ». Tout correspond : write()
n'est pas interrompu, il arrive trop tard.
Au final, c'est très probablement rabbitmqctl
(ou la machinerie Erlang) qui affiche le message d'erreur « Error: Terminated » quand l'un des processus enfant ne se termine pas de manière attendue.
Difficile d'aller plus loin (j'aurais voulu savoir quoi, précisément, écrit le message d'erreur) :
su
(le script shell rabbitmqctl
l'appelle afin de lancer la machinerie Erlang). Sur une machine de bureau Debian 10, si l'on fait un su -s /bin/sh -c cat
(comme le fait rabbitmqctl
sauf que la commande n'est pas cat
, évidemment) et que l'on envoie un signal à cat
avec kill
, on constate que su
consulte /usr/share/locale/<LOCALE>/LC_MESSAGE/libc.mo
et write()
un message d'erreur qui varie en fonction du signal envoyé. Mais, sur le serveur RabbitMQ Debian 9, ce n'est pas le cas : su
write()
rien, ni quand on le charge de lancer cat
, ni quand on le charge de lancer rabbitmqctl
;gdb
permet de jouer avec les signaux, mais on est face à un empilement de scripts shell (sur lesquels gdb
est incompétent) qui lancent, in fine, du Erlang, qui, lui, a besoin que des variables d'environnement soient définies (par les scripts) et dont des sous-processus discutent entre eux pour accomplir le boulot…, bref, un joli merdier ;signal()
et sigaction()
sont des appels système, pas des fonctions de la libc, y'a-t-il moyen d'intercepter ?) ou de faire des dégâts collatéraux (comportement inattendu lié à des signaux qui auraient du être ignorés ou traités et qui ne le sont pas à cause de la surcharge, par exemple) ;Résumé : les erreurs rapportées ci-dessous (et dans le titre) sont rares pour une machine virtuelle (peu de pages web en parle), je n'ai pas de solution à proposer et, dans mon cas, la machine virtuelle a totalement crashé deux mois après les premiers symptômes. Vérifie tes sauvegardes. :)
En juillet 2020, l'une de nos machines virtuelles Proxmox+KVM kernel-panic-ait, parfois plusieurs fois par jour. Puis ce comportement a disparu sans intervention humaine.
Début août 2020, /var passe en lecture seule. Je redémarre la VM, un fsck
se déclenche et la partition était à nouveau montée en écriture. Le lendemain, notre supervision m'indique que cette partition est à nouveau en lecture seule. dmesg
indique que la transition a eu lieu 256 minutes (4 h) après le démarrage. Les erreurs consignées sont :
kernel: sd 0:0:0:0: [sda] Result: hostbyte=DID_OK driverbyte=DRIVER_TIMEOUT,SUGGEST_OK
kernel: end_request: I/O error, dev sda, sector 29954432
kernel: Aborting journal on device sda7.
kernel: ext3_abort called.
kernel: EXT3-fs error (device sda7): ext3_journal_start_sb: Detected aborted journal
kernel: Remounting filesystem read-only
Pourquoi uniquement /var alors que toutes les partitions de cette machine virtuelle sont stockées dans le même LV LVM sur l'hyperviseur ? Car il s'agit d'un serveur, donc une fois qu'il a démarré et que les principaux binaires sont en RAM, il n'y a quasi plus de lecture et encore moins d'écriture sur /, alors que /var reçoit les journaux systèmes et applicatifs en permanence.
I/O wait côté hyperviseur ? Je n'y crois pas, car les graphes sur la page de résumé de l'hyperviseur dans l'interface web de Proxmox ne le montrent pas.
La VM n'a pas assez de temps CPU pour effectuer ses opérations car ses ressources CPU sont sous-dimensionnées ou que l'hyperviseur est débordé par d'autres VMs ? Je n'y crois pas, car top
affichait « 0,0 st » (st = steal time = temps volé). Mais comme je n'étais pas là au moment du passage en lecture seule… De plus, c'était les vacances, donc la charge de ce serveur était très réduite et aucun changement n'a été mis en œuvre par les administrateurs sur l'ensemble du périmètre (cette VM, l'hyperviseur, le réseau, etc.).
Très peu de ressources sur le web mentionnent les erreurs que je rencontre.
Je trouve la première partie des erreurs extraites de mon dmesg
dans un ticket chez VirtualBox.
La première piste est un problème d'I/O côté hyperviseur. Comme vu ci-dessus, aucun élément me permet d'affirmer cela.
La deuxième est de désactiver NCQ (optimisation des I/O en laissant le disque dur ordonnancer lui-même les requêtes afin de les traiter dans l'ordre de l'emplacement physique des données). Je n'y crois pas : 1) mes erreurs ne mentionnent pas NCQ ; 2) il y a trop d'abstractions (ext4 sur une partition étendue dans un LV LVM dans un volume RAID matériel) pour que NCQ puisse agir. J'ai quand même désactivé NCQ dans la VM.
Je trouve la deuxième partie des erreurs dans un rapport de bug chez Red Hat. Problème dans Linux censé avoir été corrigé à la fin des années 2000 mais qui est toujours là en 2013 et 2014… La version du système de notre VM date justement de la fin des années 2000, mais la version de notre noyau est ultérieure à celle dans laquelle le correctif est apparu.
Je me laisse convaincre que, peut-être, le journal ext est corrompu, ce qui explique le déclenchement automatique d'un fsck
à chaque redémarrage, même quand la partition /var n'a pas été remontée en lecture seule.
La partition /var étant utilisée par plein de processus, je ne peux pas travailler dessus. Je redémarre donc en single user mode (une entrée GRU me le proposait, sinon il faut éditer la ligne et ajouter « single » à la fin de la ligne « linux » et démarrer en pressant ctrl+x) puis je tape les commandes suivantes proposées dans un commentaire du rapport de bug :
tune2fs -O ^has_journal /dev/sda7
fsck.ext4 -f /dev/sda7
tune2fs -j /dev/sda7
reboot
Vu que fsck
n'a pas trouvé d'erreur, je pense que tout cela a été vain.
Quoique… Cela a tenu un mois et demi.
Le serveur a totalement crashé mi-septembre 2020. Impossible de booter car absence de partition… Il semble qu'il ne s'agissait donc pas d'un problème temporaire type I/O wait / temps CPU volé, etc.
Un coup de testdisk
depuis un Live CD a permis de remettre la partition / dans le MBR, mais pas /var…
Nous avons monté une nouvelle machine virtuelle. La configuration du service a été récupérée depuis Bacula. Les données des utilisateurs du service étaient stockées dans un partage NFS. Aucune perte de données à déplorer.
Firefox met en cache les redirections HTTP définitives (code HTTP 301).
Ainsi, quand tu configures une redirection sur un serveur web, que tu constates que tu t'es trompé, que tu remets la configuration d'origine et que tu testes, t'es encore redirigé. D'où l'importance de tester avec un outil de diagnostic qui ne conserve pas d'état comme wget
ou curl
.
Ce qui m'a étonné cette fois-ci, c'est que la mise en cache de la redirection a perduré après le redémarrage de Firefox. Je n'ai pas le souvenir que ça me soit déjà arrivé.
Pour faire oublier à Firefox une redirection sans effacer tout l'historique / cache de la dernière heure depuis les préférences : aller dans l'historique (ctrl + h), chercher la page web précise, cliquer droit, « oublier ce site ».