LinkFluence, votre crawler est bugué

Je surveille mes logs Nginx avec ferveur et j'ai un tail -f /var/log/nginx/access_log en permanence dans un de mes screens.

J'ai soudainement remarqué qu'une IP fait de nombreuses requêtes sur l'URL servant à poster un commentaire, tout en se faisant jeter. En effet, le bot essayait de poster des commentaires sur de très nombreux articles de mon blog, mais sans renseigner d'auteur, ni de texte, ni les quelques champs invisibles servant de protection contre la plupart des spambots. Et en se gourant dans la méthode HTTP (GET au lieu de POST) à utiliser.

Je vous présente donc le bot de LinkFluence, dont l'user-agent est Mozilla/5.0 (compatible; Crawler/0.9; http://linkfluence.net/), et qui est yet another analyseur de contenus sociaux parmi les trouzmille qui s'amusent parfois à crawler mon site et que je laisse généralement faire (enfin... en général).

Je me suis d'ailleurs toujours demandé pourquoi, par « réseaux sociaux », les gens incluent généralement les blogs. Surtout que le mien, en étant exempt de bouton "J'aime", "Repioupiouter" ou d'autres délires socioréticulaires, ne fait pas vraiment dans le social.

Bref, les logs (que j'abrège par concision) sont ici :

37.59.42.102 - - [06/May/2013:10:33:16 +0200] "GET /blog/16 HTTP/1.1" 200 
37.59.42.102 - - [06/May/2013:10:33:16 +0200] "GET /blog/15 HTTP/1.1" 200
37.59.42.102 - - [06/May/2013:10:33:16 +0200] "GET /blog/18 HTTP/1.1" 200
37.59.42.102 - - [06/May/2013:10:33:17 +0200] "GET /blog/21 HTTP/1.1" 200
37.59.42.102 - - [06/May/2013:10:33:17 +0200] "GET /blog HTTP/1.1" 200
37.59.42.102 - - [06/May/2013:10:33:21 +0200] "GET /blog/23 HTTP/1.1" 200
37.59.42.102 - - [06/May/2013:10:33:21 +0200] "GET /blog/14 HTTP/1.1" 200
37.59.42.102 - - [06/May/2013:10:33:22 +0200] "GET /blog/17 HTTP/1.1" 200
37.59.42.102 - - [06/May/2013:10:33:22 +0200] "GET /blog/22 HTTP/1.1" 200
37.59.42.102 - - [06/May/2013:10:33:27 +0200] "GET /blog/20 HTTP/1.1" 200
37.59.42.102 - - [06/May/2013:10:33:27 +0200] "GET /blog/19 HTTP/1.1" 200

Puis quelques secondes plus tard, surprise, des requêtes GET sur une ressource sur laquelle on n'est censé que faire des POST :

37.59.42.102 - - [06/May/2013:10:33:31 +0200] "GET /blog/16/post_comment HTTP/1.1" 403
37.59.42.102 - - [06/May/2013:10:33:31 +0200] "GET /blog/15/post_comment HTTP/1.1" 403
37.59.42.102 - - [06/May/2013:10:33:31 +0200] "GET /blog/18/post_comment HTTP/1.1" 403
37.59.42.102 - - [06/May/2013:10:33:36 +0200] "GET /blog/21/post_comment HTTP/1.1" 403
37.59.42.102 - - [06/May/2013:10:34:05 +0200] "GET /blog/23/post_comment HTTP/1.1" 403
37.59.42.102 - - [06/May/2013:10:34:08 +0200] "GET /blog/17/post_comment HTTP/1.1" 403
37.59.42.102 - - [06/May/2013:10:34:08 +0200] "GET /blog/22/post_comment HTTP/1.1" 403
37.59.42.102 - - [06/May/2013:10:34:35 +0200] "GET /blog/20/post_comment HTTP/1.1" 403
37.59.42.102 - - [06/May/2013:10:34:35 +0200] "GET /blog/19/post_comment HTTP/1.1" 403
37.59.42.102 - - [06/May/2013:10:35:14 +0200] "GET /blog/12/post_comment HTTP/1.1" 403

Alors, suivre les liens <a>, c'est bien ; éviter de le faire avec les URLs d'action pour des formulaires, c'est mieux, et, ça aurait pu éviter à ce pauvre bot de se manger un ban permanent.

Et décidément, ils n'en sont pas à leur premier fail.

Posté par x0r à 0 commentaire • Tags : bot web linkfluence crawler fail coupdegueule

Un écran Infogare sur son PC (ou comment exploiter l'Open Data SNCF)

EDIT : Je n'utilise plus cette méthode pour récupérer les horaires en live pour monrer.fr, mais une autre API une API officielle fournie par la SNCF.

Depuis quelques temps, la SNCF publie certaines données sur ses trains et ses services dans une politique d'Open Data.

Certains d'entre vous ont peut-être déjà vu mon dernier mini-site qui utilise ces données pour afficher une information de ponctualité pour la grande majorité des trains. Ainsi, un train prévu pour 11 h 07 et dont l'heure de passage est de 11 h 09 est affiché avec la mention « +2 min » :

Ces trains passeront avec deux minutes de retard.

Les horaires de passage réels des trains sont récupérables par plusieurs moyens, mais les comparer avec l'horaire théorique stocké dans les exports GTFS de la SNCF nécessite de faire un certain nombre de traitements sur ces données pour les confronter correctement.

Tout d'abord, quelques définitions

Pour ne pas vous perdre tout de suite, quelques définitions s'imposent. Au risque de réutiliser des termes du jargon ferroviaire en m'éloignant de leur sens d'origine, les voici :

Sur une ligne de RER, on assure des missions : ces missions sont tout simplement des listes de gares desservies dans un certain ordre. Certaines missions sont omnibus (i.e. s'arrêtent à toutes les gares d'une ligne), d'autres sont semi-directes et sautent parfois certaines gares. À chaque mission, on donne un code à quatre lettres, appelé code mission, unique à chaque mission, et qui permet aux régulateurs de connaître exactement la desserte d'un train donné, afin de l'aiguiller correctement. On montre également ces codes mission aux voyageurs.

Toutes les missions sont assurées à intervalles réguliers par des trains qui ont pour ordre de s'arrêter à chaque gare de leur mission en respectant un horaire théorique. Les aléas de la circulation amène souvent ces trains à accuser un retard, et on indique alors sur les écrans d'information des gares Transilien une estimation de l'horaire réel de passage d'un train dans une gare donnée.

Chaque train est repéré, en zone SNCF (lignes RER C, D, E et Transilien) par leurs numéros de train (par exemple, 123477), et en zone RATP (lignes RER A et B) par leur code mission à quatre lettres suivi de deux chiffres (par exemple, ZEUS67).

L'ensemble des trains circulant un jour donné constitue un service journalier. Souvent, on assure des services journaliers différents en semaine et en week-end ; les horaires théoriques du week-end pouvant être moins contraignants qu'en semaine, où l'on fait rouler un nombre plus conséquent de trains.

Enfin, afin de rester cohérent avec les termes utilisés dans l'export GTFS, j'appelle un itinéraire un train qui, un jour donné, assure une mission donnée. Le train 123477 un jour de semaine n'est pas forcément le même que le 123477 un samedi ou dimanche ; cependant, ces deux itinéraires sont repérés par des identifiants différents, par exemple DUASN123477R010392834 et DUASN123477R040392235.

Les sources de données de mon mini-site

J'utilise deux sources de données pour afficher les informations visibles sur le mini-site.

La première source donne tous les horaires théoriques de tous les trains que la SNCF fait rouler sur son réseau Transilien. Les gares sont repérées par leur code UIC ; la correspondance entre code UIC et nom de gare est fournie dans les données exportées. Ces données sont disponibles sur la page Transilien du site OpenData SNCF sous forme d'une archive zip qui, une fois extraite, donne ces informations dans ce fameux format GTFS dont je parle depuis le début de ce post.

La seconde source, en revanche, me donne les horaires réels des prochains trains d'une gare repérée à l'aide d'un trigramme appelé « TR3 » (exemple : SKX pour Sceaux, PAA pour Paris Gare de Lyon (RER D), COE pour Corbeil-Essonnes...). La liste officielle de ces trigrammes et la correspondance avec le nom de la gare est a priori un document interne à la SNCF, mais comme pour les codes UIC, on trouve assez facilement des listes (incomplètes) compilées sur Internet. J'ai dû passer pas mal de temps pour compléter cette liste, donc je vous propose d'aller regarder le code source et d'ouvrir le script db.sql.

Cette source n'est a priori pas publiée sous licence Open Data, mais l'URL a l'air de se balader un peu partout dans des forums. L'URL est de la forme :

http://sncf.mobi/infotrafic/iphoneapp/transilien/?gare=[trigramme gare]

et les données obtenues sont en JSON, exploitable quasi-directement dans un script, pourvu que l'on ait quelque part une base de données de gares indexées selon leur code TR3.

Utiliser les deux sources ensemble

Les problèmes principaux que j'ai eus en voulant utiliser les deux sources ensemble étaient les suivants :

  • L'export GTFS mentionne des identifiants d'itinéraire du style DUASN123477R010392834, alors que les horaires en temps réel ne donnaient que le numéro du train, du style 123477. On peut dériver le numéro du train en fonction de l'identifiant d'itinéraire, mais dans l'autre sens, comme dans mon cas, un train peut correspondre à plusieurs itinéraires ; on est donc obligé d'utiliser une clause WHERE un peu compliquée pour éliminer les itinéraires qui ne correspondent pas au jour actuel, entre autres.

  • Dans certains cas, les numéros de trains dérivés des identifiants d'itinéraire n'existent pas. En particulier avec certaines mission ROPO du RER D, ou certaines mission du RER C, où il faut aller chercher le numéro de train « à côté » pour avoir les données que l'on cherche.

  • Les horaires fournis dans l'export GTFS dépassent parfois 24 h. Un train qui part de sa gare d'origine à 23 h 50 et qui arrive à son terminus à 1 h 50 est noté comme arrivant à 25 h 50 dans les données GTFS. En revanche, le train assurant la même mission et qui part une demi-heure plus tard (à 0 h 20, donc) est noté comme arrivant à 2 h 20 au lieu de 26 h 20. Je comprends le raisonnement derrière, mais ça reste fastidieux à gérer.

  • L'export GTFS utilise les codes UIC des gares desservies par chaque train, alors que les données « temps réel » n'utilisent que les codes TR3. Heureusement, faire une table qui indexe les gares à la fois par leur code UIC et leur code TR3 n'est pas non plus la chose la plus compliquée du monde.

Conclusion

En soi, la seule chose que je regrette avec les données GTFS de la SNCF, c'est qu'il manque les numéros de trains, et que je suis obligé de les dériver d'un identifiant à l'aide d'un hack que je considère comme infâme. À part ça, cela me fait extrêmement plaisir que la SNCF ait décidé de faire un pas vers la libération de ses données, et même si la RATP a également emboîté le pas, ils ne publient pas les mêmes informations.

Néanmoins, j'espère avoir réussi à démystifier un peu cette application Web. Je tire néanmoins une grande fierté de pouvoir afficher sur ce mini-site des informations que même les écrans Infogare n'affichent pas ; on constate parfois à quel point certains trains accusent du retard en heure de pointe, même si ce n'est plus aussi visible qu'avant.

En confrontant ainsi données théoriques et informations de circulation en temps réel, ce serait là l'occasion pour des chercheurs ou des groupes de travail divers et variés de collecter des données de régularité et ainsi, peut-être, en tirer des conclusions qu'il serait impossible de tirer autrement ?

Et en bonus

Un petit truc marrant qu'on peut s'amuser à faire avec ces données GTFS : tracer le nombre de trains en service en fonction de l'heure de la journée sur chacune des lignes RER/Transilien SNCF (cliquez pour voir en grand et en meilleure qualité) :

Trains en fonction de l'heure

Suite : monrer.fr : autocomplétion et reverse-engineering

Posté par x0r à 16 commentaires • Tags : transilien sncf gtfs opendata trains rer

Le jeu de caractères des afficheurs VFD Matrix Orbital

Sur une de mes machines servant de HTPC, j'utilise un afficheur fluorescent (ou VFD) Matrix Orbital VK202-25-USB.

C'est un magnifique petit afficheur, bien pratique pour lire de la musique pendant que seule la machine est allumée et que la télé est éteinte. Le seul problème, c'est que la documentation comporte des erreurs et que le jeu de caractères qui y est présenté est erronné et incomplet.

Quelques lignes de Perl et d'Imagemagick plus tard, je vous concocte donc une image résumant le jeu de caractères de l'afficheur pour les points de code allant de 128 à 253 inclus.

Jeu de caractères du VK202-25-USB

Notez que la place faite aux katakana et autres caractères japonais font que les lettres accentuées comme "é", "è", etc. ne peuvent pas être représentées. C'est bien dommage, car ces caractères figureraient dans le charset des afficheurs LCD qu'ils vendent (et non les VFD, la seule option réellement intéresante pour mon application). Dommage, car pour le reste, ils sont plutôt agréables à programmer.

Posté par x0r à 0 commentaire • Tags : vfd matrix orbital charset

Reprendre le contrôle de son adressage avec DHCPv6 et Dibbler

Dans un article précédent, nous avons vu comment faire fonctionner son réseau avec l'IPv6 de Free en étant derrière son propre routeur OpenWRT. Je m'étais alors limité à l'autoconfiguration automatique (dit SLAAC, pour Stateless Address Autoconfiguration), pour des raisons de simplicité.

Cependant, la partie "stateless" fait que le routeur se contente de donner le préfixe /64 et éventuellement d'autres informations. Le client choisit alors lui-même les 64 derniers bits de l'adresse qu'il décide d'utiliser, moyennant quelques précautions pour éviter d'utiliser une adresse utilisée par quelqu'un d'autre (DAD, ou Duplicate Address Detection). Une adresse peut alors être générée à partir de l'adresse MAC, comme c'est souvent le cas sous Linux, mais elle peut aussi être choisie de manière complètement aléatoire, et renouvelée toutes les dix minutes, comme sous Windows et Mac OS. On parle d'utilisation d'adresses temporaires pour le second cas.

J'utilise Privoxy sur mon réseau. Il s'agit d'un proxy qui permet entre autres de filtrer les pubs et autres petits trucs indésirables (comme par exemple ces fameux boutons « J'aime » de Facebook, qui ont le malin plaisir d'utiliser un cookie pour tracer des utilisateurs, y compris ceux qui n'ont pas de compte chez eux – mais cela n'est pas l'objet principal de cet article). Il s'avère que de temps en temps, Chrome sous Windows ne parvient pas à se connecter au proxy (erreur net::ERR_PROXY_CONNECTION_FAILED pour ceux qui veulent des détails), alors que le reste du réseau fonctionne. Aucun paquet TCP, ni même un seul paquet SYN, ne parvient au serveur lorsque cela arrive.

J'ai donc conjecturé que c'était la faute de l'utilisation des adresses temporaires. J'ai donc eu l'idée d'expérimenter avec Dibbler, un petit serveur DHCPv6 portable, qui est entre autres packagé sous OpenWRT. Mon expérience est à la fois justifiée par ma conjecture et par le désir d'attribuer des reverse DNS pour les machines sur lesquelles je ne peux pas me permettre d'attribuer des IPv6 statiques à la main.

Dans ce post, je vais donc expliquer en détail ce que j'ai fait pour mettre en place un serveur DHCPv6 sur mon routeur, tout en explicitant les différences avec l'« ancien » DHCP d'IPv4. Je reviendrai d'abord sur le fonctionnement de radvd, avant de traiter de l'installation de Dibbler, de sa configuration et du test du service, pour ensuite conclure sur mes observations quant aux implémentations de dhcpcd et de Windows.

Retour sur radvd

Au moment où nous avions mis en place la connectivité IPv6 pour notre réseau, nous avions installés radvd, qui sert à répondre aux Router Solicitations (RS) d'ICMPv6 avec des Router Announcement (RA). Ces paquets contiennent deux types de flags.

Premièrement, les flags du paquet sont les suivants :

  • M (Managed) : si ce flag est à 1, utiliser DHCPv6 pour récupérer son adresse IP. Sinon, se contenter de SLAAC ;
  • O (Other) : si ce flag est à 1, utiliser DHCPv6 pour récupérer d'autres informations que l'adresse (par exemple les serveurs DNS).

Nous avions mis ces deux flags à 0 lorsque nous avions configuré radvd, signifiant que seuls des paquets RS et RA sont nécessaires pour l'autoconfiguration des clients. En passant à DHCPv6, nous mettrons le flag M à 1, et si nous souhaitons également fournir aux clients les adresses des serveurs DNS, nous ferons de même avec le flag O.

Ensuite, pour chaque préfixe signalé dans un RA, il y a également plusieurs flags, mais nous nous focaliserons surtout sur le suivant :

  • A (Autonomous) : si ce flag est à 1, le client utilise SLAAC pour obtenir une adresse dans le préfixe correspondant.

Ce flag était à 1 dans notre configuration initiale. Comme nous utilisons DHCPv6, nous pouvons la passer à 0 pour s'assurer, entre autres, que les clients n'utilisent pas d'adresses temporaires.

Installation de Dibbler

L'installation de Dibbler est très simple. En tant que root sur le routeur :

# opkg install dibbler-server

Configuration de Dibbler

La configuration de Dibbler se fait dans /etc/dibbler/server.conf. Voici un petit exemple de configuration attribuant des IP aléatoires dans son /64, tout en attribuant certaines IP fixes pour certaines machines.

# Logging level range: 1(Emergency)-8(Debug)
log-level 7

# Don't log full date
log-mode short

# set preference of this server to 0 (higher = more prefered)
preference 0

iface "br-lan" {
 // also ranges can be defines, instead of exact values
 t1 1800-2000
 t2 2700-3000
 prefered-lifetime 3600
 valid-lifetime 7200

# assign addresses from this pool

 class {
   pool 2001:db8:0:42/64
 }

 option domain example.com
 option dns-server 2001:db8:0:42::b
 option ntp-server 2001:db8:0:42::17
 option time-zone  CET

 client duid 00:01:00:01:18:92:e4:e9:aa:bb:cc:dd:ee:ff
 {
   address 2001:db8:0:42::cafe
 }

 client duid 00:01:00:01:18:5a:14:81:01:23:45:67:89:ab
 {
   address 2001:db8:0:42::c0ca
 }
}

La plupart des directives sont plutôt évidentes. Il y a cependant deux choses auxquelles il faut faire attention :

  • Dibbler 0.8.2 semble avoir un bug qui oblige les adresses statiques à être obligatoirement dans un préfixe déclaré avec la directive class. Cela signifie qu'il est pour le moment impossible de donner des IP dans deux plages disjointes selon qu'il s'agisse d'une machine connue ou inconnue.

  • On n'attribue plus d'adresses en fonction d'adresses MAC, mais en fonction d'identifiants uniques appelés DUID (plus de détails dans la RFC 3315, section 9 – lecture très recommandée). Ces DUID sont généralement générés une fois à l'installation du système (ou à la première utilisation de DHCPv6...).
    L'inconvénient majeur est le fait que ces DUID sont imprévisibles ; il faut donc regarder dans /var/lib/dibbler/server-cache.xml pour retrouver celui qui correspond à la bonne adresse.

Mis à part l'utilisation de DUID, il n'y a pas grand-chose de sensiblement différent comparé au DHCP traditionnel.

Tester le service

Sous Linux, on peut tester le bon fonctionnement avec le client fourni avec Dibbler. Il suffit de lancer dibbler-client run en tant que root, puis de faire un petit ifconfig pour voir si on obtient une adresse IP par DHCPv6.

Windows 7 implémente déjà un client DHCPv6, donc il suffit de rebooter la carte ou la machine. En faisant un petit ipconfig dans une invite de commandes, on voit que ça marche tout seul.

Conclusion

Bien que l'utilisation de DHCPv6 n'ait pas résolu le problème avec le proxy sous Chrome mentionné en introduction (ou alors ce sont des gremlins qui s'amusent avec la carte réseau), cela m'a ensuite permis de mettre en place assez facilement les enregistrements reverse DNS pour ma plage d'adresses IPv6. Pas forcément nécessaire, mais toujours appréciable.

Pour le moment, dhcpcd, le client DHCP utilisé par wicd entre autres, ne prend pas encore en charge DHCPv6, donc pour ceux qui utilisent ce démon, vous n'avez pas de chance ; vous n'aurez que du SLAAC. Ou sinon, il faudra compiler et installer la version 5.99.

Du côté des serveurs, dnsmasq implémenterait également un serveur DHCPv6, mais cela contraint de supprimer radvd, ce que je ne souhaitais pas. In fine, la solution que j'ai retenue est celle qui fournit le plus de flexibilité, et permet théoriquement de s'affranchir de cette problématique récurrente d'administration réseau qu'est l'adressage.

Posté par x0r à 0 commentaire • Tags : sysadmin ipv6 dibbler dhcpv6 dhcp reseau

minicurses 0.4

Après quelques mois de développement, de tests et de stagnation par manque de temps, j'ai décidé de faire une release de la version 0.4 de minicurses, rendant obsolète la version 0.3.2.

Cette mise à jour mineure apporte la gestion de fenêtres à minicurses. J'ai également eu l'occasion d'écrire un programme d'exemple tout pourri et bugué, que je n'ose pas encore publier, pour tester les diverses fonctionnalités que j'ai ajoutées à minicurses.

Téléchargements

ou, toujours, pour ceux qui souhaitent récupérer la toute dernière version de développement :

% hg clone https://bitbucket.org/xtab/minicurses

Comme d'habitude, je vous invite à consulter les pages de man sur le wiki.

Oui, un jour, je ferai peut-être de la doc un peu plus poussée.

Changelog

  • Ajout de la prise en charge de fenêtres : newwin(3), delwin(3), ainsi que les fonctions wfoobar() et mvwfoobar() (si pertinent) des familles addstr(3), addch(3), clear(3), attron(3), attroff(3), attrset(3), addimg(3), refresh(3) et autres.

Roadmap

Pour la version 0.5, voici les modifications les plus importantes que je prévois :

  • Gérer les frappes au clavier ;
  • Aligner la gestion des paires de couleurs à celle de ncurses pour améliorer la compatibilité source de minicurses.

Posté par x0r à 0 commentaire • Tags : programmation c minicurses minitel