Derniers postsMettre en place une protection parentale pour la famille – mise à jourMise à jour de cet ancien article, suite à l’abandon du RP3 pour un fanless PC avec 2 interfaces ethernet en natif sur une Debian Stretch. Pour mettre en place cette protection parentale, les paquets suivants seront installés Squid3 qui assure la partie “proxy” et intercepte les protocoles HTTP et HTTPS SquidGuard qui autorise ou non les domaines à visiter, les IP du réseaux locales, les heures de navigation, … IpTables pour rerouter le trafic HTTP et HTTPS sur squid pour rendre le proxy “transparent” Nginx avec le support PHP pour afficher une belle page Web en cas de site non-autorisé Quelle version de Squid ? La version 3.5 introduit une nouvelle option, “Peek and Splice” dans la fonctionnalité ssl_bump qui permet de choisir quelle partie de la connexion SSL on souhaite vérifier. Dans notre cas, on souhaite vérifier le nom de domaine lors du TCP CONNECT en HTTPS et non le contenu des données ou l’URL. Hélas, la version de base dans les répo Debian ne permet pas de gérer le protocole HTTPS, car non compilée avec les options SSL. Il va donc falloir récupérer les sources de Squid 3.5 et les recompiler à la sauce Debian. Mise à jour de sa distrib’ On commence tout d’abord par une petite mise à jour de sa distribution favorite sudo apt-get update sudo apt-get upgrade sudo reboot Compilation de Squid 3.5 On installe les paquets nécessaires, on télécharge les sources de squid 3.5, on édite quelques fichiers et on compile le tout #Installation des paquets sudo apt-get install devscripts build-essential fakeroot debhelper dh-autoreconf cdbs sudo apt-get build-dep squid3 sudo apt-get install libssl1.0-dev #Création du répertoire pour la compilation mkdir -p ~/build/squid3 cd ~/build/squid3 #Récupération et décompilation des sources wget http://ftp.debian.org/debian/pool/main/s/squid3/squid3_3.5.23-5+deb9u1.dsc wget http://ftp.debian.org/debian/pool/main/s/squid3/squid3_3.5.23.orig.tar.gz wget http://ftp.debian.org/debian/pool/main/s/squid3/squid3_3.5.23-5+deb9u1.debian.tar.xz dpkg-source -x squid3_3.5.23-5+deb9u1.dsc cd squid3-3.5.23 A ce stade, il faut modifier 2 fichiers pour que la compilation se déroule correctement : ~/build/squid3/squid3-3.5.23/debian/rules : les flags de compilation sont ajustés pour rajouter le support SSL (non activé par défaut) + suppression d’option d’authentification inutile DEB_CONFIGURE_EXTRA_FLAGS := BUILDCXXFLAGS="$(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS)" \ --datadir=/usr/share/squid \ --sysconfdir=/etc/squid \ --libexecdir=/usr/lib/squid \ --mandir=/usr/share/man \ --enable-inline \ --disable-arch-native \ --enable-async-io=8 \ --enable-storeio="ufs,aufs,diskd,rock" \ --enable-removal-policies="lru,heap" \ --enable-delay-pools \ --enable-cache-digests \ --enable-icap-client \ --enable-follow-x-forwarded-for \ --enable-auth-basic="DB,fake,getpwnam,LDAP,NCSA,NIS,PAM,POP3,RADIUS,SASL,SMB" \ --enable-auth-digest="file,LDAP" \ --enable-auth-negotiate="kerberos,wrapper" \ --enable-auth-ntlm="fake,smb_lm" \ --enable-external-acl-helpers="file_userip,kerberos_ldap_group,LDAP_group,session,SQL_session,time_quota,unix_group,wbinfo_group" \ --enable-url-rewrite-helpers="fake" \ --enable-eui \ --enable-esi \ --enable-icmp \ --enable-zph-qos \ --enable-ecap \ --disable-translation \ --with-swapdir=/var/spool/squid \ --with-logdir=/var/log/squid \ --with-pidfile=/var/run/squid.pid \ --with-filedescriptors=65536 \ --with-large-files \ --with-default-user=proxy \ --with-openssl \ --enable-ssl \ --enable-ssl-crtd ~/build/squid3/squid3-3.5.23/debian/control : la ligne de contrôle des dépendances est mise à jour pour supprimer des dépendances inutiles Build-Depends: libldap2-dev, libpam0g-dev, libdb-dev, cdbs, libsasl2-dev, debhelper, libcppunit-dev, libkrb5-dev, comerr-dev, libcap2-dev , libexpat1-dev, libxml2-dev, autotools-dev, libltdl-dev, dpkg-dev (>= 1.16.1~), pkg-config, libnetfilter-conntrack-dev , nettle-dev, libgnutls28-dev, lsb-release Puis on lance la compilation #Compilation ./configure debuild -us -uc -b Installation de Squid 3.5 Une fois la compilation terminée, on peut installer les paquets fraîchement compilés cd ~/build/squid3 #Installation des paquets sudo dpkg -i squid-common_3.5.23-5+deb9u1_all.deb squidclient_3.5.23-5+deb9u1_amd64.deb squid_3.5.23-5+deb9u1_amd64.deb #On marque le paquet pour éviter une mise à jour sudo apt-mark hold squid squid-common On crée maintenant le fichier /etc/squid3/squid.conf, on rajoute son réseau et on l’autorise avec 2-3 autres modifications. Comme beaucoup de réseaux locaux, le mien est en 192.168.1.X. Pour la génération du certificat SSL, j’ai réutilisé celui déjà mis en place au niveau du serveur Nginx en tant que reverse proxy. La procédure de création du certificat n’est donc pas décrite. Le fichier doit ressembler à ça : #Définition des ACL acl SSL_ports port 443 #https acl SSL_ports port 563 # snews acl SSL_ports port 873 # rsync acl Safe_ports port 80 # http acl Safe_ports port 21 # ftp acl Safe_ports port 443 # https acl Safe_ports port 70 # gopher acl Safe_ports port 210 # wais acl Safe_ports port 1025-65535 # unregistered ports acl Safe_ports port 280 # http-mgmt acl Safe_ports port 488 # gss-http acl Safe_ports port 591 # filemaker acl Safe_ports port 777 # multiling http acl CONNECT method CONNECT acl purge method PURGE #Le réseau local acl LocalNet src 192.168.1.0/24 acl LocalNet2 src 192.168.0.0/24 #ACL : Liste des domaines non-vérifiés acl broken_sites ssl::server_name .google.com acl broken_sites ssl::server_name .google.fr acl broken_sites ssl::server_name .google.ch acl bump_step1 at_step SslBump1 #Définition des autorisations http_access deny !Safe_ports http_access deny CONNECT !SSL_ports http_access allow localhost manager http_access deny manager http_access allow localhost http_access allow LocalNet http_access deny all #Configuration du SSL proxy sslproxy_cert_error allow all sslproxy_flags DONT_VERIFY_PEER sslproxy_options NO_SSLv2,NO_SSLv3,SINGLE_DH_USE #Localhost et les sites sur liste blanche ne sont pas vérifiés ssl_bump splice localhost ssl_bump splice LocalNet2 ssl_bump splice broken_sites #On ne vérifie que CONNECT ssl_bump peek bump_step1 all ssl_bump splice all #Définition des ports d'écoute http_port 192.168.1.5:8080 http_port 192.168.1.5:3128 transparent https_port 192.168.1.5:3129 transparent ssl-bump generate-host-certificates=on version=4 cafile=/etc/certs/example.pem cert=/etc/certs/example.crt key=/etc/erts/example.key dns_v4_first on forwarded_for off coredump_dir /var/spool/squid refresh_pattern ^ftp: 1440 20% 10080 refresh_pattern ^gopher: 1440 0% 1440 refresh_pattern -i (/cgi-bin/|?) 0 0% 0 refresh_pattern . 0 20% 4320 cache_dir ufs /cache 400 16 256 cache_access_log /var/log/squid/access.log cache_effective_user proxy Une fois la configuration de Squid3 faite, on s’occupe du répertoire /cache visant à améliorer la navigation. sudo mkdir /cache Vient l’édition du fichier /etc/fstab afin de monter 500Mo de RAM dans le répertoire /cache. La taille de 500Mo est à ajuster en fonction de la taille de cache déclarée dans le fichier /etc/squid3/squid.conf. Il est recommandé de ne pas utiliser 100% du /cache mais 80% (500 x 80% = 400). D’où les 400Mo déclaré dans /etc/squid3/squid.conf et les 500Mo dans /etc/fstab. tmpfs /cache tmpfs defaults,noatime,nosuid,size=500m 0 0 Création du répertoire /var/log/squid avec les bons droits sudo mkdir /var/log/squid sudo chmod 755 /var/log/squid sudo chown proxy:proxy /var/log/squid Un redémarrage des services et on peut désormais tester notre serveur proxy depuis un poste. L’IP de mon raspberry est 192.168.1.5. La navigation Internet doit pouvoir s’effectuer sans souci depuis le poste client. sudo service squid3 stop sudo squid3 -z sudo service squid3 start SquidGuard Comme précédemment, on installe les paquets nécessaires. sudo apt-get install squidguard Maintenant, il s’agit d’utiliser des listes contenant les sites et contenus interdits ou à surveiller. L’université de Toulouse met à disposition gracieusement de telles listes et on va donc récupérer ces listes pour les utiliser. sudo cd /var/lib/squidguard/db/ sudo wget http://dsi.ut-capitole.fr/blacklists/download/blacklists.tar.gz sudo tar -zxvf blacklists.tar.gz sudo chown -R proxy:proxy /var/lib/squidguard/db/ On édite le fichier /etc/squidguard/squidGuard.conf avec la liste des IP des appareils autorisés à tous les contenus (déclaration du group parents). Pour chaque contenu non-autorisé, un fichier *contenu*.access est crée dans le répertoire /var/log/squidguard afin de logguer les tentatives d’accès. dbhome /var/lib/squidguard/db logdir /var/log/squidguard src parents { ip 192.168.1.90 } dest ads { domainlist blacklists/ads/domains urllist blacklists/ads/urls log ads.access } dest adult { domainlist blacklists/adult/domains urllist blacklists/adult/urls log adult.access } dest aggressive { domainlist blacklists/aggressive/domains urllist blacklists/aggressive/urls log aggressive.access } dest agressif { domainlist blacklists/agressif/domains urllist blacklists/agressif/urls log agressif.access } dest arjel { domainlist blacklists/arjel/domains log arjel.access } dest drogue { domainlist blacklists/drogue/domains urllist blacklists/drogue/urls log drogue.access } dest drugs { domainlist blacklists/drugs/domains urllist blacklists/drugs/urls log drugs.access } dest malware { domainlist blacklists/malware/domains urllist blacklists/malware/urls log malware.access } dest mixed_adult { domainlist blacklists/mixed_adult/domains urllist blacklists/mixed_adult/urls log mixed_adult.access } dest phishing { domainlist blacklists/phishing/domains urllist blacklists/phishing/urls log phishing.access } dest porn { domainlist blacklists/porn/domains urllist blacklists/porn/urls log porn.access } dest proxy { domainlist blacklists/proxy/domains urllist blacklists/proxy/urls log proxy.access } dest sexual_education { domainlist blacklists/sexual_education/domains urllist blacklists/sexual_education/urls log sexual_education.access } dest violence { domainlist blacklists/violence/domains urllist blacklists/violence/urls log violence.access } dest warez { domainlist blacklists/warez/domains urllist blacklists/warez/urls log warez.access } acl { parents { pass all } default { pass !ads !adult !aggressive !agressif !arjel !drogue !drugs !malware !mixed_adult !phishing !porn !proxy !sexual_education !violence !warez all redirect http://192.168.1.5/block.php?caddr=%a&cname=%n&user=%i&group=%s&target=%t&url=%u } } On charge les listes téléchargées dans squidGuard. A noter que ces 2 commandes doivent être relancées à chaque modification du fichier /etc/squidguard/squidGuard.conf sudo squidGuard -C all sudo chown -R proxy:proxy /var/lib/squidguard/db/ Nouvelle édition du fichier /etc/squid3/squid.conf pour rajouter la ligne suivante url_rewrite_program /usr/bin/squidGuard -c /etc/squidguard/squidGuard.conf Re redémarrage des services et nouveau test sur un site interdit sudo service squid3 stop sudo squid3 -z sudo service squid3 start La page suivante doit apparaître, ce qui est normal vu que nginx n’a pas encore été installé et configuré Côté log, on peut voir que les connexions HTTP et HTTPS sont bien interceptées 1496669801.800 50 192.168.1.30 TAG_NONE/503 0 CONNECT www.y*****n.com:443 - HIER_NONE/- - 1496670016.301 6 192.168.1.30 TCP_MISS/200 1614 GET http://www.y*****n.com/ - HIER_DIRECT/192.168.1.5 text/html Nginx Comme vu, on installe les paquets nécessaires sudo apt-get install nginx php7.0-fpm Puis, édition du fichier /etc/nginx/sites-available/default pour prendre en charger les fichiers *.php et fixer les accès. On autorise seulement l’accès au réseau local server { listen 80; root /var/www/squidguard; index block.php; server_name localhost; location / { try_files $uri $uri/ /block.php; allow 192.168.1.0/8; allow 127.0.0.1; deny all; } location ~ .php$ { try_files $uri $uri/ =404; fastcgi_index block.php; fastcgi_pass unix:/run/php/php7.0-fpm.sock; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include /etc/nginx/fastcgi_params; } } Un petit fichier de test pour vérifier que Nginx avec le support PHP5 fonctionne bien echo '<?php phpinfo(); ?>' > /var/www/squidguard/info.php On redémarre Nginx et on affiche la page PHP Info sudo service nginx restart SquidGuard, le retour On va customiser notre page indiquant les sites bloqués. Pour cela, on crée le fichier /var/www/squidguard/block.php <?php if (@$_GET) $details[] = "Client Name: {$_GET}"; if (@$_GET) $details[] = "Client IP: {$_GET}"; if (@$_GET) $details[] = "Client User: {$_GET}"; if (@$_GET) $details[] = "Group: {$_GET}"; if (@$_GET) $details[] = "Category: {$_GET}"; if (isset($details) && $details) $details = implode(" | ", $details); ?> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf8" /> <title>Site Web bloqué</title> <link rel="stylesheet" type="text/css" href='http://192.168.1.190/filter.css'> </head> <body> <div id="message"> <center><img height=300px src='http://192.168.1.190/block.png' /></center> </div> <div class="outer"> <div class="header"> Contrôle parentale activé pour ce poste </div> <div class="inner"> <div class="error"> <p> Accès refusé ! </p> </div> <div class="msg"> <p> Site Web bloqué </p> <p> <strong>URL: <?php printf("<a href=\"%s\">%s</a>", @$_GET, @$_GET);?></strong> </p> <p><?php if (isset($details) && $details) print $details; ?></p> </div> </div> <div class="footer"> Web Filtering by Squid3 and SquidGuard on Kali </div> </div> </body> </html> Puis le fichier /var/www/squidguard/filter.css @CHARSET "UTF-8"; body { background-color: #ffffff; font-family: verdana, arial, sans serif; } div.outer { width: 70%; margin: 20px auto; } div.header { padding: 10px; background-color: #c0c0c0; text-align: right; font-size: 60%; } div.footer { padding: 5px; background-color: #c0c0c0; text-align: right; font-size: 60%; } div.inner { text-align: center; background-color: #f4f4f4; text-align: center; padding: 20px; } div.msg { padding: 20px; margin-top: 20px; background-color: #e2e2e2; color: black; font-size: 80%; } div.error { letter-spacing: 0.5em; word-spacing: 1em; padding: 20px; background-color: #ff0000; color: white; font-size: 200%; font-weight: bold; } Un nouveau test sur un contenu interdit en HTTP devrait nous afficher la jolie page suivante Pour le même site mais en HTTPS, pas de jolie page Web mais un message du navigateur avertissant d’un souci de confidentialité dans la chaîne SSL entre le site et lui. Cette erreur apparaîtra sur tous les navigateurs récents (Opera Neon, Chrome, Firefox, Safari, …). Côté log, on a bien l’entrée correspondante /var/log/squidguard % tail -f adult.access 2017-06-05 17:09:00 Request(default/adult/-) http://www.youporn.com/favicon.ico 192.168.1.30/pollux.loutor - GET REDIRECT 2017-06-05 17:09:06 Request(default/adult/-) www.youporn.com:443 192.168.1.30/pollux.loutor - CONNECT REDIRECT Configuration du proxy transparent Si le paquet IPtable n’est pas déjà installé sudo apt-get install iptables Puis, mise à jour des règles IPTables pour intercepter le trafic HTTP et HTTPS et le re-router sur le port 3128 et 3129 du proxy squid3 *nat -A PREROUTING -i enp1s0 -s 192.168.1.0/24 -p tcp --dport 80 -j REDIRECT --to-port 3128 -A PREROUTING -i enp1s0 -s 192.168.1.0/24 -p tcp -m tcp --dport 80 -j DNAT --to-destination 192.168.1.5:3128 -A PREROUTING -i enp1s0 -s 192.168.1.0/24 -p tcp --dport 443 -j REDIRECT --to-port 3129 -A PREROUTING -i enp1s0 -s 192.168.1.0/24 -p tcp -m tcp --dport 443 -j DNAT --to-destination 192.168.1.5:3129 COMMIT On fait un nouveau test en pensant bien à désactiver la configuration proxy. Le résultat doit être le même que précédemment, la page de restriction doit s’afficher. Mise à jour des listes Histoire d’automatiser le téléchargement des listes et de toujours avoir les dernières nouveautés, un p’tit script /etc/cron.daily/blacklist.sh est mis en place #!/bin/sh cd /var/lib/squidguard/db rm -rf blacklists wget http://dsi.ut-capitole.fr/blacklists/download/blacklists.tar.gz tar -zxvf blacklists.tar.gz rm blacklists.tar.gz squidGuard -C all chown -R proxy:proxy /var/lib/squidguard/db/ service squid3 restart Ressources utilisées http://www.pihomeserver.fr/2015/09/01/un-controle-parental-grace-au-raspberry-pi-squid-et-squidguard https://adilmehmoodbutt.wordpress.com/2014/02/19/how-to-install-squid3-transparent-proxy-server/ https://www.guillaume-leduc.fr/projet-installation-configuration-nginx-php-fpm.html https://redmine.pfsense.org/issues/6777 https://docs.diladele.com/administrator_guide_5_0/install/rpi/index.html http://david.mercereau.info/serveur-proxy-squid3-avec-ssl-rebuild-debian-squeeze-package/ https://www.linode.com/docs/web-servers/nginx/serve-php-php-fpm-and-nginx/ [...] Home Mode avec Surveillance StationL’option Geofence de Synology semble avoir quelques soucis et après de nombreux essais sans succès, j’ai décidé de passer par l’API de Surveillance Station pour déclencher le Home Mode et ainsi de refaire mon propre mode “Geofence”. Pour l’événement déclencheur, j’ai choisi de me baser sur la présence de mes téléphones portables sur le réseau. L’utilitaire “nmap” est donc utilisé pour faire un scan rapide du réseau et un script Python se charge du reste. Le tout est mis en cron sur un Raspberry Pi (ou tout autre système Linux/Unix supportant nmap et python). Les appels HTTP sont faits sur le réseau local mais il est possible de le faire depuis l’extérieur, sous réserve que Surveillance Station soit accessible. Dans un 1er temps, on s’identifie via la méthode Login pour récupérer un identifiant de session (SID). Puis, on utilise cet SID dans la suite des appels. Le script en lui-même est assez simple, il suffit de mettre à jour les variables suivantes : DOMAIN.COM PORT USERNAME PASSWORD DEVICE1 DEVICE2 #!/usr/bin/python import json import os import requests ## Get SID def authHomeMode(): res = requests.get('https://DOMAIN.COM:PORT/webapi/auth.cgi?api=SYNO.API.Auth&method=Login&version=2&account=USERNAME&passwd=PASSWORD&session=SurveillanceStation&format=sid') res_native = json.loads(res.text) sid=str(res_native.get('data').get('sid')) return sid ## Get current home mode def getHomeMode(sid): res = requests.get('https:///DOMAIN.COM:PORT/webapi/entry.cgi?api="SYNO.SurveillanceStation.HomeMode"&version=1&method=GetInfo&need_mobiles=true&_sid='+sid) res_native = json.loads(res.text) state = str(res_native.get('data').get('on')) return state ## Set home mode def setHomeMode(sid, state): res = requests.get('http:///DOMAIN.COM:PORT/webapi/entry.cgi?api="SYNO.SurveillanceStation.HomeMode"&version=1&method=Switch&on='+state+'&_sid='+sid); ## Check if the target device is on the network def isDeviceOnNetwork(hostname): response=os.system("cat /tmp/nmap.out | grep " + hostname+' > /dev/null') if response == 0: return True else: return False ## Main # Scan the local network os.system("nmap -sn 192.168.1.0/24 > /tmp/nmap.out") isHome = isDeviceOnNetwork('DEVICE1') or isDeviceOnNetwork('DEVICE2') sid = authHomeMode() state = getHomeMode(sid) # Nobody at home and Home Mode is enabled => disable it if state == 'True' and isHome == False: setHomeMode(sid, 'false') # Device detected and Home Mode is disabled => enable it if state == 'False' and isHome == True: setHomeMode(sid, 'true') [...] Lego + Raspberry = voiture télécommandée – Partie 2Suite au post expliquant comment réaliser une voiture télécommandée à partir d’anciens Lego, ce post décrit les options “possibles” pour améliorer la voiture. On/off de la voiture Pour cette étape, on rajoute un relais, asservi sur l’entrée GPIO 4 du RP pour démarrer/stopper le véhicule. Il s’agit d’un simple relais 5V 2 canaux. J’utilise la sortie NO (Normally Open) pour commander mon relais. Le relais sera fermé et activera les moteurs que si l’entrée IO4 est activée (état HIGH). Note : Pas besoin de transistor ou autre composant pour s’assurer du contrôle du relais, les GPIO du RP0 semblent fournir le voltage nécessaire pour la bascule du relais. Ajout de la caméra Rien de bien compliqué, la caméra se fixe très simplement à l’aide d’une nappe. Pour utiliser et tester la caméra, le binaire raspistill permet de prendre des photos et le binaire raspivid les vidéos. $ raspistill -w 640 -h 480 -e jpg -t 0 -o test.jpg $ raspivid -t 10000 -o test.h264 Note : attention à la connectique du RP0, plus petite que celle du RP3. Il est nécessaire d’avoir un faisceau spécial. Rajout de la marche arrière Pour la marche arrière, il a fallu trouver une solution permettant d’inverser la polarité des piles 9V pour faire tourner les moteurs dans l’autre sens et donc de faire marche arrière. Plusieurs solutions possibles mais je me suis orienté vers la solution que j’ai trouvée la plus simple : l’utilisation d’un composant dédié au contrôle des moteurs, le L293D de Texas Instrument. Le pilotage des entrées et l’alimentation du composant se fait sur du +5V et la sortie pour les moteurs varie de +4V à +36V, en fonction de la tension fournie (Vcc 2). L’utilisation de ce composant est fort simple : Le souci est que les entrées GPIO du RP fournissent du +3V et non du +5V. Pour cela, un convertisseur logique est utilisé. On alimente Vcc A avec la pin +3V du RP et Vcc B avec la pin +5V du RP. Ainsi, quand l’entrée 1 est activée avec une GPIO à +3V, la sortie 2 est activée et délivrera une tension de +5V. C’est cette sortie qui sera ensuite connectée à l’entrée du L293D pour piloter le moteur. Le montage électrique pour commander les 2 sens d’un moteur +5V depuis le RP est le suivant : Les GPIO 04, 17 et 27 sont donc utilisées pour contrôler le moteur. Le script python est le le script testMotor.py. Le montage électrique complet, avec le servo et les 2 moteurs Lego 9V est le suivant : Les scripts listener.py – version “relais” #!/usr/bin/env python import sys import evdev from subprocess import Popen devices = if len(devices) == 0: print ("No devices found, try running with sudo") sys.exit(1) for device in devices: print(device) device.grab() for event in device.read_loop(): if (event.type==3 and event.code==0 and event.value==0): print("Left") p = Popen(['./servo.py 5 0.25'], shell=True) elif (event.type==3 and event.code==0 and event.value==255): print("Right") p = Popen(['./servo.py 10 0.25'], shell=True) elif (event.type==3 and event.code==1 and event.value==0): print("Straigtening (Up)") p = Popen(['./servo.py 7.5 0.25'], shell=True) elif (event.type==1 and event.code==308 and event.value==1): print("Stopping (Y)") p = Popen(['./gpio.py 4 1'], shell=True) elif (event.type==1 and event.code==305 and event.value==1): print("Moving (B)") p = Popen(['./gpio.py 4 0'], shell=True) elif (event.type==1 and event.code==310 and event.value==1): print("Taking photo (L)") p = Popen(['./picture.sh'], shell=True) elif (event.type==1 and event.code==311 and event.value==1): print("Taking video (R)") p = Popen(['./video.sh'], shell=True) elif (event.type==1 and event.code==315 and event.value==1): print("Exiting") exit(0) listener.py – version “marche arrière” #!/usr/bin/env python import sys import evdev from subprocess import Popen devices = if len(devices) == 0: print ("No devices found, try running with sudo") sys.exit(1) for device in devices: print(device) device.grab() for event in device.read_loop(): if (event.type==3 and event.code==0 and event.value==0): print("Left") p = Popen(['./servo.py 5 0.25'], shell=True) elif (event.type==3 and event.code==0 and event.value==255): print("Right") p = Popen(['./servo.py 10 0.25'], shell=True) elif (event.type==3 and event.code==1 and event.value==0): print("Straigtening (Up)") p = Popen(['./servo.py 7.5 0.25'], shell=True) elif (event.type==1 and event.code==308 and event.value==1): print("Stopping (Y)") p = Popen(['./stop.py'], shell=True) elif (event.type==1 and event.code==305 and event.value==1): print("Moving (B)") p = Popen(['./forward.py'], shell=True) elif (event.type==1 and event.code==304 and event.value==1): print("Back (A)") p = Popen(['./reverse.py'], shell=True) elif (event.type==1 and event.code==310 and event.value==1): print("Taking photo (L)") p = Popen(['./picture.sh'], shell=True) elif (event.type==1 and event.code==311 and event.value==1): print("Taking video (R)") p = Popen(['./video.sh'], shell=True) elif (event.type==1 and event.code==307 and event.value==1): print("Transfering media (X)") p = Popen(['./transfer.sh'], shell=True) elif (event.type==1 and event.code==315 and event.value==1): print("Exiting") exit(0) testMotor.py #!/usr/bin/python3 import RPi.GPIO as GPIO from time import sleep import sys EnableDisable=4 DirectionBit0=17 DirectionBit1=27 GPIO.setmode(GPIO.BCM) GPIO.setwarnings(False) GPIO.setup(EnableDisable, GPIO.OUT) GPIO.setup(DirectionBit0, GPIO.OUT) GPIO.setup(DirectionBit1, GPIO.OUT) try: while True: GPIO.output(EnableDisable, GPIO.LOW) sleep(1) print("forward") GPIO.output(DirectionBit0, GPIO.LOW) GPIO.output(DirectionBit1, GPIO.HIGH) GPIO.output(EnableDisable, GPIO.HIGH) sleep(2) GPIO.output(EnableDisable, GPIO.LOW) sleep(1) print("reverse") GPIO.output(DirectionBit0, GPIO.HIGH) GPIO.output(DirectionBit1, GPIO.LOW) GPIO.output(EnableDisable, GPIO.HIGH) sleep(2) except KeyboardInterrupt: print ("exiting") GPIO.cleanup() GPIO.cleanup() video.sh #!/bin/bash dateTime=`date +%Y%m%d-%H%M%S` videoDirectory=/home/pi/videos echo "Taking a video for 10 seconds" raspivid -t 10000 -o $videoDirectory/$dateTime.h264 picture.sh #!/bin/bash dateTime=`date +%Y%m%d-%H%M%S` pictureDirectory=/home/pi/pictures raspistill -o $pictureDirectory/$dateTime.jpg stop.py #!/usr/bin/python3 import RPi.GPIO as GPIO from time import sleep import sys EnableDisable=4 GPIO.setmode(GPIO.BCM) GPIO.setwarnings(False) GPIO.setup(EnableDisable, GPIO.OUT) GPIO.output(EnableDisable, GPIO.LOW) GPIO.cleanup() forward.py #!/usr/bin/python3 import RPi.GPIO as GPIO from time import sleep import sys EnableDisable=4 DirectionBit0=17 DirectionBit1=27 GPIO.setmode(GPIO.BCM) GPIO.setwarnings(False) GPIO.setup(EnableDisable, GPIO.OUT) GPIO.setup(DirectionBit0, GPIO.OUT) GPIO.setup(DirectionBit1, GPIO.OUT) print("forward") GPIO.output(DirectionBit0, GPIO.HIGH) GPIO.output(DirectionBit1, GPIO.LOW) GPIO.output(EnableDisable, GPIO.HIGH) reverse.py #!/usr/bin/python3 import RPi.GPIO as GPIO from time import sleep import sys EnableDisable=4 DirectionBit0=17 DirectionBit1=27 GPIO.setmode(GPIO.BCM) GPIO.setwarnings(False) GPIO.setup(EnableDisable, GPIO.OUT) GPIO.setup(DirectionBit0, GPIO.OUT) GPIO.setup(DirectionBit1, GPIO.OUT) print("forward") GPIO.output(DirectionBit0, GPIO.LOW) GPIO.output(DirectionBit1, GPIO.HIGH) GPIO.output(EnableDisable, GPIO.HIGH) Test et vidéo [...] Lego + Raspberry = voiture télécommandée – Partie 1Après la borne rétrogaming à base de Raspberry 3, place aux Lego avec un Raspberry Pi 0W embarqué largement inspiré de cet article 🙂 Afin de rester dans la thématique “rétro”, je suis resté sur de vieux Lego techniques et uniquement ceux en ma possession. Le Set 8850 m’a bien été utile pour la propulsion et la direction du véhicule. Afin de mener à bien ce projet, je l’ai découpé en plusieurs parties, partant d’une solution “simple”, à savoir créer une véhicule télécommandé et capable de tourner via une manette de jeu BT, pour arriver à un véhicule “espion” avec une caméra et pouvant être contrôlé en SSH depuis l’extérieur. Le montage électrique Pour cette 1ère étape, avant d’assembler 2 pièces de Lego ensemble, le montage électrique utilisé comprant : un raspberry 0W pour profiter de la connexion BT et Wifi (simplifié par Gnd/Vcc/IO); un servo moteur pour contrôler la direction des roues; ce servo moteur sera asservi depuis l’entrée GPIO 18 du RP; deux moteurs Lego pour avancer; 1 seul pourrait suffire mais 2 moteurs donnent carrément plus de puissance et donc de vitesse. Les moteurs sont montés en parallèle; une batterie externe 5V capable d’alimenter le RP et le servo motezr; deux piles 6LR61 9V montées en série pour alimenter les 2 moteurs Lego Note : Mes moteurs Lego fonctionnent sur du 9V et peuvent “tourner” dans les 2 sens si on inverse la polarité. Ce point sera particulièrement utile lors de l’ajout de la fonctionnalité “marche arrière” du véhicule; Les moteurs ne sont pas asservis et démarrent donc dès le branchement de la batterie. Ce point sera amélioré dans la partie suivante avec l’ajout d’un relais, contrôlé par la GPIO 4 du RP; les moteurs Lego en ma possession sont de vieux moteurs de type 2838, pas très performants. Même si je possède de nouveaux moteurs, je suis resté sur ces vieux moteurs afin de ne pas mélanger nouveaux et anciens. Le site Philohome compare les moteurs produits par Lego. Il semble possible de directement alimenter des moteurs Lego à partir des GPIO 17 et 18 du RP et de gérer le “sens” du moteur avec 2 pin (cf. article de Karl). Mais avec mes moteurs “old school” ayant besoin de 9V, pas possible de réaliser ce type de montage. Validation du montage et test des GPIO Une fois le connecteur externe soudé au RP, on peut tester la GPIO 18. Pour cela, le binaire gpio de WiringPi est particulièrement utile. Mais il faut d’abord l’installer via les commandes suivantes : $ sudo apt-get install git-core $ sudo apt-get update $ sudo apt-get upgrade $ cd $ git clone git://git.drogon.net/wiringPi $ cd ~/wiringPi $ git pull origin $ cd ~/wiringPi $ ./build $ cd $ gpio -v Pour WiringPi, la même sortie peut avoir jusqu’à 3 noms différents : en mode BOARD (numérotation physique de 1 à 40 des pins) en mode BCM (Broadcom SOC channel) pour faire référence à une GPIO pilotable en mode wiringPI Les GPIO du Raspberry Pi 0 Une fois installé, on peut commander les GPIO directement depuis un terminal. La fonction gpio readall permet de voir l’état des sorties et les nomenclatures possibles (BCM, wPi et Physical). Pour activer la GPIO 18, il suffit de taper les commandes suivantes : $ gpio -g mode 18 out && gpio -g write 18 1 L’option -g permet d’indiquer à wPi l’utilisation de la nomenclature BCM. Et pour éteindre la sortie, $ gpio -g write 18 0 Les mêmes contrôles sont possibles en Python avec le package RPi.GPIO. Un simple sudo apt-get install python-dev python-rpi.gpio permet d’installer la suite complète. Le code équivalent en Python est le suivant : #!/usr/bin/env python import RPi.GPIO as GPIO from time import sleep import sys GPIO.setmode(GPIO.BCM) GPIO.setwarnings(False) GPIO.setup(18, GPIO.OUT) GPIO.output(18, GPIO.HIGH) sleep(3) GPIO.output(18, GPIO.LOW) GPIO.cleanup() Pour visualiser le résultat, un buzzer ou une LED relié à la GPIO permet de valider le bon fonctionnement de la sortie. Appairage de la manette BT via bluetoothctl La manette BT est une des manettes BT de ma borne d’arcade rétrogaming. Je l’ai donc appairé en ligne de commande et je lance ensuite un script pour réaliser la connexion BT une fois la manette allumé. La binaire utilisé est bluetoothctl. Une fois la manette appairée, la connexion se fait au démarrage via un script. Les commandes de base pour bluetoothctl sont : power on pour s’assurer que le bluetooth est bien activé agent on pour s’assurer que le bluetooth fonctionne scan on pour rechercher les périphériques bluetooth à proximité La commande scan on renvoie les @MAC des périphériques BT. A vous d’identifier la bonne @MAC pour se connecter dessus. connect suivi de l’@ MAC connect E4:17:D8:EA:65:6A Les scripts Pour pouvoir télécommander le véhicule à partir d’une télécommande, je suis parti sur le langage Python. Très rapidement, un simple listener sur une manette BT appairée permet d’exécuter les scripts nécessaires pour contrôler son véhicule. Pour le listener, les lignes print(event.type) et print(repr(event)) peuvent vous aider pour trouver le code correspondant à votre manette. Dans ce 1er jet de listener, les directions “Avant”, “Droite” et “Gauche” sont détectées avec la touche “Start” pour stopper le listener. La touche “Avant” permet de remettre les roues droite autopair.sh #!/bin/bash bluetoothctl << EOF connect E4:17:D8:EA:65:6A EOF listener.py #!/usr/bin/env python import sys import evdev from subprocess import Popen devices = if len(devices) == 0: print ("No devices found, try running with sudo") sys.exit(1) for device in devices: print(device) device.grab() for event in device.read_loop(): if (event.type==3 and event.code==0 and event.value==0): print("Left") p = Popen(['./servo.py 5 0.25'], shell=True) elif (event.type==3 and event.code==0 and event.value==255): print("Right") p = Popen(['./servo.py 10 0.25'], shell=True) elif (event.type==3 and event.code==1 and event.value==0): print("Straigtening (Up)") p = Popen(['./servo.py 7.5 0.25'], shell=True) elif (event.type==1 and event.code==315 and event.value==1): print("Exiting") exit(0) testServo.py #!/usr/bin/python3 import RPi.GPIO as GPIO import time import sys import math GPIO.setmode(GPIO.BCM) GPIO.setwarnings(False) GPIO.setup(4, GPIO.OUT) htz=50 dc=7.5 min=dc-3 max=dc+3 print ("dc", dc) print ("min ", min) print ("max ", max) p = GPIO.PWM(4, htz) p.start(dc) p.ChangeDutyCycle(dc) time.sleep(2) try: while True: print ("move to DC position") p.ChangeDutyCycle(dc) time.sleep(2) print ("move to right", min) p.ChangeDutyCycle(min) time.sleep(2) print ("move to DC position") p.ChangeDutyCycle(dc) time.sleep(2) print ("move to left", max) p.ChangeDutyCycle(max) time.sleep(2) except KeyboardInterrupt: time.sleep(2) p.ChangeDutyCycle(dc) time.sleep(2) p.stop() GPIO.cleanup() p.stop() GPIO.cleanup() servo.py #!/usr/bin/python3 import RPi.GPIO as GPIO import time import sys GPIO.setmode(GPIO.BCM) GPIO.setwarnings(False) GPIO.setup(18, GPIO.OUT) p = GPIO.PWM(18, 50) p.start(7.5) p.ChangeDutyCycle(float(sys.argv)) time.sleep(float(sys.argv)) p.stop() GPIO.cleanup() Assemblage du Lego Pour l’assemblage du Lego, il a d’abord fallu réfléchir à quelques points essentiels pour s’assurer de pouvoir : diriger le véhicule via le servo moteur; faire avancer le véhicule avec deux moteurs; caser les différents éléments du circuit dans différents logements : le RP la batterie externe les piles 9V pour les moteurs les 2 moteurs Lego Le servo moteur les composants rajoutés ultérieurement (relais, circuit électrique, caméra; …) construire un chassis suffisamment grand pour tout accueillir sans être trop lourd; réaliser le tout avec les pièces de Lego à ma disposition. La direction Comme mentionné ci-dessus, le set 8850 m’a été d’une grande utilité. J’ai réutilisé le mécanisme de direction proposé dans ce set. Deux axes parallèles dont un mobile et l’autre fixe. L’axe mobile cranté est bougé grace à une petite roue. Un axe perpendiculaire est ensuite ajouté et c’est cet axe qui est ensuite asservi au servo moteur. La propulsion Hormis le fait que les moteurs sont des 9V, rien de spécial à signaler. J’ai préféré “additionner” la puissance des 2 moteurs pour faire tourner les 2 roues ensemble que coupler 1 moteur sur 1 roue. Et plutôt que d’utiliser des roues crantées, j’ai utilisé des élastiques comme suggéré dans la motorisation du Set 8850. Le montage est le suivant : Les logements Pour éviter que tous les composants ne bougent sans cesse, il a fallu créer des compartiments pour les éléments suivants : le raspberry 0 le servo moteur relié à la direction la batterie externe qui sert d’alimentation au servo moteur et au RP les 2 piles 9V en série pour pouvoir donner suffisamment de puissance aux 2 moteurs Lego 9V le bornier permettant de relier les différents composants et éviter de faire de vilaines soudures Test et video Test de la direction avec le script testServo.py Test de la voiture sur circuit privé 🙂 [...] Ma borne d’arcadeComme beaucoup. j’ai succombé à l’appel du RetroGaming et j’ai moi aussi voulu monter ma “borne d’arcade” pour pouvoir jouer à mes vieux jeux sans utiliser la TV. Le côte nomade de la borne m’a tout de suite séduit car je peux ainsi la déplacer dans la maison ou à l’extérieur et ainsi jouer ou regarder des séries. Et étant nostalgique de l’iMac G3, la bouboule d’Apple, j’en ai profité pour recycler le caisson pour abriter le hardware à base d’un Raspberry PI 3. Le matériel Description Coût Fournisseur Kit RP3 71,99€ Amazon Convertisseur HDMI->VGA 7,59€ Amazon Paire d’enceinte mini-Jack/USB 13,00€ Amazon Ecran 15” TFT LG L1511S 16,90€ eBay Manette Bluetooth 8BitDo SFC30 29,99€ Amazon Coque iMac G3 Récup Prise USB Récup Clavier USB Récup Prise multiple Récup Colle, vis, scotch,… Récup DD USB Récup Manette USB Récup Total 139,47€ Pour la manette BT, j’ai opté pour la 8BitDo SFC30, qui ressemble à la manette SNES. Une manette BT de la PS3 aurait également fait l’affaire, simple question de préférence. Pour l’écran 15”, j’ai dû essayer pas mal d’écran de récupération avant de trouver le bon. En effet, la plupart des écrans testés étaient bien des 15” mais avec une caisson bien plus grand que les dimensions du G3. En effet, le G3 contient à la base un 15” CRT et non un 15” TFT. Le montage Attention : le désassemblage de l’iMac G3 peut s’avérer dangereux, il est vivement recommandé de lire des tutoriels pour démonter le G3, notamment la partie alimentation et l’écran. Pour l’écran, il a fallu faire de la place. A l’aide d’une pince coupante, j’ai fait sauter tout le contour en plastique qui servait à maintenir le 15” CRT. Une fois la place faite, l’écran 15” TFT s’insère pile poil. Pour le maintenir, j’ai utilisé une latte en bois afin de maintenir l’écran. Pour les enceintes, j’ai désossé ces dernières afin de récupérer uniquement le haut-parleur. Chaque haut-parleur a ensuite été collé avec un pistolet à colle à l’emplacement prévu. Pour le RP 3 et la connectique, j’ai confectionné un cache en carton pour pouvoir le maintenir à hauteur de la sortie des USB. J’ai utilisé du scotch pour éviter que les fils se baladent partout et du scotch double-face pour maintenir la prise multiple. La prise multiple alimente l’écran, les enceintes, une sortie mini-USB pour recharger les manettes BT et le RP3. Pour l’assemblage finale des 2 morceaux de coque et rendre ainsi le tout transportable, ayant fait sauté pas mal de bout de plastique, j’utilise des systèmes de protection pour les enfants pour ne pas ouvrir les tiroirs. Etant équipé de 3 mini loutors, j’ai utilisé 2 systèmes restants dans mon fourbi. Sur le côté, je laisse dépasser le contrôle du son des enceintes, afin de pouvoir régler le son rapidement sans passer par le réglage logiciel et un câble mini-USB pour recharger une manette BT. Le DD est également en externe afin de pouvoir facilement le débrancher pour rajouter des ROMs depuis mon Mac. Pour le rangement des manettes, j’utilise des legos pour pouvoir accrocher les manettes. Le câble de la multiprise peut se rentrer facilement pour rendre le déplacement de l’ensemble plus élégant :=). Le logiciel Pour le choix du logiciel, j’ai d’abord testé RecalBox mais j’ai rencontré pas mal de soucis lors de la configuration avec les manettes BT ou mon Wifi. Au bout d’une journée sans pouvoir faire fonctionner le Wifi ou en perdant les synchros BT de mes manettes, j’ai donc décidé de tester une autre solution, RetroPie. Pour la comparaison entre RecalBox et RetroPie, cet article résume bien les différences avec avantages/inconvéniants de chaque solution. “Recalbox Is Best If You’re New or Want Something Simple, RetroPie Is for People Who Need Control” Au bout de quelques heures, tout fonctionnait : le wifi, les différentes manettes, Kodi et j’ai pu attaquer la customisation futile (splashscreen) avant de pouvoir jouer 🙂 La manette d’arcade En bonus, j’ai craqué pour la réalisation de ma propre borne d’arcade à partir des plans de construction de Fredrik Setterberg. Ayant pas mal d’outils et de “stock”, je n’ai pas eu besoin d’acheter grand-chose ou alors, j’ai pu emprunter ce qu’il me manquer. Description Coût Fournisseur Kit éléctronique 20,89€ Amazon VARIERA 10,00€ IKEA APTITLIG 12,99€ IKEA Total 43,88€ [...] Une alternative au duo Squid/SquidguardLa mise en place d’un contrôle parentale à la maison peut s’avérer un poil complexe. En effet, outre la recompilation de Squid 3.5 sur Debian Jessie, on peut observer certains ralentissements au niveau du proxy. Une alternative simple et rapide est une protection de type DNS, permettant d’autoriser ou non l’accès à certains sites. Certains sites Web, dont le site Web OpenDNS propose donc des serveurs DNS faisant office de “contrôle parentale” : ce sont ces serveurs DNS qui font autoriser ou non certains sites en fonction d’un filtre pré-configuré pour bloquer le contenu destiné à des adultes. Pour la plupart des sites proposant ce genre de service gratuit, je n’ai trouvé aucune information sur le type de site filtré ou de catégorie, … Mais notons que ce type de service existe ! Un rapide bilan des avantages/inconvénient Pro Con Facile d’utilisation Mise à jour des sites et domaines gérée par un tiers Gratuit, pas de compte à créer Pas de maîtrise sur les sites autorisés ou non (pas de white list ou black list) Pas de maîtrise sur les appareils autorisés ou non Pas de notion de plage horaire Pour l’inconvénient “Pas de maîtrise sur les appareils autorisés ou non“, il est possible de remédier à ce souci grâce à un serveur DHCP local. Ayant installé le paquet isc-dhcp-server sur Raspbian, il est facile de spécifier un serveur DNS pour un périphérique appartenant au réseau en se basant sur l’adresse MAC. Pour cet exemple, je me base sur le service proposé par le site OpenDNS Ci-dessous, un extrait de mon fichier /etc/dhcp/dhcpd.conf avec l’utilisation des serveurs DNS de Google (8.8.8.8) par défaut et pour un périphérique particulier, le serveur DNS d’OpenDNS (208.67.222.123) : subnet 192.168.1.0 netmask 255.255.255.0 { interface eth0 ; prepend domain-name-servers 8.8.8.8; option domain-name-servers 8.8.8.8; option routers 192.168.1.5 ; range 192.168.1.250 192.168.1.254; host device1 { hardware ethernet 00:AA:22:CC:44:EE ; option domain-name-servers 208.67.222.123 ;} # tablette de Loutor } Rien de bien compliqué à mettre en place et cela permet donc de maîtriser simplement quel appareil a accès à un contenu filtré ou non. [...] Polar ProTrainer sur Windows 10Si vous utilisez toujours un récepteur InfraRouge (IR) pour envoyer les données de votre montre RS (RS400 pour ma part), le passage à Windows 10 est un poil compliqué. Il faut faire quelques manipulations pour réactiver la prise en charge IrDA. Prérequis Windows 10 version 1511 (accessible via Settings -> About) Téléchargement des programmes d’installation Polar ProTrainer est gratuitement disponible sur le site de Polar. L’installation se fait en double cliquant sur le programme d’installation. En plus du programme d’installation, les drivers sont nécessaires. Rien de nouveau jusqu’ici, il faut faire l’installation complète de l’application et des drivers. Activation du IrDA La procédure du site Microsoft On commence par réinitialiser le protocole IrDA ouvrir une invite de commande avec les droits administrateurs (clic droit sur le logo Windows de la barre des tâches) Dans le commande prompt, saisir les commandes suivantes netcfg -u ms_irda netcfg -c p -I ms_irda Vider le cache de la configuration précédente. Pour ma part, je n’ai pas eu besoin de réaliser cette étape car ce point s’occupe d’adaptateur IrDA réseaux. Redémarrer le PC Vérifier que le protocole IrDA est bien pris en charge désormais ouvrir une invite de commande avec les droits administrateurs (clic droit sur le logo Windows de la barre des tâches) Dans le commande prompt, saisir les commandes suivantes sc query irda sc query irmon La 2ème commande doit retourner le statut “Running”, indiquant que le protocole IrDA est de nouveau pris en charge. Configuration dans ProTrainer Dans l’application, la configuration est la suivante. Puis, comme auparavant, on lance la communication entre l’adaptateur IrDA et la montre pour récupérer ses données. C’est fini, vous pouvez de nouveau transférer vos données depuis votre montre vers ProTrainer ou autres 🙂 [...] Comparatif Cardio – Polar RS400, iPhone & iWatchSuite à la lecture de plusieurs articles vantant la précision de l’iWatch sur le cardio, j’ai voulu moi-même comparé les résultats par rapport à 2 autres dispositifs : ma RS400 avec son émetteur mon iPhone avec un cardio BT, le H7 Cette curiosité est parti du fait suivant : avec le cardio natif de l’iWatch, mon coeur semblait dépasser très rarement les 170 bpm lors de mes sorties fractionnées. Alors que durant d’autres entraînements sportifs tous aussi intenses, un p’tit 180 apparaissait furtivement… J’ai donc décidé de ressortir ma vielle RS400 de son placard et de comparer les données brutes sur quelques séances. Matériel Polar RS400 avec émetteur WearLink Coded iWatch Series 2 avec l’application native “Workout” et le mode “Outdoor Run” Polar H7 en Bluetooth avec RunKeeper sur un iPhone 6 Fréquence Première constatation qui a un impact assez important sur la pertinence des calculs, notamment le calcul des calories dépensées : la fréquence des mesures. iWatch : les points semblent enregistrés de manière “événementielle” Polar RS400 : configurable avec 1 , 5, 15 ou 60 secondes comme intervalle Polar H7 : les points semblent enregistrés de manière “événementielle” J’ai envisagé de passer l’intervalle de temps de la RS400 à 1 seconde pour pouvoir être sûr de “caler” une mesure iWatch/H7 à une mesure RS400 mais le temps d’enregistrement devenait alors de 30mn environ. J’ai donc conservé les 5 secondes en laissant Excel faire le reste pour l’affichage des données sous forme de graphe. Pour l’iWatch, j’ai bien suivi les recommandations d’Apple sur la manière de porter la montre suffisamment serrée autour du poignet. Je n’ai pas poussé l’expérience jusqu’à me raser le poignet pour améliorer la qualité de ma peau. Pour la capture des données, j’ai utilisé l’application native de la montre, “Workout”. Les sorties Sortie n°1 : séance de fractionné sur 45mn environ 5′ d’échauffement 12 x 77”/55” 12-14′ au calme Sortie n°2 : séance libre de 8km en 48mn avec 200 mètres de dénivelé positif Sortie n°3 : séance libre de 11km en 67mm avec 230 mètres de dénivelé positif Sortie n°4 : séance de fractionné sur 45mn environ (identique à la séance n°1) A la fin de chaque sortie, j’ai récupéré les données brutes des différents dispositifs, à savoir : le fichier HRM de Polar, le fichier XML avec les données de l’iWatch le fichier GPX sur RunKeeper avec les données cardio du H7 J’ai ensuite formaté ces données dans des fichiers CSV fort simple : “HH:MM:SS;BPM“. Au final, la plus grande plage de temps commune a été utilisée. Comparaison des données Date Source Min Max Moyenne Nb point % nb point Temps Fréquence Delta min Delta max 01.06.2017 iWatch 121 191 152 454 -17.45% 00:45:40 00:00:06 00:00:01 00:00:47 RS400 120 187 151 550 00:45:45 00:00:05 00:00:05 00:00:05 05.06.2017 H7 121 164 143 580 +16.70% 00:41:16 00:00:04 00:00:02 00:00:32 RS400 120 165 144 497 00:41:20 00:00:05 00:00:05 00:00:05 26.06.2017 H7 79 169 150 964 +19.60% 01:07:12 00:00:04 00:00:03 00:01:32 RS400 71 167 148 806 01:07:05 00:00:05 00:00:05 00:00:05 iWatch 108 169 151 699 -13.28% 01:07:18 00:00:06 00:00:01 00:02:12 29.06.2017 H7 79 168 147 694 +25.05% 00:46:22 00:00:04 00:00:02 00:00:19 RS400 80 169 145 555 00:46:10 00:00:05 00:00:05 00:00:05 iWatch 82 180 146 327 -41.08% 00:45:52 00:00:08 00:00:01 00:05:40 (1) appairé avec RunKeeper / iPhone 6 Le “delta” est la différence de temps entre 2 points consécutifs. Un 1er constat rapide : Les moyennes cardio sont très proches, avec 3 bpm de différence max lors de la sortie du 26.06.2017, ce qui semble prometteur. La RS400 capturant systématiquement un point toutes les 5 secondes, on peut se poser la question de quelle fréquence est enregistrée lorsque le capteur a un soucis L’iWatch décroche à chaque séance pendant plusieurs minutes, sans pouvoir enregistrer de données. le nombre de points capturés diffèrent énormément. En prenant la RS400 comme point de comparaison (car utilisé sur l’ensemble des séances), l’iWatch capture entre -13% et -41% de points en moins alors que RK avec le H7 capture 16% à 25% de points en plus. Bien entendu, cet écart est d’autant plus important que l’iWatch ou le H7 décroche pendant plusieurs minutes. Même avec quelques décrochages, le H7 capture plus de points que la RS400, ce qui laisse envisager une meilleure précision pour les données capturées. Calories dépensées Pour le calcul des calories, je me suis basé sur la formule suivante : Calorie = ((-55.0969 + (0.6309 x FCmoy) + (0.1988 x P) + (0.2017 x A))/4.184) x 60 x T avec : FCmoy la fréquence cardiaque moyenne de la séance P le poids (83 kg) A l’âge (35 ans) T la durée de séance en heure Cette formule fonctionne pour un homme et est imparfaite pour les raisons suivantes (liste non exhaustive) : Elle ne tient pas compte de la VO2 max. On peut obtenir des calories “négatives”. En prenant un FC moy de 49 bpm sur 1 heure, on obtient -9 calories… et 0 calorie pour une FC moy de 50 bpm. FCmoy n’est pas assez précis. Il faut donc prendre l’échantillon FC par rapport à la mesure précédente. T devient donc l’intervalle de temps en heure entre 2 mesures. La formule étant linéaire (cf. ci-dessous), on peut en déduire que 1 minute d’exercice représente 0.15 calorie pour un homme de 35 ans à 83 kg et que 60 bpm pendant 1 minute consomme 1.51 calorie. J’ai donc calculé la dépense énergétique en calorie pour chaque séance et je l’ai comparé : pour la RS400, à la valeur indiquée par la montre et remontée dans Polar Pro Trainer pour le duo RK/H7, à la valeur indiquée par RK dans le résumé de la séance avec les données cardiaque du H7 pour l’iWatch, à la valeur indiquée dans l’application “Health” Date Source Calcul Relevé Écart1 Écart2 26.06.2017 H7 995.52 1040 4.47% 0.59% RS400 989.52 879 -11.18% iWatch 1017.52 713 -29.93% 2.81% 29.06.2017 H7 676.59 710 7.51% 0.42% RS400 659.14 594 -9.68% iWatch 663.26 511 -26.66% 5.95% 1 entre le calcul et le relevé 2 entre la RS400 et la source sur le calcul théorique Et là, c’est le chaos… Les écarts font jusqu’à 30% par rapport à la formule théorique et de 6% entre eux (séance du 05.06.2017). Je me doute que chaque application à sa propre formule pour calculer les calories dépensées et que la comparaison n’est donc pas pertinente. Je n’ai donc même pas calculé les écarts entre les relevés pour la même séance. Il est tout de même rassurant de voir que la RS400 et le H7 sont assez proches pour les résultats sur le calcul théorique (< 1%). La dépense énergétique semble donc être une métrique peu fiable et plus compliquée à maîtriser que la fréquence cardiaque. Note et graphique des sorties Sortie n°1 Durant cette sortie, j’ai constaté durant ma course que la montre a “perdu” mon pouls durant 1’20”, soit 16 enregistrements côté RS400. J’ai donc supprimé cet intervalle pour le calcul de la moyenne. Malgré une différence d’une centaine de points environ en faveur de la RS400, les résultats sont très proches pour la fréquence moyenne et le min/max de mon cœur. La méthode de capture du pouls mis en place sur l’iWatch semble efficace. Le graphe ci-dessous trace les courbes de mon pouls et le résultat est assez surprenant… La 1ère partie de la sortie, à savoir le fractionné diffère énormément alors que la 2nd partie, le retour au calme est très proche. L’impression obtenu est que les gros “écarts” de pouls suite aux accélérations brusques sont mal gérés par un des deux dispositifs. On note également des “ratés” de l’iWatch sur la 7ème accélération (un pic trop important) et la 11ème accélération (une accélération non-détectée). Sortie n°2 Concernant les données cardio du H7, ces dernières ne sont pas “brutes” car relevées par RunKeeper. Je ne sais pas ce que fait RK lorsque la position GPS est de mauvaise qualité. Le point est-il omis ? De manière générale, les courbes sont très proches, un seul décrochement “non-justifiée” pour la RS400 Sortie n°3 La totale : RS400, H7 et iWatch ! Comme pour les sorties précédentes, la RS400 et le capteur H7 sont assez proches dans les données. On note un décrochement de 1:32 pour le H7 et 2:12 pour l’iWatch, qui ne semblent pas pouvoir capturer la fréquence cardiaque durant certains intervalles. Pour l’iWatch, on observe des aberrations en début de parcours avec des “pics” non justifiés, un poul trop rapide au départ (>120bpm) et un arrêt au feu rouge (à 11h35) mal détecté. Sortie n°4 La totale de nouveau: RS400, H7 et iWatch ! A nouveau, la RS400 et le capteur H7 sont assez proches dans les données. Toujours avec l’iWatch, on observe des aberrations en début de parcours et des “pics” non justifiés. Conclusion Pour ma part, le cardio fréquencemètre de l’iWatch ne tient donc pas les promesses vantées. On peut discuter de la mesure du pouls mais les décrochages trop nombreux et longs rendent les mesures plus que discutables. Le capteur reste de l’ordre du gadget pour mesurer son pouls pendant une courte période et en étant statique (dans son lit, sur une chaise, …) mais ne semble pas adapté pour des séances sportives. Pour la RS400 et le H7, les données semblent fiables mais il est plus agréable d’avoir l’iWatch à son poignet que la RS400. La combinaison gagnante pour mes sorties est l’iWatch couplé en BlueTooth avec le H7 et RunKeeper sur l’iPhone et l’iWatch. Ainsi, le pouls affiché sur l’iWatch est bien le pouls capturé par le H7 et je peux contrôler RK depuis la montre. Seul bémol avec cette configuration : les instructions audio de RK ne sont pas disponibles. Ressources https://support.apple.com/en-us/HT204666 https://9to5mac.com/2015/05/08/apple-watch-heart-rate-monitor-accuracy/ http://www.shapesense.com/fitness-exercise/calculators/heart-rate-based-calorie-burn-calculator.shtml [...] Dockerisation d’un serveur LAMPAfin de rendre pérenne un vieux site en PHP qui ne supportait plus de mise à jour, j’ai du dockerisé ce dernier dans un serveur LAMP afin de pouvoir continuer à mettre à jour ma debian sans me soucier des EOL et ainsi de profiter des dernières mises à jour de sécurité et fonctionnalité au niveau de l’OS hôte. Prérequis Pour utiliser Docker, un Kernel Linux > 3.10 est nécessaire. Je suis parti d’une Debian Jessie 8.0 pour réaliser le container. $ uname -a Linux gally 3.18.48 Installation de Docker L’installation se fait assez simplement. On installe d’abord des paquets nécessaire à Docker, la clef GPG de Docker, les repo Debian, Docker et des outils tierces comme Docker-compose $ sudo apt-get install apt-transport-https ca-certificates curl gnupg2 software-properties-common python-pip $ curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add - $ sudo add-apt-repository "deb https://download.docker.com/linux/debian $(lsb_release -cs) stable" $ sudo apt-get update $ sudo apt-get install docker-ce $ sudo pip install docker-compose Puis, on vérifie la bonne installation de Docker. Ce dernier va télécharger le container de test et l’executer. $ sudo docker run hello-world Unable to find image 'hello-world:latest' locally latest: Pulling from library/hello-world 78445dd45222: Pull complete Digest: sha256:c5515758d4c5e1e838e9cd307f6c6a0d620b5e07e6f927b07d05f6d12a1ac8d7 Status: Downloaded newer image for hello-world:latest Hello from Docker! This message shows that your installation appears to be working correctly. To generate this message, Docker took the following steps: 1. The Docker client contacted the Docker daemon. 2. The Docker daemon pulled the "hello-world" image from the Docker Hub. 3. The Docker daemon created a new container from that image which runs the executable that produces the output you are currently reading. 4. The Docker daemon streamed that output to the Docker client, which sent it to your terminal. To try something more ambitious, you can run an Ubuntu container with: $ docker run -it ubuntu bash Share images, automate workflows, and more with a free Docker ID: https://cloud.docker.com/ For more examples and ideas, visit: https://docs.docker.com/engine/userguide/ La commande docker version retourne la version Client: Version: 17.03.1-ce API version: 1.27 Go version: go1.7.5 Git commit: c6d412e Built: Mon Mar 27 17:07:28 2017 OS/Arch: linux/amd64 Server: Version: 17.03.1-ce API version: 1.27 (minimum version 1.12) Go version: go1.7.5 Git commit: c6d412e Built: Mon Mar 27 17:07:28 2017 OS/Arch: linux/amd64 Experimental: false Modification du driver de stockage Par défaut, le driver de stockage utilisé par Docker est le “devicemapper (loop)” Ce driver n’est pas recommandé par Docker pour un environnement de “production” Docker hosts running the devicemapper storage driver default to a configuration mode known as loop-lvm. This mode uses sparse files to build the thin pool used by image and container snapshots. The mode is designed to work out-of-the-box with no additional configuration. However, production deployments should not run under loop-lvm mode. J’ai préféré utiliser le driver “overlay”, disponible sur les kernels Linux >= 3.18 car ma VM est assez légère côté ressource. Pour cela, c’est assez simple. On vérifie que le module est bien chargé au niveau du noyau, sinon, il faut l’installer. Par chance, ce module est déjà présent sur ma distrib. $ sudo service docker stop $ sudo modprob overlay $ lsmod | grep over overlay 29421 0 $ sudo service Ensuite, il suffit de configurer le fichier /etc/docker/daemon.json (ou le créer si besoin) avec les lignes suivantes : { "storage-driver": "overlay" } Puis, on redémarre le service $ sudo service docker start $ docker info Storage Driver: overlay Backing Filesystem: extfs Supports d_type: true Fin de la partie configuration pour Docker ! Vue d’ensemble et structure Pour des raisons bien précises, le serveur de la base de données est séparé du serveur Web. Il y a donc à minima 2 containers, l’idée étant de pouvoir rajouter des images du container Web pour faire du failover ou d’autres containers Web avec des versions plus récentes d’Apache et/ou PHP. Le serveur Web Pour la création du container, je suis parti d’une image officielle de Debian/wheezy. A partir de ce container, il faut rajouter les paquets souhaités, faire un downgrade de PHP et rajouter un peu de configuration pour obtenir un serveur Web Apache 2.2-PHP5.3 Le contenu du fichier WebDockerfile est le suivant : FROM debian:wheezy WORKDIR ./ ENV DEBIAN_FRONTEND noninteractive ENV APACHE_RUN_USER www-data ENV APACHE_RUN_GROUP www-data ENV APACHE_LOG_DIR /var/log/apache2 ENV APACHE_LOCK_DIR /var/lock/apache2 ENV APACHE_PID_FILE /var/run/apache2.pid #Set preferences for PHP installation COPY config/preferences /etc/apt/preferences.d/ #Add old GPG keys RUN gpg --keyserver pgpkeys.mit.edu --recv-key 8B48AD6246925553 RUN gpg -a --export 8B48AD6246925553 | apt-key add - RUN apt-get update RUN apt-get -y install nano apt-utils debconf-utils apache2 #Add squeeze repo RUN echo 'deb http://archive.debian.org/debian-archive/debian/ squeeze main contrib non-free' >> /etc/apt/sources.list RUN echo 'deb http://archive.debian.org/debian-archive/debian/ squeeze-lts main contrib non-free' >> /etc/apt/sources.list RUN gpg --keyserver pgpkeys.mit.edu --recv-key 64481591B98321F9 RUN gpg -a --export 64481591B98321F9 | apt-key add - RUN gpg --keyserver pgpkeys.mit.edu --recv-key AED4B06F473041FA RUN gpg -a --export AED4B06F473041FA | apt-key add - #Update repo RUN apt-get -o Acquire::Check-Valid-Until=false update #Install packages RUN apt-get -y install php5 libapache2-mod-php5 php5-mysql php5-gd RUN apt-mark hold php5 libapache2-mod-php5 #Copy configuration files RUN mkdir -p /etc/apache2/conf.d/ COPY config/apache2.conf /etc/apache2/ COPY config/ports.conf /etc/apache2/ COPY config/envvars /etc/apache2/ COPY config/default.conf /etc/apache2/sites-available/ RUN a2ensite default.conf RUN a2enmod rewrite FROM debian:wheezy WORKDIR ./ ENV DEBIAN_FRONTEND noninteractive ENV APACHE_RUN_USER www-data ENV APACHE_RUN_GROUP www-data ENV APACHE_LOG_DIR /var/log/apache2 ENV APACHE_LOCK_DIR /var/lock/apache2 ENV APACHE_PID_FILE /var/run/apache2.pid #Set preferences for PHP installation COPY config/preferences /etc/apt/preferences.d/ #Add old GPG keys RUN gpg --keyserver pgpkeys.mit.edu --recv-key 8B48AD6246925553 RUN gpg -a --export 8B48AD6246925553 | apt-key add - RUN apt-get update RUN apt-get -y install nano apt-utils debconf-utils apache2 #Add squeeze repo RUN echo 'deb http://archive.debian.org/debian-archive/debian/ squeeze main contrib non-free' >> /etc/apt/sources.list RUN echo 'deb http://archive.debian.org/debian-archive/debian/ squeeze-lts main contrib non-free' >> /etc/apt/sources.list RUN gpg --keyserver pgpkeys.mit.edu --recv-key 64481591B98321F9 RUN gpg -a --export 64481591B98321F9 | apt-key add - RUN gpg --keyserver pgpkeys.mit.edu --recv-key AED4B06F473041FA RUN gpg -a --export AED4B06F473041FA | apt-key add - #Update repo RUN apt-get -o Acquire::Check-Valid-Until=false update #Install packages RUN apt-get -y install php5 libapache2-mod-php5 php5-mysql php5-gd RUN apt-mark hold php5 libapache2-mod-php5 #Copy configuration files RUN mkdir -p /etc/apache2/conf.d/ COPY config/apache2.conf /etc/apache2/ COPY config/ports.conf /etc/apache2/ COPY config/envvars /etc/apache2/ COPY config/default.conf /etc/apache2/sites-available/ RUN a2ensite default.conf RUN a2enmod rewrite # Remove APT files RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* # Make port 8080 available to the world outside this container EXPOSE 8080 # Remove APT files RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* # Make port 8080 available to the world outside this container EXPOSE 8080 # Start services CMD ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"] Les fichiers apache2.conf, envvars, default.conf et ports.conf sont les fichiers de configuration utilisés par Apache. Ils sont intégrés dans le container Web et proviennent de la configuration déjà réalisée. Le fichier preferences indique la version à installer pour PHP Package: php5* Pin: version 5.3* Pin-Priority: 700 Package: libapache2-mod-php5 Pin: version 5.3* Pin-Priority: 700 Package: php-pear Pin: version 5.3* Pin-Priority: 700 Package: php-apc Pin: version 3.1.3p* Pin-Priority: 700 Package: * Pin: release a=stable Pin-Priority: 600 Fichier de test n°1 Au niveau du fichier Dockerfile, le fichier www/info.php pour tester le bon fonctionnement de notre serveur Web. Le fichier n’est pas intégré au container mais disponible sur un répertoire partagé entre l’instance de notre container et la Debian. <?php phpinfo(); ?> Le fichier docker-compose.yml Ce fichier est le fichier décrivant comment les différents containers sont lancés et communiquent entre eux. version: "3" services: web: image: cweb ports: - "80:80" volumes: - /var/www:/var/www On crée le container décrit dans le fichier Dockerfile puis on lance son exécution en mappant le port 80 de l’instance sur le port 80 de la Debian et le répertoire /var/www de l’instance sur le répertoire /var/www de la Debian. $ docker build -f WebDockerfile -t cweb . $ docker-compose up Puis, on se connecte en local sur le port 80 (http://localhost/info.php) pour vérifier que tout fonctionne correctement et afficher le PHP info. Le serveur de base de données Un des gros avantages de docker est la mise à disposition de nombreuses images prêtes à l’emploi. Il suffit donc de récupérer la version MySQL souhaité directement et de la lancer avec les bons paramètres. Il suffit donc de mettre le fichier docker-compose.yml à jour pour rajouter ce serveur de base de données et le faire communiquer avec le serveur Web. version: "3" services: db: image: mysql/mysql-server:5.5 environment: - MYSQL_ROOT_PASSWORD=mysql - MYSQL_DATABASE=test - MYSQL_USER=test - MYSQL_PASSWORD=test web: image: cweb ports: - "80:80" volumes: - /var/www:/var/www links: - db Fichier de test n°2 Toujours au niveau du fichier Dockerfile, le fichier www/mysql.php pour vérifier la connexion entre le serveur Web et le serveur de base de données. <?php echo "Connecting to MySQL<br />"; mysqli_connect("db", "root", "") or die(mysqli_error()); echo "Connected to MySQL<br />"; ?> Il suffit ensuite de lancer de nouveau la commande suivante et de se connecter sur http://localhost/mysql.php pour vérifier la connexion MySQL: $ docker-compose up PhpMyAdmin Histoire de pouvoir administrer les bases de données et créer des utilisateurs, PhpMyAdmin est installé via un autre container, prêt à l’emploi. Une nouvelle section est rajouté au fichier docker-compose.yml. Le mot de passe MYSQL_ROOT_PASSWORD doit être identique dans les 2 sections. version: "3" services: db: image: mysql/mysql-server:5.5 volumes: - /var/lib/mysql:/var/lib/mysql restart: always environment: - MYSQL_ROOT_PASSWORD=mysql - MYSQL_DATABASE=test - MYSQL_USER=test - MYSQL_PASSWORD=test web: depends_on: - db image: cweb restart: always ports: - "80:80" volumes: - /var/www:/var/www links: - db:mysql phpmyadmin: depends_on: - db image: phpmyadmin/phpmyadmin restart: always ports: - "81:80" environment: - PMA_HOST=db - MYSQL_ROOT_PASSWORD=mysql links: - db:mysql De nouveau, on exécute la commande ci-dessous et on se connecte sur http://localhost:81 $ docker-compose up [...] Surveillance Station, iSight et iPhone 3GSHistoire d’utiliser l’application Surveillance Station de Synology, je me suis amusé à configurer mes webcams en tant que caméra. Après plusieurs essais, voici les configurations et scripts utilisés iPhone 3GS La seule application gratuite et compatible avec Surveillance Station pour le 3GS que j’ai trouvée sur l’AppStore est “Mini WebCam“. Simple, cette application a néanmoins plusieurs défauts : l’écran doit rester allumer, pas de mot de passe, réglages très basiques mais c’est gratuit. Une fois la qualité de la vidéo et le port choisi, l’appli se lance et la diffusion commence. Sur Surveillance Station, on rajoute la caméra avec les propriétés suivantes : Le nom de la caméra L’adresse IP Marque : Défini par utiisateur Chemin source : /video Et le tour est joué iSight Pour streamer la webcam iSight des iMac et MacBook, j’utilise VLC. La ligne de commande qui fonctionne le mieux pour moi est la suivante : #!/bin/sh su - vlc -c "/Applications/VLC.app/Contents/MacOS/VLC http qtcapture:// --sout='#transcode{vcodec=mjpg,vb=3000,fps=30,width=1280,height=1024}:std{access=http{mime=\"multipart/x-mixed-repla\ ce;boundary=7b3cc56e5f51db803f790dad720ed50a\"},dst=:8888/out.mpg,mux=mpjpeg}'" avec les droits en execution sur le script sudo chmod 755 /home/vlc/iSight_start.sh La ligne de commande utilise su car je souhaite que VLC n’apparaisse pas dans le Dock. J’ai donc crée un utilisateur vlc, fait quelques ajustements sur cet utilisateur pour le limiter au maximum et je lance la commande ci-dessous avec le compte root. Pour démarrer le streaming au démarrage, il suffit de rajouter le fichier suivant : sudo /Library/LaunchDaemons/com.loutor.vlcsight.plist <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key> <string>com.loutor.vlcsight</string> <key>Program</key> <string>/home/vlc/iSight_start.sh</string> <key>RunAtLoad</key> <true/> </dict> </plist> et de mettre les droits corrects dessus sudo chown root:wheel /Library/LaunchDaemons/com.loutor.vlcsight.plist sudo chmod 644 /Library/LaunchDaemons/com.loutor.vlcsight.plist Si besoin, il est possible de rajouter des logs sur le service pour diagnostiquer les causes d’échec au démarrage, juste avant la balise </dict> <key>StandardErrorPath</key> <string>/var/log/com.loutor.vlcsight.err</string> <key>StandardOutPath</key> <string>/var/log/com.loutor.vlcsight.log</string> On lance ensuite le service avec launchctl sudo launchctl load /Library/LaunchDaemons/com.loutor.vlcsight.plist Sur Surveillance Station, on rajoute la caméra avec les propriétés suivantes : Le nom de la caméra L’adresse IP sur le port 8888 Marque : Défini par utiisateur Chemin source : /out.mpg [...] Externaliser la gestion des filtres de Gmail via imapfilterLes labels sous Gmail et les filtres associés sont assez limités; il est impossible d’appliquer 2 labels en même temps et tous les filtres sont appliqués les uns après les autres, ce qui peut donner des résultats assez surprenants. Afin de palier à ces limites, la gestion de mes filtres est assurée par imapfilter installé sur un serveur externe. Installation du package sudo apt-get install imapfilter mkdir ~/.imapfilter touch ~/.imapfilter/config.lua echo "GMAIL PWD" > ~/.imapfilter/.password.offlineimaprc chmod 600 ~/.imapfilter/.password.offlineimaprc Configuration de imapfilter function main() -- more timeout options.timeout = 120 -- label can be created options.create = true -- authorize subscription options.subscribe = true -- ignore SSL certificates issue options.certificates = false -- Gmail account local home = IMAP { server = 'imap.gmail.com', username = '<EMAIL ADDRESS>', password = get_imap_password(".imapfilter/.password.offlineimaprc"), ssl = 'ssl3', } -- filter by subject move_subject(home, "INBOX", "NEWSLETTER", "Newsletter") -- filter by sender move_sender(home, "INBOX", "FACEBOOK", "@facebookmail.com") end function move_subject(imap, from, to, pattern) local messages = imap:contain_subject(pattern) messages:move_messages(imap) end function move_sender(imap, from, to, pattern) local messages = imap:contain_from(pattern) messages:move_messages(imap) end function get_imap_password(file) local home = os.getenv("HOME") local file = home .. "/" .. file local str = io.open(file):read() return str; end -- start imapfilter as daemon and run check every 3 seconds become_daemon(3, main) Lancement au démarrage Création du script/etc/init.d/imapfilter via son éditeur préféré sudo nano /etc/init.d/imapfilter #!/bin/sh #/etc/init.d/imapfilter PID=`ps -elf | grep '/usr/bin/imapfilter' | grep -v grep | awk '{print $4}'` # The following part carries out specific functions depending on arguments. case "$1" in start) echo "Starting imapfilter" su - YOUR_USER -c '/usr/bin/imapfilter -c ~/.imapfilter/config.lua' ;; stop) echo "Stopping imapfilter" kill -9 $PID ;; *) echo "Usage: /etc/init.d/imapfilter {start|stop}" exit 1 ;; esac exit 0 On règle les droits et ajout des scripts au démarrage (dans /etc/rc0.d) sudo chmod 755 /etc/init.d/imapfilter sudo update-rc.d imapfilter defaults Ressources utilisées https://github.com/lefcha/imapfilter https://gist.github.com/dylanwh/408810 https://raymii.org/s/blog/Filtering_IMAP_mail_with_imapfilter.html http://blog.endpoint.com/2015/11/taking-control-of-your-imap-mail-with.html https://baptiste-wicht.com/posts/2014/07/a-mutt-journey-filter-mails-with-imapfilter.html [...] Créer des configurations client en fonction des profils OpenVPN pour mieux gérer les accèsSi comme moi, vous avez installé un serveur OpenVPN sur votre RP préféré, il vous est peut-être arrivé d’avoir besoin de séparer les besoins suivants : uniquement avoir accès à son réseau local à distance (accéder à un NAS non connecté à Internet, l’interface Web du routeur Wifi. pour dépanner un pote de passage..) mettre en place un proxy Internet pour contourner le firewall d’une entreprise combiner les 2 donner un accès à une ressource particulière à un tiers Et pour cela, l’utilisation de la variable client-config-dir va nous être très utile Avant de commencer la configuration, les choix suivants ont été faits : le réseau 10.8.1.0 correspond au besoin 1, le réseau local uniquement le réseau 10.8.2.0 correspond au besoin 2, le proxy uniquement pour contourner les firewalls le réseau 10.8.0.0 correspond au besoin 3, à savoir un accès à mon réseau local + proxy le besoin 4 n’est pas traité dans ce post On édite le fichier de configuration du serveur vpn /etc/openvpn/server.conf dans mon cas et on s’intéresse aux lignes rouges. On déclare les 3 réseaux, les routes correspondantes et le chemin du répertoire contenant des fichiers de configuration spécifiques aux clients. port 1194 proto tcp dev tun script-security 3 ca /etc/openvpn/certs/ca.crt cert /etc/openvpn/certs/pumpkin.crt key /etc/openvpn/certs/pumpkin.key dh /etc/openvpn/certs/dh2048.pem tls-auth /etc/openvpn/certs/ta.key 0 crl-verify /etc/openvpn/crl.pem #all : local network + internet gw server 10.8.0.0 255.255.255.0 #local network only server 10.8.1.0 255.255.255.0 #internet gw only server 10.8.2.0 255.255.255.0 client-config-dir ccd route 10.8.0.0 255.255.255.0 route 10.8.1.0 255.255.255.0 route 10.8.2.0 255.255.255.0 keepalive 1800 4000 cipher AES-256-CBC comp-lzo max-clients 3 user nobody group nogroup persist-key persist-tun log /var/log/ovpn/openvpn.log status /var/log/ovpn/openvpn-status.log verb 5 mute 20 On crée le répertoire en question sudo mkdir /etc/openvpn/ccd On crée ensuite les fichiers client en fonction du CN des profils crées. /etc/openvpn % sudo cat /etc/openvpn/easy-rsa/keys/index.txt V 270320145652Z 03 unknown /C=FR/ST=FR/L=MaVille/O=MaVille/OU=LoutorInc/CN=besoin3-all/name=localhost/emailAddress=admin@domain.com V 270320145721Z 04 unknown /C=FR/ST=FR/L=MaVille/O=MaVille/OU=LoutorInc/CN=besoin1-local/name=localhost/emailAddress=admin@domain.com V 270320145758Z 05 unknown /C=FR/ST=FR/L=MaVille/O=MaVille/OU=LoutorInc/CN=besoin2-gw/name=localhost/emailAddress=admin@domain.com Le contenu du fichier /etc/openvpn/ccd/besoin1-local, à ajuster en fonction de votre réseau local ifconfig-push 10.8.1.2 10.8.1.1 push "route 10.8.0.1 255.255.255.255" push "route 10.8.0.0 255.255.255.0" push "route 192.168.1.0 255.255.255.0" Le contenu du fichier /etc/openvpn/ccd/besoin2-gw ifconfig-push 10.8.2.2 10.8.2.1 push "route 10.8.0.1 255.255.255.255" push "route 10.8.0.0 255.255.255.0" push "redirect-gateway def1" Le contenu du fichier /etc/openvpn/ccd/besoin3-all, à ajuster en fonction de votre réseau local ifconfig-push 10.8.0.2 10.8.0.1 push "route 10.8.0.1 255.255.255.255" push "route 10.8.0.0 255.255.255.0" push "route 192.168.1.0 255.255.255.0" push "dhcp-option DNS 192.168.1.5" push "redirect-gateway def1" On édite ensuite les règles IPTables pour autoriser ou non la redirection vers le réseau local (eth0) ou Internet (eth1) Les 2 règles POSTROUTING dans nat reroutent automiquement le trafic de 10.8.0.0/24 (tun0) et de 10.8.0.2/24 (tun0) vers Internet (eth1), ce qui correspond aux besoins 2 et 3 Les 2 premières règles FORWARD/ACCEPT dans filter autorisent le trafic d’OpenVPN (tun0) vers Internet (eth1), ce qui correspond aux besoins 2 et 3 Les 2 règles suivantes INPUT et OUTPUT autorisent les paquets entrants et sortants de l’interface OpenVPN (tun0), ce qui correspond aux besoins 1, 2 et 3 La dernière règle FORWARD/DROP interdit les paquets de tun0 ayant une adresse IP de type 10.8.2.X vers le réseau local (eth0), ce qui correspond aux besoins 2 (pas d’accès au réseau local) *nat -A POSTROUTING -s 10.8.0.0/24 -o eth1 -j MASQUERADE -A POSTROUTING -s 10.8.2.0/24 -o eth1 -j MASQUERADE COMMIT *filter -A FORWARD -s 10.8.0.0/24 -i tun0 -o eth1 -j ACCEPT -m comment --comment "Accept forward Internal (tun0) to External (eth1)" -A FORWARD -s 10.8.2.0/24 -i tun0 -o eth1 -j ACCEPT -m comment --comment "Accept forward Internal (tun0) to External (eth1)" -A INPUT -i tun0 -j ACCEPT -m comment --comment " Accept incoming packet" -A OUTPUT -o tun0 -j ACCEPT -m comment --comment " Accept outgoing packet" -I FORWARD -i tun0 -o eth0 -s 10.8.2.0/24 -d 192.168.1.0/24 -j DROP COMMIT Si on regarde rapidement les logs OpenVPN, on peut vérifier que le serveur charge la bonne configuration client en fonction du profil et envoie les bonnes informations au client Fri Mar 24 10:17:22 2017 us=93304 178.197.231.226:13903 Control Channel: TLSv1, cipher TLSv1/SSLv3 DHE-RSA-AES256-SHA, 2048 bit RSA Fri Mar 24 10:17:22 2017 us=93505 178.197.231.226:13903 Peer Connection Initiated with 178.197.231.226:13903 Fri Mar 24 10:17:22 2017 us=93715 besoin2-gw/178.197.231.226:13903 OPTIONS IMPORT: reading client specific options from: ccd/besoin2-gw Fri Mar 24 10:17:22 2017 us=94109 besoin2-gw/178.197.231.226:13903 MULTI: Learn: 10.8.2.2 -> besoin2-gw/178.197.231.226:13903 Fri Mar 24 10:17:22 2017 us=94248 besoin2-gw/178.197.231.226:13903 MULTI: primary virtual IP for besoin2-gw/178.197.231.226:13903: 10.8.2.2 RFri Mar 24 10:17:23 2017 us=225647 besoin2-gw/178.197.231.226:13903 PUSH: Received control message: 'PUSH_REQUEST' Fri Mar 24 10:17:23 2017 us=225838 besoin2-gw/178.197.231.226:13903 send_push_reply(): safe_cap=940 Fri Mar 24 10:17:23 2017 us=226036 besoin2-gw/178.197.231.226:13903 SENT CONTROL : 'PUSH_REPLY,route 10.8.2.1,topology net30,ping 1800,ping-restart 4000,route 10.8.0.1 255.255.255.255,route 10.8.0.0 255.255.255.0,redirect-gateway def1,ifconfig 10.8.2.2 10.8.2.1' (status=1) [...] Mettre en place une protection parentale pour la familleEt c’est parti pour la mise en place d’une protection parentale pour la famille afin de filtrer les accès Web (et leurs contenus) de manière transparente pour tous les périphériques de la famille. Les loutors finiront un jour par avoir accès à Internet et je préfère prendre les devants pour éviter toute surprise. Pour cela, j’utilise mon Raspberry PI 3, installé avec Raspbian Jessie en tant que passerelle, pour séparer mon réseau interne d’Internet. Vu que le RP fait office de passerelle avec 2 interfaces réseaux, eth0 en interne et eth1 en externe, la configuration routeur est déjà faite et je ne détaillerai pas ces opérations dans ce post. Pour mettre en place cette protection parentale, les paquets suivants seront installés Squid3 qui assure la partie “proxy” et intercepte les protocoles HTTP et HTTPS SquidGuard qui autorise ou non les domaines à visiter, les IP du réseaux locales, les heures de navigation, … IpTables pour rerouter le trafic HTTP et HTTPS sur squid pour rendre le proxy “transparent” Nginx avec le support PHP pour afficher une belle page Web en cas de site non-autorisé Quelle version de Squid ? Par défaut, la version de Squid est la 3.4. Cette version ne permet pas de gérer le protocole HTTPS de manière simple (SSL bumping très rudimentaire). Avec la version 3.4, on est obligé de déployer un certificat SSL sur les PC/tabelettes/smartphone pour pouvoir décrypter le contenu des paquets. En effet, les navigateurs récents stoppent toute connexion HTTPS dès qu’une activité suspecte sur le certificat est détecté. Vu que Squid 3.4 remplace le certificat du site distant par un certificat dynamique, le navigateur pense à une attaque de type “Man In The Middle”. Mais outre les questions d’éthique (je ne peux plus proposer à mes invités ma connexion Wifi) que cela peut poser en plus des problèmes de sécurité, le déploiement du certificat SSL me parait trop lourd. La version 3.5 introduit une nouvelle option, “Peek and Splice” dans la fonctionnalité ssl_bump qui permet de choisir quelle partie de la connexion SSL on souhaite vérifier. Dans notre cas, on souhaite vérifier le nom de domaine lors du TCP CONNECT en HTTPS et non le contenu des données ou l’URL. Il va donc falloir récupérer les sources de Squid 3.5 et les recompiler à la sauce Debian. Mise à jour de sa distrib’ On commence tout d’abord par une petite mise à jour de sa distribution favorite sudo apt-get update sudo apt-get upgrade sudo reboot Compilation de Squid 3.5 On installe les paquets nécessaires, on télécharge les sources de squid 3.5, on édite quelques fichiers et on compile le tout #Installation des paquets sudo apt-get install devscripts build-essential fakeroot debhelper dh-autoreconf cdbs sudo apt-get build-dep squid3 sudo apt-get install libssl-dev #Création du répertoire pour la compilation mkdir -p ~/build/squid3 cd ~/build/squid3 #Récupération et décompilation des sources wget http://http.debian.net/debian/pool/main/s/squid3/squid3_3.5.23-3.dsc wget http://http.debian.net/debian/pool/main/s/squid3/squid3_3.5.23.orig.tar.gz wget http://http.debian.net/debian/pool/main/s/squid3/squid3_3.5.23-3.debian.tar.xz dpkg-source -x squid3_3.5.23-3.dsc cd squid3-3.5.23 A ce stade, il faut modifier 2 fichiers pour que la compilation se déroule correctement : ~/build/squid3/squid3-3.5.23/debian/rules : les flags de compilation sont ajustés pour rajouter le support SSL (non activé par défaut) + suppression d’option d’authentification inutile DEB_CONFIGURE_EXTRA_FLAGS := BUILDCXXFLAGS="$(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS)" \ --datadir=/usr/share/squid \ --sysconfdir=/etc/squid3 \ --libexecdir=/usr/lib/squid \ --mandir=/usr/share/man \ --enable-inline \ --disable-arch-native \ --enable-async-io=8 \ --enable-storeio="ufs,aufs,diskd,rock" \ --enable-removal-policies="lru,heap" \ --enable-delay-pools \ --enable-cache-digests \ --enable-icap-client \ --enable-follow-x-forwarded-for \ --enable-auth-basic="DB,fake,getpwnam,LDAP,NCSA,NIS,PAM,POP3,RADIUS,SASL,SMB" \ --enable-auth-digest="file,LDAP" \ --enable-auth-negotiate="kerberos,wrapper" \ --enable-auth-ntlm="fake,smb_lm" \ --enable-external-acl-helpers="file_userip,kerberos_ldap_group,LDAP_group,session,SQL_session,time_quota,unix_group,wbinfo_group" \ --enable-url-rewrite-helpers="fake" \ --enable-eui \ --enable-esi \ --enable-icmp \ --enable-zph-qos \ --disable-translation \ --with-swapdir=/var/spool/squid \ --with-logdir=/var/log/squid \ --with-pidfile=/var/run/squid.pid \ --with-filedescriptors=65536 \ --with-large-files \ --with-default-user=proxy \ --with-openssl \ --enable-ssl \ --enable-ssl-crtd ~/build/squid3/squid3-3.5.23/debian/control : la ligne de contrôle des dépendances est mise à jour pour supprimer des dépendances inutiles Build-Depends: libldap2-dev, libpam0g-dev, libdb-dev, cdbs, libsasl2-dev, debhelper, libcppunit-dev, libkrb5-dev, comerr-dev, libcap2-dev , libexpat1-dev, libxml2-dev, autotools-dev, libltdl-dev, dpkg-dev (>= 1.16.1~), pkg-config, libnetfilter-conntrack-dev , nettle-dev, libgnutls28-dev, lsb-release Puis on lance la compilation #Compilation ./configure debuild -us -uc -b Installation de Squid 3.5 Une fois la compilation terminée, on peut installer les paquets fraîchement compilés cd ~/build/squid3 #Installation des paquets sudo dpkg -i squid-common_3.5.23-3_all.deb squidclient_3.5.23-3_armhf.deb squid_3.5.23-3_armhf.deb #On marque le paquet pour éviter une mise à jour sudo apt-mark hold squid squid-common On crée maintenant le fichier /etc/squid3/squid.conf, on rajoute son réseau et on l’autorise avec 2-3 autres modifications. Comme beaucoup de réseaux locaux, le mien est en 192.168.1.X. Pour la génération du certificat SSL, j’ai réutilisé celui déjà mis en place au niveau du serveur Nginx en tant que reverse proxy. La procédure de création du certificat n’est donc pas décrite. Le fichier doit ressembler à ça : #Définition des ACL acl SSL_ports port 443 acl Safe_ports port 80 # http acl Safe_ports port 21 # ftp acl Safe_ports port 443 # https acl Safe_ports port 70 # gopher acl Safe_ports port 210 # wais acl Safe_ports port 1025-65535 # unregistered ports acl Safe_ports port 280 # http-mgmt acl Safe_ports port 488 # gss-http acl Safe_ports port 591 # filemaker acl Safe_ports port 777 # multiling http acl CONNECT method CONNECT #Le réseau local acl LocalNet src 192.168.1.0/24 #ACL : Liste des domaines non-vérifiés acl broken_sites ssl::server_name .google.com acl broken_sites ssl::server_name .google.fr acl broken_sites ssl::server_name .google.ch acl bump_step1 at_step SslBump1 #Définition des autorisations http_access deny !Safe_ports http_access deny CONNECT !SSL_ports http_access allow localhost manager http_access deny manager http_access allow localhost http_access allow LocalNet http_access deny all #Configuration du SSL proxy sslproxy_cert_error allow all sslproxy_flags DONT_VERIFY_PEER sslproxy_options NO_SSLv2,NO_SSLv3,SINGLE_DH_USE #Localhost et les sites sur liste blanche ne sont pas vérifiés ssl_bump splice localhost ssl_bump splice broken_sites #On ne vérifie que CONNECT ssl_bump peek bump_step1 all ssl_bump splice all #Définition des ports d'écoute http_port 3128 transparent https_port 3129 transparent ssl-bump generate-host-certificates=on version=4 \ cafile=/etc/certs/example.pem \ cert=/etc/certs/example.crt \ key=/etc/erts/example.key coredump_dir /var/spool/squid3 refresh_pattern ^ftp: 1440 20% 10080 refresh_pattern ^gopher: 1440 0% 1440 refresh_pattern -i (/cgi-bin/|\?) 0 0% 0 refresh_pattern . 0 20% 4320 cache_dir ufs /cache 400 16 256 cache_access_log /var/log/squid3/access.log cache_effective_user proxy Une fois la configuration de Squid3 faite, on s’occupe du répertoire /cache visant à améliorer la navigation. Le DD étant une SD, je monte ce répertoire en RAM plutôt que sur la SD pour économiser la flash. sudo mkdir /cache Vient l’édition du fichier /etc/fstab afin de monter 500Mo de RAM dans le répertoire /cache. La taille de 500Mo est à ajuster en fonction de la taille de cache déclarée dans le fichier /etc/squid3/squid.conf. Il est recommandé de ne pas utiliser 100% du /cache mais 80% (500 x 80% = 400). D’où les 400Mo déclaré dans /etc/squid3/squid.conf et les 500Mo dans /etc/fstab. tmpfs /cache tmpfs defaults,noatime,nosuid,size=500m 0 0 Un redémarrage des services et on peut désormais tester notre serveur proxy depuis un poste. L’IP de mon raspberry est 192.168.1.5. La navigation Internet doit pouvoir s’effectuer sans souci depuis le poste client. sudo service squid3 stop sudo squid3 -z sudo service squid3 start SquidGuard Comme précédemment, on installe les paquets nécessaires. sudo apt-get install squidguard Maintenant, il s’agit d’utiliser des listes contenant les sites et contenus interdits ou à surveiller. L’université de Toulouse met à disposition gracieusement de telles listes et on va donc récupérer ces listes pour les utiliser. sudo cd /var/lib/squidguard/db/ sudo wget http://dsi.ut-capitole.fr/blacklists/download/blacklists.tar.gz sudo tar -zxvf blacklists.tar.gz sudo chown -R proxy:proxy /var/lib/squidguard/db/ On édite le fichier /etc/squidguard/squidGuard.conf avec la liste des IP des appareils autorisés à tous les contenus (déclaration du group parents). Pour chaque contenu non-autorisé, un fichier *contenu*.access est crée dans le répertoire /var/log/squidguard afin de logguer les tentatives d’accès. dbhome /var/lib/squidguard/db logdir /var/log/squidguard src parents { ip 192.168.1.90 } dest ads { domainlist blacklists/ads/domains urllist blacklists/ads/urls log ads.access } dest adult { domainlist blacklists/adult/domains urllist blacklists/adult/urls log adult.access } dest aggressive { domainlist blacklists/aggressive/domains urllist blacklists/aggressive/urls log aggressive.access } dest agressif { domainlist blacklists/agressif/domains urllist blacklists/agressif/urls log agressif.access } dest arjel { domainlist blacklists/arjel/domains log arjel.access } dest drogue { domainlist blacklists/drogue/domains urllist blacklists/drogue/urls log drogue.access } dest drugs { domainlist blacklists/drugs/domains urllist blacklists/drugs/urls log drugs.access } dest malware { domainlist blacklists/malware/domains urllist blacklists/malware/urls log malware.access } dest mixed_adult { domainlist blacklists/mixed_adult/domains urllist blacklists/mixed_adult/urls log mixed_adult.access } dest phishing { domainlist blacklists/phishing/domains urllist blacklists/phishing/urls log phishing.access } dest porn { domainlist blacklists/porn/domains urllist blacklists/porn/urls log porn.access } dest proxy { domainlist blacklists/proxy/domains urllist blacklists/proxy/urls log proxy.access } dest sexual_education { domainlist blacklists/sexual_education/domains urllist blacklists/sexual_education/urls log sexual_education.access } dest violence { domainlist blacklists/violence/domains urllist blacklists/violence/urls log violence.access } dest warez { domainlist blacklists/warez/domains urllist blacklists/warez/urls log warez.access } acl { parents { pass all } default { pass !ads !adult !aggressive !agressif !arjel !drogue !drugs !malware !mixed_adult !phishing !porn !proxy !sexual_education !violence !warez all redirect http://192.168.1.5/block.php?caddr=%a&cname=%n&user=%i&group=%s&target=%t&url=%u } } On charge les listes téléchargées dans squidGuard. A noter que ces 2 commandes doivent être relancées à chaque modification du fichier /etc/squidguard/squidGuard.conf sudo squidGuard -C all sudo chown -R proxy:proxy /var/lib/squidguard/db/ Nouvelle édition du fichier /etc/squid3/squid.conf pour rajouter la ligne suivante url_rewrite_program /usr/bin/squidGuard -c /etc/squidguard/squidGuard.conf Re redémarrage des services et nouveau test sur un site interdit sudo service squid3 stop sudo squid3 -z sudo service squid3 start La page suivante doit apparaître, ce qui est normal vu que nginx n’a pas encore été installé et configuré Côté log, on peut voir que les connexions HTTP et HTTPS sont bien interceptées 1496669801.800 50 192.168.1.30 TAG_NONE/503 0 CONNECT www.y*****n.com:443 - HIER_NONE/- - 1496670016.301 6 192.168.1.30 TCP_MISS/200 1614 GET http://www.y*****n.com/ - HIER_DIRECT/192.168.1.5 text/html Nginx Comme vu, on installe les paquets nécessaires sudo apt-get install nginx php5-fpm On édite le fichier /etc/php5/fpm/pool.d/www.conf pour décommenter/vérifier la ligne suivante listen = /var/run/php5-fpm.sock Vu que squidGuard et Nginx tournent sur la même machine, on utilise donc une socket Unix pour la communication. On redémarre PHP5 sudo service php5-fpm restart On crée un nouveau fichier /etc/nginx/conf.d/php5-fpm.conf pour indiquer la location de la socket upstream php5-fpm-sock { server unix:/var/run/php5-fpm.sock; } Puis, édition du fichier /etc/nginx/sites-available/default pour prendre en charger les fichiers *.php et fixer les accès. On autorise seulement l’accès au réseau local server { listen 80; root /var/www/squidguard; index block.php; server_name localhost; location / { try_files $uri $uri/ /block.php; allow 192.168.1.0/8; allow 127.0.0.1; deny all; } location ~ \.php$ { try_files $uri $uri/ =404; fastcgi_index block.php; fastcgi_pass php5-fpm-sock; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include /etc/nginx/fastcgi_params; } } Un petit fichier de test pour vérifier que Nginx avec le support PHP5 fonctionne bien echo '<?php phpinfo(); ?>' > /var/www/squidguard/info.php On redémarre Nginx et on affiche la page PHP Info sudo service nginx restart SquidGuard, le retour On va customiser notre page indiquant les sites bloqués. Pour cela, on crée le fichier /var/www/squidguard/block.php Site Web bloqué Contrôle parentale activé pour ce poste Accès refusé ! Site Web bloqué URL: Web Filtering by Squid3 and SquidGuard on Pumpkin Puis le fichier /var/www/squidguard/filter.css @CHARSET "UTF-8"; body { background-color: #ffffff; font-family: verdana, arial, sans serif; } div.outer { width: 70%; margin: 20px auto; } div.header { padding: 10px; background-color: #c0c0c0; text-align: right; font-size: 60%; } div.footer { padding: 5px; background-color: #c0c0c0; text-align: right; font-size: 60%; } div.inner { text-align: center; background-color: #f4f4f4; text-align: center; padding: 20px; } div.msg { padding: 20px; margin-top: 20px; background-color: #e2e2e2; color: black; font-size: 80%; } div.error { letter-spacing: 0.5em; word-spacing: 1em; padding: 20px; background-color: #ff0000; color: white; font-size: 200%; font-weight: bold; } Un nouveau test sur un contenu interdit en HTTP devrait nous afficher la jolie page suivante Pour le même site mais en HTTPS, pas de jolie page Web mais un message du navigateur avertissant d’un souci de confidentialité dans la chaîne SSL entre le site et lui. Cette erreur apparaîtra sur tous les navigateurs récents (Opera Neon, Chrome, Firefox, Safari, …). Côté log, on a bien l’entrée correspondante /var/log/squidguard % tail -f adult.access 2017-06-05 17:09:00 Request(default/adult/-) http://www.youporn.com/favicon.ico 192.168.1.30/pollux.loutor - GET REDIRECT 2017-06-05 17:09:06 Request(default/adult/-) www.youporn.com:443 192.168.1.30/pollux.loutor - CONNECT REDIRECT Configuration du proxy transparent Si le paquet IPtable n’est pas déjà installé sudo apt-get install iptables Puis, mise à jour des règles IPTables pour intercepter le trafic HTTP et HTTPS et le re-router sur le port 3128 et 3129 du proxy squid3 *nat -A PREROUTING -i eth0 -p tcp -m tcp --dport 80 -j DNAT --to-destination 192.168.1.5:3128 -A PREROUTING -i eth0 -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 3128 -A PREROUTING -i eth0 -p tcp -m tcp --dport 443 -j DNAT --to-destination 192.168.1.5:3129 -A PREROUTING -i eth0 -p tcp -m tcp --dport 443 -j REDIRECT --to-ports 3129 -A POSTROUTING -s 192.168.1.0/24 -o eth1 -j MASQUERADE COMMIT On fait un nouveau test en pensant bien à désactiver la configuration proxy. Le résultat doit être le même que précédemment, la page de restriction doit s’afficher. Mise à jour des listes Histoire d’automatiser le téléchargement des listes et de toujours avoir les dernières nouveautés, un p’tit script /etc/cron.daily/blacklist.sh est mis en place #!/bin/sh cd /var/lib/squidguard/db rm -rf blacklists wget http://dsi.ut-capitole.fr/blacklists/download/blacklists.tar.gz tar -zxvf blacklists.tar.gz rm blacklists.tar.gz squidGuard -C all chown -R proxy:proxy /var/lib/squidguard/db/ service squid3 restart Ressources utilisées http://www.pihomeserver.fr/2015/09/01/un-controle-parental-grace-au-raspberry-pi-squid-et-squidguard https://adilmehmoodbutt.wordpress.com/2014/02/19/how-to-install-squid3-transparent-proxy-server/ https://www.guillaume-leduc.fr/projet-installation-configuration-nginx-php-fpm.html https://redmine.pfsense.org/issues/6777 https://docs.diladele.com/administrator_guide_5_0/install/rpi/index.html http://david.mercereau.info/serveur-proxy-squid3-avec-ssl-rebuild-debian-squeeze-package/ [...] Exporter ses playlists iTunes vers DS Audio de SynologyAfin de pouvoir utiliser les playlists gérées par iTunes sur mon NAS Synology et DSAudio, j’ai récupéré l’application Java développé par Eric Daugherty qui permet d’exporter les playlists iTunes contenues dans le fichier iTunes Library.xml au format m3u reconnu par DSAudio. J’utilise iTunesExport avec les options suivantes : -separator=MAC to have '/' separator -fileTypes=ALL to export all extension files (AAC, MP3, MP4) -musicPath=/volume1/ to set the target music path Une fois la playlist générée, j’utilise le binaire iconv pour convertir le fichier au format UTF8 Ci-dessous, le script utilisé #!/bin/sh NAS=/PATH_TO_CHANGE iTunesXML='$NAS/iTunes/iTunes Library.xml' outM3U='$NAS/playlists' java -jar $HOME/Documents/scripts/iTunesExportScala-2.2.2/itunesexport.jar -separator=MAC -outputDir="$outM3U" -library="$iTunesXML" -fileTypes=ALL -musicPath=/volume1/ find $outM3U -type f -name "*.m3u" -print0 -maxdepth 1 | while read -d $'\0' file do echo convert $file to the right utf8 iconv -f UTF8-MAC -t UTF8 "$file" > "$file" done Une fois le script mis en place, édition de ma crontab pour exécuter l’export quotidien de mes playlists loutor@pollux ~ % crontab -l #Export iTunes playlists every day at 0:30am 30 0 * * * $HOME/Documents/scripts/exportiTunesPlaylist2NAS.sh [...] Répliquer une base de données MySLQ en localAfin de pouvoir avoir une site de test, j’ai eu besoin de répliquer en continu la base de données DHC1 vers une autre base de données, DHC2, sur le même serveur MySQL 5.5 sous Debian 7 Après quelques heures de galère à configurer MySQL, voici ma configuration qui permet de réaliser cette réplication continue d’une base de données vers l’autre sur un seul serveur MySQL Configurer my.cnf Rien de bien sorcier, il suffit de recopier les lignes suivantes et de les adapter si besoin dans le fichier /etc/mysql/my.cnf Quelques vérifications de mise: la variable “skip-name-resolve” doit être présente et la variable “bind-address” contient mon adresse IP publique (important pour la suite) bind-address = PUBLIC_IP skip-name-resolve server-id = 1 replicate-same-server-id= 1 log-bin = /var/log/mysql/mysql-bin log-error = /var/log/mysql/mysql-err relay-log = /var/log/mysql/mysql-rel report-host = master-is-slave-host binlog_do_db = dhc1 replicate-do-db = dhc2 replicate-rewrite-db = dhc1->dhc2 replicate-wild-do-table = dhc2.% Redémarrage du service Le redémarrage du service démarre automatiquement le master $>/etc/init.d/mysql restart Stopping MySQL database server: mysqld. Starting MySQL database server: mysqld . .. Configurer le compte salve Il est possible de créer un compte dédié pour la replication ou de simplement utiliser le compte “owner” de la base de données cible (dhc2). On se connecte avec un compte (au hasard: root) ayant les priviléges nécessaire pour réaliser les commandes ci-dessous: $>mysql -uroot -p mysql> SHOW MASTER STATUS; +------------------+----------+--------------+------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | +------------------+----------+--------------+------------------+ | mysql-bin.000009 | 97091 | dhc1 | | +------------------+----------+--------------+------------------+ 1 row in set (0.00 sec) mysql> GRANT REPLICATION SLAVE ON *.* TO 'dhc2'@'PUBLIC_IP' IDENTIFIED BY 'password'; mysql> CHANGE MASTER TO MASTER_HOST='PUBLIC_IP', MASTER_USER='dhc2', MASTER_PASSWORD='password', MASTER_LOG_FILE='mysql-bin.000009', MASTER_LOG_POS=97091; mysql> START SLAVE; mysql> SHOW SLAVE STATUS; mysql> FLUSH PRIVILEGES; En cas de problème le site de référence: https://dev.mysql.com/doc/refman/5.5/en/replication.html Vérifier le fichier /var/log/mysql/mysql-err.err Vérifier dans SHOW SLAVE STATUS que les threads Slave_IO_Running et Slave_SQL_Running sont bien à “Yes” Utiliser phpmyadmin (version testée 3.4.11.1) pour contrôler la partie “Replication” des bases de données [...] Améliorer ses photos avec Gimp sous MacOSDepuis 3 ans maintenant, à chaque retour de vacances, un des tâches est le traitement des photos afin de les améliorer (balance des blancs, amélioration de la netteté et équilibre des couleurs). Adepte des logiciels libres, j’ai depuis longtemps adopté Gimp comme outil officiel pour les retouches photos et je passe toujours par sa ligne de commande pour traiter les 3000 photos Le résultat est relativement correct et Gimp est largement suffisant pour mes besoins. Sous Windows Le script Gimp, version 1 Ce résultat a été obtenu avec les scripts suivants pour Windows. Le 1er script (batch-photos-nett-coul-auto.scm) est le script Gimp qui charge les photos et les traite : (define (batch-unsharp-mask pattern) ; charge les images correspondant au pattern donné (let* ((filelist (cadr (file-glob pattern 1)))) ; parcourt la liste des fichiers trouvés (while (not (null? filelist)) (let* ((filename (car filelist)) (image (car (gimp-file-load 1 filename filename))) (drawable (car (gimp-image-get-active-drawable image)))) ; ameliore la nettete de l'image - NETT (plug-in-unsharp-mask 1 image drawable 5.0 0.5 0) ; fait la balance auto. des blancs - AUTO ;(gimp-levels-stretch drawable) ; ameliore les couleurs de l'image - COUL (plug-in-color-enhance 1 image drawable ) ; sauvegarde de l'image (set! drawable (car (gimp-image-get-active-layer image))) (gimp-file-save 1 image drawable filename filename) (gimp-image-delete image)) (set! filelist (cdr filelist))) ) ) Le Script Shell, version Windows Le 2ème script (call-batch-gimp.sh) parcourt les dossiers (utile si les photos sont triées par répertoire) et appelle le script Gimp sur les différents dossiers (les 2 scripts sont dans le même répertoire) : GIMPPATH="C:/Program Files/GIMP-2.0/bin" GIMPEXE=gimp-console-2.6.exe WORK_DIR=C:/MesPhotos/Lot1 DIRS=`find $WORK_DIR -name "*" -type d` LOG=C:/MesPhotos/logGimp.txt if [ ! -f "$GIMPPATH/$GIMPEXE" ]; then echo "$GIMPEXE" not exists exit 1 fi rm -f $LOG for DIR in $DIRS; do cd $DIR if ; then echo ============================================= echo Call gimp batch on $DIR $GIMPPATH/$GIMPEXE -c -d -f -s --no-shm -i -b "(batch-unsharp-mask \"*.JPG\")" ERRORLEVEL=$? echo ERRORLEVEL: $ERRORLEVEL echo echo ============================================= if ; then echo Error in $DIR >> $LOG fi fi done Ensuite, il suffit de lancer via la ligne de commande le Shell script ci-dessus pour traiter toutes les photos dans le répertoire C:/MesPhotos/Lot1. : cette solution nécessite un environnement Linux sous Windows, de type Cygwin Sous MacOS Suite à une “migration” de Windows vers MacOS, j’ai bien entendu réinstallé Gimp sur Mac et lancé mes p”tits scripts pour traiter mes photos. Hélas, hélas, hélas, il m’a fallu quelques heures avant de trouver comment faire pour que cela fonctionne et les adaptations nécessaires aux scripts. Les problèmes rencontrés ont été les suivants : Le binaire gimp-console-2.6.exe n’existe plus sous MacOS et MacOS présente des applications contenant toutes les ressources (il faut penser à ouvrir l’application via un clic droit pour voir le contenu); désormais, le chemin vers l’exécutable est /Applications/Gimp.app/Contents/Resources/bin et non plus C:/Program Files/GIMP-2.0/bin Lors du lancement de Gimp en ligne de commande, Gimp utilise les fonctions uniquement définies et enregistrées et “ne pense pas” à regarder le répertoire courant pour charger la nouvelle fonction dans le script Gimp. Il faut donc déclarer la fonction contenue dans le script au préalable et ensuite appeler la fonction avec les paramètres souhaitées. L’appel au script Gimp via le script Shell est légèrement modifié, on passe en mode lecture sur la ligne de commande Voici donc la solution que j’ai trouvé Le script Gimp, version 2 On prend le même et on lui rajoute 2 lignes uniquement à la fin du fichier pour que tout fonctionne correctement : ; appelle la fonction batch-unsharp-mask avec le pattern souhaité (batch-unsharp-mask "*.JPG") ; finit le bloc et quitte le script (gimp-quit 0) Ça peut paraitre tout bête mais c’est 2 lignes m’ont énormément coûté en temps. Le script Shell, sous MacOS GIMPPATH=/Applications/Gimp.app/Contents/MacOS GIMPEXE=gimp-2.8 DIR="/Users/admin/Pictures/to_batch/*" SCRIPT=/Users/admin/Pictures/scriptsGimp/batch-gimp.scm DIRS=`find $DIR -name "*" -type d -exec echo "{}:" ';'` PATH=$GIMPPATH:$PATH LOG=$DIR/logGimp.txt DIRS=`echo $DIRS | sed "s/: /:/g"` echo DIRS $DIRS if [ ! -f "$GIMPPATH/$GIMPEXE" ]; then echo "$GIMPEXE" can not be found exit 1 fi which $GIMPEXE if ; then echo "$GIMPEXE" can not be found exit 1 fi echo "Gimp has been found; continue process..." rm -f $LOG IFS=':' for DIR in $DIRS; do echo "cd $DIR" cd "$DIR" FILES=`ls *.JPG 2> /dev/null` if ; then echo ============================================= echo Call gimp batch on $DIR "$GIMPPATH/$GIMPEXE" -c -d -f -s -i -b - < $SCRIPT ERRORLEVEL=$? echo ERRORLEVEL: $ERRORLEVEL echo echo ============================================= if ; then echo Error in $DIR >> $LOG fi fi done echo "Process is over" Rien de bien sorcier mais il faut le savoir et y penser. Et on n’oublie pas de donner les droits d’exécution au script sh pour pouvoir l’exécuter sous MacOS [...] Récupérer les données d’un DD défectueuxBien souvent, des DD vous lâchent et aucun backup de vos précieuses données n’a malheureusement pu être réalisé… Et impossible de lire ce satané DD… Voici la solution que j’utilise systématiquement pour récupérer mes données : DD pour récupérer mes DD Tout d’abord, quelques liens: Image Ghost DD Wiki DD Man Avec ma distrib’ Linux préférée sur un CD ou une clef USB, Je démarre donc sur la distrib’ de mon choix Je monte sur /mnt/backup une partition suffisamment grande pour pouvoir héberger les données récupérables Je tape une des deux commandes suivantes : dd if=/dev/sda1 conv=noerror | gzip -9 | dd of=/mnt/backup/mon_backup-sda1.dd.gz (avec compression) dd if=/dev/sda1 conv=noerror of=/mnt/backup/mon_backup-sda1.dd (sans compression) et je laisse tourner le temps qu’il faut (48H parfois) pour créer une image des données potentiellement récupérable. Ensuite, sur un DD sain et sur une partition saine, je restore les données : dd if=/mnt/backup/mon_backup-sda1.dd of=/dev/sda1 [...] Améliorer son temps au semi, mode d’emploiSuite à mon 1er semi-marathon réalisé en 1h42m43s, j’ai voulu améliorer ce temps. En effet, suite au calcul de ma VMA et de mes temps sur 10km, le temps estimé est normalement de 1h39, soit 3mn de moins que mon temps réalisé. J’ai donc décidé de m’inscrire à un autre semi-marathon et d’améliorer mon temps, en visant un temps entre 1h37m et 1h39m. Pour réussir ce nouveau défi : entretien des mes acquis avec 2 séances par semaine, une séance EMA et une séance VMA reprise de l’entrainement sur 8 semaines avant le semi amélioration de mes connaissances sur la CPA pour mieux construire mes séances Comprendre le lien entre la VMA et la FC Tout d’abord, quel est le lien entre la VMA et la FC ? Pourquoi 95% de sa FC correspond à 90% de sa VMA ? Est-il possible d’affiner cette équivalence ? La réponse est oui ! Bien déterminer sa FC max… Il existe 3méthodes pour obtenir sa FC max (FCM) : la meilleure méthode mais aussi la moins facile à réaliser est de prendre rendez-vous avec un cardiologue. Ce dernier vous fera passer un test d’effort pour déterminer avec précision votre FCM; un test d’effort : après 20/30mn d’échauffement, commencer à courir en augmentant progressivement votre vitesse jusqu’à atteindre votre maximum et essayer de tenir cette allure pendant 3mn. Durant l’exercice, si ce dernier est réalisé avec sérieux, la plus haute fréquence atteinte est votre FCM; la dernière méthode, la plus simple et la moins fatiguante : avec une calculatrice. Ces formules représente une ‘compilation‘ de résultats observés sur un panel assez vaste de coureur. Néanmoins, il est possible qu’aucune de ces formules ne puisse approximer votre FCM. Nom Méthode Astrand et Ryhming (1954) FC = 220 – âge Inbar (1994) FCM = 205,8 – 0,685 x âge Robers et Lanwher (2002) FCM = 208,754 – 0,734 x âge Sportif régulier et sérieux FCM= 208,2 – (0.48 x âge) Sportif amateur FCM = 205,1 – (0.44 x âge) … mais aussi sa FC repos… Il est également intéressant de connaître sa FC de repos. Pour connaître votre FC au repos, il vous suffit de la prendre dès le réveil, en position allongée et avant de vous lever, pendant trois ou quatre jours afin d’en déterminer une moyenne. … pour calculer sa FC réserve et sa FC d’entrainement Une fois ces 2 FC évalués, on peut passer aux calculs de 2 autres constantes, la FC de réserve (FCR) et la FC d’entrainement (FCE). La FCR représente la différence entre la fréquence cardiaque maximale et la fréquence cardiaque de repos : FCR = FCM – FC de repos Une fois la FCR calculé, on utilise la formule de Karvonen pour déterminer la FCE : FCE = X% x FCR + FC repos, avec X% le % de VMA souhaité Exemple Un exemple est toujours plus parlant. FCM Si je reprends le tableau pour déterminer FCM, pour un coureur de 29 ans (au hasard) : Nom Méthode Astrand et Ryhming (1954) FC = 220 – âge 191 Inbar (1994) FCM = 205,8 – 0,685 x âge 186 Robers et Lanwher (2002) FCM = 208,754 – 0,734 x âge 187 Sportif régulier et sérieux FCM= 208,2 – 0.48 x âge 194 Sportif amateur FCM = 205,1 – 0.44 x âge 192 Difficile de faire le bon choix… Pour mon cas, c’est la formule du “sportif amateur” qui semble le mieux approcher ma FCM, FCM que j’ai obtenu sur un test d’effort. FC de repos Après 3 jours de mesure de ma FC de repos le matin, la moyenne obtenue est de 57 FCR er FCE Du coup, on obtient facilement les 2 constantes manquantes FCR = 192 – 57 = 135 FCE = X% x 135 + 57 Affiner les sorties Ainsi, pour une sortie EMA (85% de la VMA), la FCE est 85% x 135 + 57 = 171bpm en récupération (65% de la VMA), la FCE est 60% x 135 + 57 = 145bpm Dans le cas de notre coureur de 29 ans, on obtient les FC suivantes : Plusieurs remarques sur les différences observées : la FCE tient compte du % de VMA cible, contrairement à FC, ce qui est beaucoup plus intéressant afin de réduire la plage de FC. En effet, sans utiliser FCE, on avait l’estimation suivante : X% de VMA équivaut à X;X+5% de FCE. En incluant directement le % de VMA cible dans le calcul de FCE, on réduit l’estimation. la plage FCE 144;192 est beaucoup moins large que la plage FC 134;192, ce qui va donc ‘obliger‘ le coureur à avoir des moyennes FC durant ses sorties plus élevées et donc mieux faire travailler son cardio. Le test de VM5 pour se situer Le test de VM5 est un test intéressant à réaliser pour le coureur amateur pour approximer sa VMA. Mais une fois la VMA déterminée, comment se situer ? Pour rappel, le test de VM5 consiste à courir sur une distance connue (idéalement, une piste d’athlétisme) pendant une durée de 5 à 6mn, en essayant de courir le plus rapidement possible à la même vitesse durant toute la durée du test. Il ne faut donc pas partir à ‘fond les manettes‘ mais à une vitesse suffisamment élevée pouvant être maintenue pendant plus de 5mn. Ci-dessous, un tableau qui permet de vous donner une idée de votre niveau : Niveau du coureur VMA estimée Distance du test Débutant 10-12km/h 800 à 900m Débrouillé 13-15km/h 1000 à 1100m Confirmé 16-18km/h 1200 à 1300m Expert 19-21km/h 1400 à 1500m Quel FCE pour une course ? OK, c’est bien joli tous ces calculs, mais à quoi peuvent-ils servir ? Tout simplement à donner une idée de la FCE à maintenir sur une distance pendant une course. Pour un 10km : 90 à 95% de la FCE Pour un semi-marathon : 85 à 90% de la FCE Pour un marathon : 80 à 85% de la FCE Mieux comprendre ses besoins énergétiques : Métabolisme de base (en Kcal) = 1,083 x Poids0,48 x Taille0,5 x Age-0,13 x 1000/4,1868. : Métabolisme de base (en Kcal) = 1,083 x Poids0,48 x Taille0,5 x Age-0,13 x 889/4,1868 (avec le poids en kg, la taille en mètres et l’âge en années) Au final, ça donne quoi ? Très honnêtement, je ne sais pas encore ce que donnera ce nouvel entrainement… Je suis actuellement en train de le mettre en place et suis en phase d’entretien de mes acquis et non de préparation. La suite au prochain billet [...] Client FTP récursif avec WgetCet article n’est pas de moi mais il m’a été tellement utile que j’ai préféré en faire une copie ! Lien original Il me faut faire une moulinette infernale. Le travail consiste à récupérer récursivement une arborescence monstrueuse sur un serveur ftp avant de procéder à l’agrégation et au traitement des données. D’ordinaire, pour un script complet allant de la récupération des données à leur intégration en base de données, j’aurais utilisé totalement Ruby. Je dis bien “j’aurais” car ce n’est pas le cas. J’ai utilisé Ruby pour le traitement des fichiers et l’alimentation de la base mais, vu les limitations des fonctionnalités FTP imposées par Ruby, il me semblait beaucoup trop contraignant de perdre un temps fou, sur une chose aussi triviale, à triturer ce langage. J’ai donc porté mon dévolu sur la commande wget qui fait parfaitement office de ftp récursif en… une ligne. $wget -r -P/home/demoi/ -nH –cut-dirs=8 –ftp-user nom_login –ftp-password mot_de_passe ftp://ftp.prout.fr/../../arbo/des/fichiers/*’ Descriptif des options utilisées : -r : récupération récursive de l’arborescence -P/home/demoi : Le répertoire (/home/demoi) dans lequel vont attérir les fichiers downloadés -nH/ : Désactive la génération de la racine des répertoires avec le nom de l’hôte. Par défaut, l’invocation de wget avec -r http://ftp.prout.fr/ crée une hiérarchie de répertoires avec ftp.prout.fr/ comme racine. L’option -nH désactive ce comportement. –cut-dirs=5 : Ignore 5 niveaux du répertoires distant pour la copie en local. Maintenant, reprenons notre exemple pour illustrer l’utilisation des options -nH –cut-dirs=n. la récupération de “ftp://ftp.prout.fr/../../arbo/des/fichiers/*” donnerait : Sans option : ftp.prout.fr/../../arbo/des/fichiers/ -nH : ../../arbo/des/fichiers/ -nH –cut-dirs=1 : ../arbo/des/fichiers/ -nH –cut-dirs=4 : fichiers/ Maintenant, examinons le comportement avec –cut-dirs sans -nH : –cut-dirs=4 : ftp.prout.fr/fichiers/ Et enfin, les informations de connexion –ftp-user</green> : le login ftp –ftp-password</green> : le mot de passe ftp Pour plus d’infos, consultez la manpage de wget ou allez jeter un oeil ici. [...] Avoir le backspace sur un clavier mac dans un term LinuxQuelques lignes simples pour obtenir le backspace dans un Term MacOs 🙂 Log in to the affected Linux box. echo $TERM to confirm the terminfo setting. (Mac OS X Terminal should be using xterm-color.) infocmp >xterm-color Edit xterm-color, find kbs and make sure it reads kbs=\177, and find kdch1 and make sure it reads kdch1=\E[3~. Save. mkdir -p ~/.terminfo/x Temporarily set the TERMINFO environment variable to /.terminfo Test-compile the new terminfo file: tic xterm-color If successful, ~/.terminfo/x/xterm-color will be the compiled terminfo file. unset TERMINFO If desired, back up the original compiled terminfo file. Look for it as /etc/terminfo/x/xterm-color or /usr/lib/terminfo/x/xterm-color. Run tic xterm-color again as root (using su or sudo) to compile and install the new version in the official location. [...]