[couverture de Linux Magazine 90]

Perles de Mongueurs (28)

Article publié dans Linux Magazine 90, janvier 2007.

[+ del.icio.us] [+ Developers Zone] [+ Bookmarks.fr] [Digg this] [+ My Yahoo!]

La perle de ce mois-ci a été rédigée par Philippe "BooK" Bruhat (book@mongueurs.net), de Lyon.pm et Paris.pm.

Un scanneur de ports à pas cher

J'utilise un serveur Linux pour quelques développements internes à mon travail. Il s'agit d'un PC de récupération, sans écran ni clavier, posé sous un bureau, auquel je me connecte par SSH depuis un portable Windows.

Il arrive trop souvent hélas que mes collègues l'éteignent le soir en partant. Ou alors ce sont les personnes chargées du ménage qui le débranchent pour brancher l'aspirateur ! ;-)

Le serveur obtenant son adresse IP par DHCP, celle-ci peut changer au démarrage et il est parfois un peu laborieux de chercher un clavier et un écran, juste pour regarder le résultat de la commande ifconfig. Heureusement, c'est la seule machine du sous-réseau qui fasse tourner le service SSH.

J'ai donc programmé un scanneur de ports minimal qui cherche les machines connectées au réseau, et tente de se connecter au service SSH.

    #!/usr/bin/perl
    use strict;
    use warnings;
    use Net::Ping;
    use IO::Socket::INET;

    $|++;
    my $base = shift || '192.168.9';

    # délai d'attente sur le ping : 0.1 seconde (réseau local !)
    my $p = Net::Ping->new( 'icmp', 0.1 );

    # boucle sur toute la plage d'adresse
    for my $h ( 1 .. 254 ) {
        print ".";

        # d'abord on essaye un ping
        my $host = "$base.$h";
        if ( $p->ping($host) ) {
            print "\r$host: alive\n";

            # si ça marche, on tente une connexion port 22
            my $s = IO::Socket::INET->new(
                PeerAddr => $host,
                PeerPort => 22,
                Timeout  => 0.1,     # en secondes
            );
            next if !( $s && $s->connected() );
            print "    " . <$s> . "\n";
            close $s;
        }
    }

$|++ permet de passer en mode sans temporisation (ou autoflush), afin d'afficher des points pour indiquer la progression du script.

Et voici le résulat :

    192.168.9.1: alive
    192.168.9.3: alive
    192.168.9.5: alive
    192.168.9.6: alive
    192.168.9.7: alive
    192.168.9.8: alive
    192.168.9.9: alive
        SSH-2.0-OpenSSH_4.3p2 Debian-5
    
    192.168.9.10: alive
    192.168.9.20: alive
    192.168.9.21: alive
    192.168.9.25: alive
    192.168.9.42: alive
    192.168.9.44: alive
    192.168.9.46: alive
    192.168.9.103: alive.......................................
    192.168.9.104: alive
    192.168.9.106: alive
    192.168.9.109: alive
    ............................

Notez que les valeurs de délai de garde (timeout) sont très faibles (0.1 seconde) car je m'intéresse seulement aux machines du réseau local.

Ce matin encore, après que ma connexion a échoué, j'ai rallumé le serveur et lancé le script sur mon portable pendant que la cafetière chauffait. Le scanneur a fait le tour du réseau en 40 secondes, mais j'ai eu ma réponse en 7 secondes. Même pas le temps de profiter de mon café ! (Avec un délai de garde d'une seconde, il faut environ 4 minutes 30 pour faire le tour du réseau.)

Il est évidemment très simple d'étendre ce scanneur pour rechercher d'autres ports, tout simplement en ajoutant une boucle de connexion sur les ports souhaités, juste après le ping :

    # si ça marche, on tente une connexion sur chaque port
    for my $port (@ports) {
        my $s = IO::Socket::INET->new(
            PeerAddr => $host,
            PeerPort => $port,
            Timeout  => 1,       # en secondes
        );
        next if !( $s && $s->connected() );
        print "    port $port\n";
        close $s;
    }

On obtiendra alors des résultats comme ci-après (ici @ports contient les valeurs 22, 23 et 80 :

    192.168.9.1: alive
        port 23
    192.168.9.3: alive
    192.168.9.5: alive
    192.168.9.6: alive
    192.168.9.7: alive
        port 80
    192.168.9.8: alive
    192.168.9.9: alive
        port 22
        port 80
    192.168.9.10: alive
    192.168.9.20: alive
    192.168.9.21: alive
        port 80
    192.168.9.25: alive
    192.168.9.42: alive
        port 23

L'avantage d'un tel script est qu'il ne nécessite aucun droit administratif sur la machine pour pouvoir être installé et qu'il est même suffisamment simple pour pouvoir être écrit de mémoire.

Ceci dit, si vous voulez vraiment vous livrer à un scan exhaustif du réseau, je vous conseille d'utiliser nmap. Et d'être discret, car il est fort probable que votre administrateur réseau n'appréciera pas votre curiosité. :-)

À vous !

Envoyez vos perles à perles@mongueurs.net, elles seront peut-être publiées dans un prochain numéro de Linux Magazine.

[IE7, par Dean Edwards] [Validation du HTML] [Validation du CSS]