15.6. Commandes de communications

Certaines des commandes suivantes trouvent leur utilité dans la chasse aux spammers, ainsi que dans les transferts réseaux et les analyses de données.

Informations et statistiques

host

Recherche de l'information à propos d'un hôte suivant son nom ou son adresse IP en utilisant DNS.

bash$ host surfacemail.com
surfacemail.com. has address 202.92.42.236
              
ipcalc

Affiche des informations IP sur un hôte. Avec l'option -h, ipcalc fait une recherche DNS inversée, trouvant le nom de l'hôte (serveur) à partir de l'adresse IP.

bash$ ipcalc -h 202.92.42.236
HOSTNAME=surfacemail.com
              
nslookup

Lance une « recherche sur un serveur de noms » par l'adresse IP d'un hôte. Ceci est l'équivalent de ipcalc -h ou dig -x. La commande peut être lancée interactivement ou pas, donc elle est utilisable dans un script.

La commande nslookup est « obsolète » mais elle a toujours son utilité.

bash$ nslookup -sil 66.97.104.180
nslookup kuhleersparnis.ch
 Server:         135.116.137.2
 Address:        135.116.137.2#53

 Non-authoritative answer:
 Name:   kuhleersparnis.ch
              
dig

Domain Information Groper. Similaire à nslookup, dig fait une « recherche Internet par un serveur de noms » sur un hôte. Peut être lancé interactivement ou non, donc il est utilisable à partir d'un script.

Voici quelques options intéressantes de dig : +time=N pour configurer un délai de N secondes pour obtenir la réponse, +nofail pour continuer à demander aux serveurs jusqu'à la réception d'une réponse et -x pour faire une recherche inverse.

Comparez la sortie de dig -x avec ipcalc -h et nslookup.

bash$ dig -x 81.9.6.2
;; Got answer:
 ;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 11649
 ;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0

 ;; QUESTION SECTION:
 ;2.6.9.81.in-addr.arpa.         IN      PTR

 ;; AUTHORITY SECTION:
 6.9.81.in-addr.arpa.    3600    IN      SOA     ns.eltel.net. noc.eltel.net.
 2002031705 900 600 86400 3600

 ;; Query time: 537 msec
 ;; SERVER: 135.116.137.2#53(135.116.137.2)
 ;; WHEN: Wed Jun 26 08:35:24 2002
 ;; MSG SIZE  rcvd: 91
              

Exemple 15.37. Trouver où dénoncer un spammeur

#!/bin/bash
# spam-lookup.sh : Recherche le contact pour rapporter un spammeur.
# Merci, Michael Zick.

# Vérification de l'argument en ligne de commande.
NBARGS=1
E_MAUVAISARGS=65
if [ $# -ne "$NBARGS" ]
then
  echo "Usage: `basename $0` nom_domaine"
  exit $E_MAUVAISARGS
fi


dig +short $1.contacts.abuse.net -c in -t txt
# Essayez aussi :
#     dig +nssearch $1
#     Essaie de trouver les serveurs de noms principaux
#     et affiche les enregistrements SOA.

# Ce qui suit fonctionne aussi :
#     whois -h whois.abuse.net $1
#           ^^ ^^^^^^^^^^^^^^^  Spécifiez l'hôte.
#     Peut même rechercher plusieurs spammeurs comme ceci, c'est-à-dire
#     whois -h whois.abuse.net $domainespam1 $domainespam2 . . .


#  Exercice :
#  ---------
#  Étendre la fonctionnalité de ce script
#+ pour qu'il envoie automatiquement une notification par courrier électronique
#+ au(x) adresse(s) de contact du responsable du FAI.
#  Astuce : utilisez la commande "mail".

exit $?

# spam-lookup.sh chinatietong.com
#                Un domaine connu pour le spam.

# "crnet_mgr@chinatietong.com"
# "crnet_tec@chinatietong.com"
# "postmaster@chinatietong.com"


#  Pour une version plus élaborée de ce script,
#+ voir la page de SpamViz, http://www.spamviz.net/index.html.

Exemple 15.38. Analyser le domaine d'un courrier indésirable

#! /bin/bash
# is-spammer.sh: Identifier les domaines des spams

# $Id: is-spammer.sh,v 1.6 2005/12/12 19:28:17 gleu Exp $
# L'information ci-dessus est l'ID RCS.
#
#  C'est une version simplifiée du script "is_spammer.bash"
#+ dans l'annexe des scripts contribués.

# is-spammer <nom.domaine>

# Utilise un programme externe : 'dig'
# Testé avec la version : 9.2.4rc5

# Utilise des fonctions.
# Utilise IFS pour analyser des chaînes par affectation dans des tableaux.
# Et fait même quelque chose d'utile : vérifie les listes noires d'emails.

# Utilise nom.domaine(s) à partir du corps du message :
# http://www.good_stuff.spammer.biz/just_ignore_everything_else
#
# Ou nom.domaine(s) à partir d'une adresse de courrier électronique :
# Really_Good_Offer@spammer.biz
#                   ^^^^^^^^^^^
# comme seul argument de ce script.
#(PS : votre connexion Internet doit être disponible)
#
# Donc, pour appeller ce script script dans les deux instances ci-dessus :
#       is-spammer.sh spammer.biz


# Espace blanc == :espace:tabulation:retour à la ligne:retour chariot:
WSP_IFS=$'\x20'$'\x09'$'\x0A'$'\x0D'

# Pas d'espace blanc == retour à la ligne:retour chariot
No_WSP=$'\x0A'$'\x0D'

# Séparateur de champ pour les adresses IP décimales
ADR_IFS=${No_WSP}'.'

# Obtient l'enregistrement de la ressource texte du DNS.
# recupere_txt <code_erreur> <requete>
recupere_txt() {

    # Analyse $1 par affectation sur les points.
    local -a dns
    IFS=$ADR_IFS
    dns=( $1 )
    IFS=$WSP_IFS
    if [ "${dns[0]}" == '127' ]
    then
        # Voir s'il existe une raison.
        echo $(dig +short $2 -t txt)
    fi
}

# Obtient l'enregistrement de la ressource adresse du DNS.
# verifie_adr <rev_dns> <serveur>
verifie_adr() {
    local reponse
    local serveur
    local raison

    serveur=${1}${2}
    reponse=$( dig +short ${serveur} )

    # Si reponse est un message d'erreur...
    if [ ${#reponse} -gt 6 ]
    then
        raison=$(recupere_txt ${reponse} ${serveur} )
        raison=${raison:-${reponse}}
    fi
    echo ${raison:-' ne fait pas partie de la liste noire.'}
}

# Doit obtenir l'adresse IP du nom.
echo 'Obtenir adresse de : '$1
adr_ip=$(dig +short $1)
reponse_dns=${adr_ip:-' aucune réponse '}
echo ' Adresse trouvée : '${reponse_dns}

# Une réponse valide contient au moins quatre nombres et trois points.
if [ ${#adr_ip} -gt 6 ]
then
    echo
    declare requete

    # Analyse par affectation au niveau des points.
    declare -a dns
    IFS=$ADR_IFS
    dns=( ${adr_ip} )
    IFS=$WSP_IFS

    # Réordonne les octets dans l'ordre de la requête DNS.
    rev_dns="${dns[3]}"'.'"${dns[2]}"'.'"${dns[1]}"'.'"${dns[0]}"'.'

# Voir : http://www.spamhaus.org (Conservatif, bien maintenu)
    echo -n 'spamhaus.org indique : '
    echo $(verifie_adr ${rev_dns} 'sbl-xbl.spamhaus.org')

# Voir : http://ordb.org (Relais ouverts)
    echo -n '   ordb.org  indique : '
    echo $(verifie_adr ${rev_dns} 'relays.ordb.org')

# Voir : http://www.spamcop.net/ (Vous pouvez rapporter les spammers ici)
    echo -n ' spamcop.net indique : '
    echo $(verifie_adr ${rev_dns} 'bl.spamcop.net')

# # # autres opérations de mise sur liste noire # # #

# Voir : http://cbl.abuseat.org.
    echo -n ' abuseat.org indique : '
    echo $(verifie_adr ${rev_dns} 'cbl.abuseat.org')

# Voir : http://dsbl.org/usage (Différents relais)
    echo
    echo 'Liste de serveurs de répertoires'
    echo -n '       list.dsbl.org indique : '
    echo $(verifie_adr ${rev_dns} 'list.dsbl.org')

    echo -n '   multihop.dsbl.org indique : '
    echo $(verifie_adr ${rev_dns} 'multihop.dsbl.org')

    echo -n 'unconfirmed.dsbl.org indique : '
    echo $(verifie_adr ${rev_dns} 'unconfirmed.dsbl.org')

else
    echo
    echo 'Impossible d\'utiliser cette adresse.'
fi

exit 0

# Exercices:
# --------

# 1) Vérifiez les arguments du script,
#    et quittez avec le message d'erreur approprié si nécessaire.

# 2) Vérifiez l'état de la connexion à l'appel du script,
#    et quittez avec le message d'erreur approprié si nécessaire.

# 3) Substituez des variables génériques pour les domaines BHL "codés en dur".

# 4) Initialiser le délai en utilisant l'option "+time=" pour la commande 'dig'.

Pour une version bien plus élaborée de ce script, voir l'Exemple A.29, « Identification d'un spammer ».

traceroute

Trace la route prise par les paquets envoyés à un hôte distant. Cette commande fonctionne à l'intérieur d'un LAN, WAN ou sur Internet. L'hôte distant peut être indiqué par son adresse IP. La sortie de cette commande peut être filtrée par grep ou sed via un tube.

bash$ traceroute 81.9.6.2
traceroute to 81.9.6.2 (81.9.6.2), 30 hops max, 38 byte packets
 1  tc43.xjbnnbrb.com (136.30.178.8)  191.303 ms  179.400 ms  179.767 ms
 2  or0.xjbnnbrb.com (136.30.178.1)  179.536 ms  179.534 ms  169.685 ms
 3  192.168.11.101 (192.168.11.101)  189.471 ms  189.556 ms *
 ...
              
ping

Envoie un paquet « ICMP ECHO_REQUEST » aux autres machines, soit sur un réseau local soit sur un réseau distant. C'est un outil de diagnostic pour tester des connections réseaux, et il devrait être utiliser avec précaution.

bash$ ping localhost
PING localhost.localdomain (127.0.0.1) from 127.0.0.1 : 56(84) bytes of data.
 64 bytes from localhost.localdomain (127.0.0.1): icmp_seq=0 ttl=255 time=709 usec
 64 bytes from localhost.localdomain (127.0.0.1): icmp_seq=1 ttl=255 time=286 usec

 --- localhost.localdomain ping statistics ---
 2 packets transmitted, 2 packets received, 0% packet loss
 round-trip min/avg/max/mdev = 0.286/0.497/0.709/0.212 ms
              

Un ping réussi renvoie un code de sortie de 0. Ceci peut être testé dans un script.

  HNAME=nastyspammer.com
# HNAME=$HOST     # Débogage : test pour localhost.
nombre=2  # Envoie seulement deux ping.

if [[ `ping -c $nombre "$HNAME"` ]]
then
  echo ""$HNAME" toujours présent et envoyant du SPAM chez vous."
else
  echo ""$HNAME" semble arrêté. Dommage."
fi
whois

Réalise une recherche DNS (Domain Name System, système de nom de domaine). L'option -h permet de spécifier sur quel serveur whois particulier envoyer la requête. Voir l'Exemple 4.6, « wh, recherche d'un nom de domaine avec whois » et l'Exemple 15.37, « Trouver où dénoncer un spammeur ».

finger

Retrouve de l'information sur les utilisateurs d'un réseau. Optionnellement, cette commande peut afficher les fichiers ~/.plan, ~/.project et ~/.forward d'un utilisateur si un des fichiers est présent.

bash$ finger
Login  Name           Tty      Idle  Login Time   Office     Office Phone
 bozo   Bozo Bozeman   tty1        8  Jun 25 16:59
 bozo   Bozo Bozeman   ttyp0          Jun 25 16:59
 bozo   Bozo Bozeman   ttyp1          Jun 25 17:07



bash$ finger bozo
Login: bozo                             Name: Bozo Bozeman
 Directory: /home/bozo                   Shell: /bin/bash
 Office: 2355 Clown St., 543-1234
 On since Fri Aug 31 20:13 (MST) on tty1    1 hour 38 minutes idle
 On since Fri Aug 31 20:13 (MST) on pts/0   12 seconds idle
 On since Fri Aug 31 20:13 (MST) on pts/1
 On since Fri Aug 31 20:31 (MST) on pts/2   1 hour 16 minutes idle
 No mail.
 No Plan.
              

En plus de raisons de sécurité, un grand nombre de réseaux désactive finger et son démon associé. [55]

chfn

Modifie l'information découverte par la commande finger.

vrfy

Vérifie une adresse Internet de courrier électronique.

Cette commande semble absente sur les dernières distributions Linux.

Accès à un hôte distant

sx, rx

L'ensemble de commandes sx et rx sert à transférer des fichiers de et vers un hôte distant en utilisant le protocole xmodem. Ils font généralement partie d'un paquetage de communications, tel que minicom.

sz, rz

L'ensemble de commandes sz et rz sert à transférer des fichiers de et vers un hôte distant en utilisant le protocole zmodem. Zmodem a certains avantages sur xmodem, tels qu'un meilleur taux de transmission et une reprise des transferts interrompus. Comme sx et rx, ils font généralement partie d'un paquetage de communications.

ftp

Utilitaire et protocole pour envoyer / recevoir des fichiers vers ou à partir d'un hôte distant. Une session ftp peut être automatisée avec un script (voir l'Exemple 18.6, « Télécharger un ensemble de fichiers dans le répertoire de récupération Sunsite », l'Exemple A.4, « encryptedpw : Charger un fichier sur un site ftp, en utilisant un mot de passe crypté en local » et l'Exemple A.13, « ftpget: Télécharger des fichiers via ftp  »).

uucp, uux, cu

uucp : Copie UNIX vers UNIX (UNIX to UNIX copy). C'est un paquetage de communication pour transférer des fichiers entre des serveurs UNIX. Un script shell est un moyen efficace de gérer une séquence de commandes uucp.

Depuis le développement d'Internet et du courrier électronique, uucp semble avoir disparu, mais il existe toujours et reste parfaitement utilisable dans des situations où des connexions Internet ne sont pas disponibles ou appropriées. L'avantage d'uucp est qu'il est tolérant aux pannes, donc même s'il y a une interruption de service, l'opération de copie continuera là où elle s'est arrêtée quand la connexion sera restaurée.

---

uux : exécution d'UNIX à UNIX. Exécute une commande sur un système distant. Cette commande fait partie du paquetage uucp.

---

cu : appelle (Call Up) un système distant et se connecte comme un simple terminal. C'est une version diminuée de telnet. Cette commande fait partie du paquetage uucp.

telnet

Utilitaire et protocole pour se connecter à un hôte distant.

[Attention]

Attention

Le protocole telnet contient des failles de sécurité et devrait donc être évité. Son utilisation dans un script shell n'est pas recommandée.

wget

L'utilitaire wget recupère de façon non-interactive ou télécharge des fichiers à partir d'un site Web ou d'un site ftp. Il fonctionne bien dans un script.

wget -p http://www.xyz23.com/file01.html
#  L'option -p ou --page-requisite fait que wget récupère tous les fichiers
#+ requis pour afficher la page spécifiée.

wget -r ftp://ftp.xyz24.net/~bozo/project_files/ -O $SAVEFILE
#  L'option -r suit récursivement et récupère tous les liens du site
#+ spécifié.

wget -c ftp://ftp.xyz25.net/bozofiles/filename.tar.bz2
#  L'option -c autorise wget à continuer un téléchargement interrompu.
#  Ceci fonctionne avec les serveurs FTP et beaucoup de sites HTTP.

Exemple 15.39. Obtenir la cote d'une valeur de bourse

#!/bin/bash
# quote-fetch.sh : Téléchargez une cote boursière.


E_SANSPARAMETRES=66

if [ -z "$1" ]  # Doit spécifier une cote boursière (symbole) à récupérer.
  then echo "Usage: `basename $0` symbole_stock"
  exit $E_SANSPARAMETRES
fi

symbole=$1

suffixe=.html
# Récupère un fichier HTML, donc nommez-le de façon approprié.
URL='http://finance.yahoo.com/q?s='
# Site finances Yahoo, avec le suffixe de la requête.

# -----------------------------------------------------------
wget -O ${symbole}${suffixe} "${URL}${symbole}"
# -----------------------------------------------------------


# Pour rechercher quelque chose sur http://search.yahoo.com :
# -----------------------------------------------------------
# URL="http://search.yahoo.com/search?fr=ush-news&p=${query}"
# wget -O "$fichier_sauvegarde" "${URL}"
# -----------------------------------------------------------
# Sauvegarde une liste d'URL en rapport.

exit $?

# Exercices :
# ----------
#
# 1) Ajoutez un test pour vous assurer que l'utilisateur ayant lancé le script
# est en ligne.
#    (Astuce : analysez la sortie de 'ps -ax' pour "ppp" ou "connect."
#
# 2) Modifiez ce script pour récupérer le rapport sur le temps local,
#+   en prenant le code postal de l'utilisateur comme argument.

Voir aussi l'Exemple A.31, « Rendre wget plus facile à utiliser » et l'Exemple A.32, « Un script de « podcasting » ».

lynx

Le navigateur web lynx peut être utilisé dans un script (avec l'option -dump) pour récupérer un fichier d'un site web ou ftp de façon non interactive.

lynx -dump http://www.xyz23.com/file01.html >$FICHIER

Avec l'option -traversal, lynx commence avec l'URL HTTP spécifiée comme argument, puis « navigue » jusqu'aux liens situés sur ce serveur particulier. Utilisée avec l'option -crawl, affiche le texte des pages dans un fichier de traces.

rlogin

Connexion distante, initie une session sur un hôte distant. Cette commande a des failles de sécurité, donc utilisez à la place ssh.

rsh

Shell distant, exécute des commande(s) sur un hôte distant. Il a aussi des failles de sécurité, donc utilisez à la place ssh.

rcp

Copie distante, copie des fichiers entre deux machines différentes.

rsync

Remote synchronize (NdT : synchronisation à distance), met à jour (synchronise) des fichiers entre deux machines différentes sur le réseau.

bash$ rsync -a ~/sourcedir/*txt /node1/subdirectory/
              

Exemple 15.40. Mettre à jour FC4

#!/bin/bash
# fc4upd.sh

# Auteur du script : Frank Wang.
# Légères modifications du style par l'auteur du guide ABS.
# Utilisé dans le guide ABS avec sa permission.


#  Télécharge les mises à jour de Fedora 4 à partir du site miroir en utilisant rsync.
# Devrait aussi fonctionner avec les dernières Fedora Cores -- 5, 6, ...
#  Télécharge seulement le dernier package si plusieurs versions existent
#+ pour sauvegarder de l'espace.

URL=rsync://distro.ibiblio.org/fedora-linux-core/updates/
# URL=rsync://ftp.kddilabs.jp/fedora/core/updates/
# URL=rsync://rsync.planetmirror.com/fedora-linux-core/updates/

DEST=${1:-/var/www/html/fedora/updates/}
LOG=/tmp/repo-update-$(/bin/date +%Y-%m-%d).txt
PID_FILE=/var/run/${0##*/}.pid

E_RETURN=65        # Quelque chose d'inattendu est survenu.


# Options générales de rsync
# -r: téléchargement récursif
# -t: conservation des heures
# -v: verbeux

OPTS="-rtv --delete-excluded --delete-after --partial"

# modèle d'inclusion de rsync
# Le premier slash ajoute une correspondance d'un chemin absolu.
INCLUDE=(
    "/4/i386/kde-i18n-Chinese*" 
#   ^                         ^
# Les guillemets sont nécessaires pour empêcher les remplacements.
) 


# modèle d'exclusion de rsync
# Désactive temporairement les packages non voulus en utilisant "#"...
EXCLUDE=(
    /1
    /2
    /3
    /testing
    /4/SRPMS
    /4/ppc
    /4/x86_64
    /4/i386/debug
   "/4/i386/kde-i18n-*"
   "/4/i386/openoffice.org-langpack-*"
   "/4/i386/*i586.rpm"
   "/4/i386/GFS-*"
   "/4/i386/cman-*"
   "/4/i386/dlm-*"
   "/4/i386/gnbd-*"
   "/4/i386/kernel-smp*"
#  "/4/i386/kernel-xen*" 
#  "/4/i386/xen-*" 
)


init () {
    # La commande pipe renvoit les erreurs possibles de rsync, par exemple un réseau saturé.
    set -o pipefail                     # Introduit dans Bash, version 3.

    TMP=${TMPDIR:-/tmp}/${0##*/}.$$     # Stocke la liste de téléchargement défini.
    trap "{
        rm -f $TMP 2>/dev/null
    }" EXIT                             # Efface le fichier temporaire en sortie.
}


check_pid () {
# Vérifie si le processus existe.
    if [ -s "$PID_FILE" ]; then
        echo "PID file exists. Checking ..."
        PID=$(/bin/egrep -o "^[[:digit:]]+" $PID_FILE)
        if /bin/ps --pid $PID &>/dev/null; then
            echo "Process $PID found. ${0##*/} seems to be running!"
           /usr/bin/logger -t ${0##*/} \
                 "Process $PID found. ${0##*/} seems to be running!"
            exit $E_RETURN
        fi
        echo "Process $PID not found. Start new process . . ."
    fi
}


#  Set overall file update range starting from root or $URL,
#+ according to above patterns.
set_range () {
    include=
    exclude=
    for p in "${INCLUDE[@]}"; do
        include="$include --include \"$p\""
    done

    for p in "${EXCLUDE[@]}"; do
        exclude="$exclude --exclude \"$p\""
    done
}


# Récupère et redéfinit la liste de mise à jour pour rsync.
get_list () {
    echo $$ > $PID_FILE || {
        echo "Can't write to pid file $PID_FILE"
        exit $E_RETURN
    }

    echo -n "Retrieving and refining update list . . ."

    # Récupère la liste -- 'eval' est nécessaire pour exécuter rsync en une seule commande.
    # $3 et $4 sont la date et l'heure de création du fichier.
    # $5 est le nom complet du package.
    previous=
    pre_file=
    pre_date=0
    eval /bin/nice /usr/bin/rsync \
        -r $include $exclude $URL | \
        egrep '^dr.x|^-r' | \
        awk '{print $3, $4, $5}' | \
        sort -k3 | \
        { while read line; do
            # Obtient le nombre de secondes depuis epoch pour filtrer les packages obsolètes.
            cur_date=$(date -d "$(echo $line | awk '{print $1, $2}')" +%s)
            #  echo $cur_date

            # Récupère le nom du fichier.
            cur_file=$(echo $line | awk '{print $3}')
            #  echo $cur_file

            # Récupère le nom du package RPM à partir du nom du fichier si possible.
            if [[ $cur_file == *rpm ]]; then
                pkg_name=$(echo $cur_file | sed -r -e \
                    's/(^([^_-]+[_-])+)[[:digit:]]+\..*[_-].*$/\1/')
            else
                pkg_name=
            fi
            # echo $pkg_name

            if [ -z "$pkg_name" ]; then   #  Si ce n'est pas un fichier RPM,
                echo $cur_file >> $TMP    #+ alors l'ajouter à la liste de téléchargements.
            elif [ "$pkg_name" != "$previous" ]; then   # Un nouveau package trouvé.
                echo $pre_file >> $TMP                  # Affichage du package précédent.
                previous=$pkg_name                      # Sauvegarde de l'actuel.
                pre_date=$cur_date
                pre_file=$cur_file
            elif [ "$cur_date" -gt "$pre_date" ]; then  #  Si même pakage en plus récent,
                pre_date=$cur_date                      #+ alors mise à jour du dernier pointeur.
                pre_file=$cur_file
            fi
            done
            echo $pre_file >> $TMP                      #  TMP contient TOUTE
                                                        #+ la liste redéfinie.
            # echo "subshell=$BASH_SUBSHELL"

    }       # Bracket required here to let final "echo $pre_file >> $TMP" 
            # Remained in the same subshell ( 1 ) with the entire loop.

    RET=$?  # Récupère le code de retour de la commande pipe.

    [ "$RET" -ne 0 ] && {
        echo "List retrieving failed with code $RET"
        exit $E_RETURN
    }

    echo "done"; echo
}

# La vraie partie du téléchargement par rsync.
get_file () {

    echo "Downloading..."
    /bin/nice /usr/bin/rsync \
        $OPTS \
        --filter "merge,+/ $TMP" \
        --exclude '*'  \
        $URL $DEST     \
        | /usr/bin/tee $LOG

    RET=$?

        #  --filter merge,+/ is crucial for the intention. 
        #  + modifier means include and / means absolute path.
        #  Then sorted list in $TMP will contain ascending dir name and 
        #+ prevent the following --exclude '*' from "shortcutting the circuit." 

    echo "Done"

    rm -f $PID_FILE 2>/dev/null

    return $RET
}

# --------------------
# Programme principal
init
check_pid
set_range
get_list
get_file
RET=$?
# --------------------

if [ "$RET" -eq 0 ]; then
    /usr/bin/logger -t ${0##*/} "Fedora update mirrored successfully."
else
    /usr/bin/logger -t ${0##*/} \
    "Fedora update mirrored with failure code: $RET"
fi

exit $RET

Voir aussi #!/bin/bash # nightly-backup.sh # http://www.richardneill.org/source.php#nightly-backup-rsync # Copyright (c) 2005 Richard Neill &lt;backup@richardneill.org&gt;. # Ce logiciel libre est sous licence GNU GPL. # ==> Inclus dans le guide ABS avec l'aimable autorisation de l'auteur du script. # ==> (Merci !) # Ceci réalise une sauvegarde de l'ordinateur hôte vers un disque dur firewire #+ connecté localement en utilisant rsync et ssh. # Il exécute ensuite une rotation des sauvegardes. # Exécutez-la via cron tous les jours à 5h du matin. # Cela ne sauvegarde que le répertoire principal. # Si le propriétaire (autre que l'utilisateur) doit être conservé, #+ alors exécutez le processus rsync en tant que root (et ajoutez le -o). # Nous sauvegardons tous les jours pendant sept jours, #+ puis chaque semaine pendant quatre semaines, #+ puis chaque mois pendant trois mois. # Voir http://www.mikerubel.org/computers/rsync_snapshots/ #+ pour plus d'informations sur la théorie. # À sauvegarder sous : $HOME/bin/nightly-backup_firewire-hdd.sh # Bogues connus : # --------------- # i) Idéalement, nous voulons exclure ~/.tmp et les caches du navigateur. # ii) Si l'utilisateur est devant son ordinateur à 5h du matin #+ et que les fichiers sont modifiés alors que le rsync est en cours, #+ alors la branche SAUVEGARDE_AUCASOU est appelée. # D'une certaine façon, c'est une fonctionnalité #+ mais cela cause aussi une "fuite d'espace disque". ##### DÉBUT DE LA SECTION DE CONFIGURATION ################################### UTILISATEUR_LOCAL=rjn # Utilisateur dont le répertoire principal sera #+ sauvegardé. POINT_MONTAGE=/backup # Point de montage du répertoire de sauvegarde. # Pas de slash à la fin ! # Il doit être unique #+ (par exemple en utilisant un lien symbolique udev) REP_SOURCE=/home/$UTILISATEUR_LOCAL # Pas de slash à la fin - important pour rsync. REP_DEST_SAUVE=$POINT_MONTAGE/backup/`hostname -s`.${UTILISATEUR_LOCAL}.nightly_backup ESSAI_A_BLANC=false # Si vrai, appelle rsync avec -n, réalisant un test. # Commentez ou configurez à faux pour une utilisation #+ normale. VERBEUX=false # Si vrai, rend rsync verbeux. # Commentez ou configurez à faux sinon. COMPRESSIONION=false # Si vrai, compresse. # Bon pour internet, mauvais sur LAN. # Commentez ou configurez à faux sinon. ### Codes d'erreur ### E_VAR_NON_CONF=64 E_LIGNECOMMANDE=65 E_ECHEC_MONTAGE=70 E_PASREPSOURCE=71 E_NONMONTE=72 E_SAUVE=73 ##### FIN DE LA SECTION DE CONFIGURATION ##################################### # Vérifie que toutes les variables importantes sont configurées : if [ -z "$UTILISATEUR_LOCAL" ] || [ -z "$REP_SOURCE" ] || [ -z "$POINT_MONTAGE" ] || [ -z "$REP_DEST_SAUVE" ] then echo "Une des variables n'est pas configurée ! Modifiez le fichier $0. ÉCHEC DE LA SAUVEGARDE." exit $E_VAR_NON_CONF fi if [ "$#" != 0 ] # Si des paramètres en ligne de commande... then # Document(ation) en ligne. cat <<-FINDUTEXTE Sauvegarde quotienne automatique exécutée par cron. Lisez les sources pour plus de détails : $0 Le répertoire de sauvegarde est $REP_DEST_SAUVE . Il sera créé si nécessaire ; une initialisation est inutile. ATTENTION : le contenu de $REP_DEST_SAUVE est l'objet de rotation. Les répertoires nommés 'backup.\$i' seront éventuellement supprimés. Nous conservons des répertoires pour chaque jour sur sept jours (1-8), puis pour chaque semaine sur quatre semaines (9-12), puis pour chaque mois sur trois mois (13-15). Vous pouvez ajouter ceci à votre crontab en utilisant 'crontab -e' # Fichiers sauvegardés : $REP_SOURCE dans $REP_DEST_SAUVE #+ chaque nuit à 3:15 du matin 15 03 * * * /home/$UTILISATEUR_LOCAL/bin/nightly-backup_firewire-hdd.sh N'oubliez pas de vérifier que les sauvegardes fonctionnent, surtout si vous ne lisez pas le mail de cron !" FINDUTEXTE exit $E_LIGNECOMMANDE fi # Analyse des options. # ==================== if [ "$ESSAI_A_BLANC" == "true" ]; then ESSAI_A_BLANC="-n" echo "ATTENTION" echo "CECI EST UN TEST SIMPLE !" echo "Aucune donnée ne sera réellement transférée !" else ESSAI_A_BLANC="" fi if [ "$VERBEUX" == "true" ]; then VERBEUX="-v" else VERBEUX="" fi if [ "$COMPRESSION" == "true" ]; then COMPRESSION="-z" else COMPRESSION="" fi # Chaque semaine (en fait tous les huit jours) et chaque mois, #+ des sauvegardes supplémentaires seront effectuées. JOUR_DU_MOIS=`date +%d` # Jour du mois (01..31). if [ $JOUR_DU_MOIS = 01 ]; then # Premier du mois. DEBUTMOIS=true elif [ $JOUR_DU_MOIS = 08 \ -o $JOUR_DU_MOIS = 16 \ -o $JOUR_DU_MOIS = 24 ]; then # Jour 8,16,24 # (on utilise 8 et non pas 7 pour mieux gérer les mois à 31 jours) DEBUTSEMAINE=true fi # Vérifie que le disque est monté. # En fait, vérifie que *quelque chose* est monté ici ! # Nous pouvons utiliser quelque chose d'unique sur le périphérique #+ plutôt que de simplement deviner l'ID SCSI en utilisant la bonne règle udev #+ dans /etc/udev/rules.d/10-rules.local #+ et en plaçant une entrée adéquate dans /etc/fstab. # Par exemple, cette règle udev : # BUS="scsi", KERNEL="sd*", SYSFS{vendor}="WDC WD16", # SYSFS{model}="00JB-00GVA0 ", NAME="%k", SYMLINK="lacie_1394d%n" if mount | grep $POINT_MONTAGE >/dev/null; then echo "Le point de montage $POINT_MONTAGE est déjà utilisé. OK" else echo -n "Tentative de montage de $POINT_MONTAGE..." # S'il n'est pas monté, essaie de le monter. sudo mount $POINT_MONTAGE 2>/dev/null if mount | grep $POINT_MONTAGE >/dev/null; then DEMONTE_APRES=TRUE echo "OK" # Note : s'assure qu'il sera aussi démonté #+ si nous quittons prématurément avec erreur. else echo "ÉCHEC" echo -e "Rien n'est monté sur $POINT_MONTAGE. ÉCHEC DE LA SAUVEGARDE!" exit $E_ECHEC_MONTAGE fi fi # Vérifie que le répertoire source existe et est lisible. if [ ! -r $REP_SOURCE ] ; then echo "$REP_SOURCE n'existe pas ou ne peut être lu. ÉCHEC DE LA SAUVEGARDE." exit $E_PASREPSOURCE fi # Vérifie que la structure du répertoire de sauvegarde est bonne. # Sinon, il la crée. # Crée les sous-répertoires. # Notez que backup.0 sera créé si nécessaire par rsync. for ((i=1;i<=15;i++)); do if [ ! -d $REP_DEST_SAUVE/backup.$i ]; then if /bin/mkdir -p $REP_DEST_SAUVE/backup.$i ; then # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Pas de tests entre crochets. Pourquoi ? echo "Attention : le répertoire $REP_DEST_SAUVE/backup.$i n'existe pas" echo "ou n'a pas été initialisé. (Re-)creation du répertoire." else echo "ERREUR : le répertoire $REP_DEST_SAUVE/backup.$i" echo "n'existe pas et n'a pas pu être créé." if [ "$DEMONTE_APRES" == "TRUE" ]; then # Avant de quitter, démonte le point de montage si nécessaire. cd sudo umount $POINT_MONTAGE && echo "Démontage de $POINT_MONTAGE. Abandon." fi exit $E_NONMONTE fi fi done # Configure les droits à 700 pour de la sécurité #+ sur un système multi-utilisateur. if ! /bin/chmod 700 $REP_DEST_SAUVE ; then echo "ERREUR : n'a pas pu configurer les droits du répertoire $REP_DEST_SAUVE à 700." if [ "$DEMONTE_APRES" == "TRUE" ]; then # Avant de quitter, démonte le point de montage si nécessaire. cd ; sudo umount $POINT_MONTAGE && echo "Démontage de $POINT_MONTAGE. Abandon." fi exit $E_NONMONTE fi # Création du lien symbolique : current -> backup.1 si nécessaire. # Un échec ici n'est pas critique. cd $REP_DEST_SAUVE if [ ! -h current ] ; then if ! /bin/ln -s backup.1 current ; then echo "Attention : n'a pas pu créer le lien symbolique current -> backup.1" fi fi # Maintenant, exécute le rsync. echo "Sauvegarde en cours avec rsync..." echo "Répertoire source : $REP_SOURCE" echo -e "Répertoire destination : $REP_DEST_SAUVE\n" /usr/bin/rsync $ESSAI_A_BLANC $VERBEUX -a -S --delete --modify-window=60 \ --link-dest=../backup.1 $REP_SOURCE $REP_DEST_SAUVE/backup.0/ # Avertit seulement, plutôt que de quitter, si rsync a échoué, #+ car cela pourrait n'être qu'un problème mineur. # Par exemple, si un fichier n'est pas lisible, rsync échouera. # Ceci ne doit pas empêcher la rotation. # Ne pas utiliser, par exemple, `date +%a` car ces répertoires #+ sont plein de liens et ne consomment pas *tant* d'espace. if [ $? != 0 ]; then SAUVEGARDE_AUCASOU=backup.`date +%F_%T`.justincase echo "ATTENTION : le processus rsync n'a pas complètement réussi." echo "Quelque chose s'est mal passé. Sauvegarde d'une copie supplémentaire dans : $SAUVEGARDE_AUCASOU" echo "ATTENTION : si cela arrive fréquemment, BEAUCOUP d'espace sera utilisé," echo "même si ce ne sont que des liens !" fi # Ajoute un fichier readme dans le répertoire principal de la sauvegarde. # En sauvegarde un autre dans le sous-répertoire recent. echo "La sauvegarde de $REP_SOURCE sur `hostname` a été exécuté le \ `date`" > $REP_DEST_SAUVE/README.txt echo "Cette sauvegarde de $REP_SOURCE sur `hostname` a été créé le \ `date`" > $REP_DEST_SAUVE/backup.0/README.txt # Si nous n'avons pas fait un test, exécute une rotation des sauvegardes. [ -z "$ESSAI_A_BLANC" ] && # Vérifie l'espace occupé du disque de sauvegarde. # Avertissement si 90%. # Si 98% voire plus, nous échouerons probablement, donc abandon. # (Note : df peut afficher plus d'une ligne.) # Nous le testons ici plutôt qu'avant pour donner une chance à rsync. DISK_FULL_PERCENT=`/bin/df $REP_DEST_SAUVE | tr "\n" ' ' | awk '{print $12}' | grep -oE [0-9]+ ` echo "Vérification de l'espace disque sur la partition de sauvegarde \ remplie à $POINT_MONTAGE $DISK_FULL_PERCENT%." if [ $DISK_FULL_PERCENT -gt 90 ]; then echo "Attention : le disque est rempli à plus de 90%." fi if [ $DISK_FULL_PERCENT -gt 98 ]; then echo "Erreur : le disque est rempli complètement ! Abandon." if [ "$DEMONTE_APRES" == "TRUE" ]; then # Avant de quitter, démonte le point de montage si nécessaire. cd; sudo umount $POINT_MONTAGE && echo "Démontage de $POINT_MONTAGE. Abandon." fi exit $E_NONMONTE fi # Crée une sauvegarde supplémentaire. # Si cette copie échoue, abandonne. if [ -n "$SAUVEGARDE_AUCASOU" ]; then if ! /bin/cp -al $REP_DEST_SAUVE/backup.0 $REP_DEST_SAUVE/$SAUVEGARDE_AUCASOU then echo "ERREUR : échec lors de la création de la copie de sauvegarde \ $REP_DEST_SAUVE/$SAUVEGARDE_AUCASOU" if [ "$DEMONTE_APRES" == "TRUE" ]; then # Avant de quitter, démonte le point de montage si nécessaire. cd ;sudo umount $POINT_MONTAGE && echo "Démontage de $POINT_MONTAGE. Abandon." fi exit $E_NONMONTE fi fi # Au début du mois, exécute une rotation des huit plus anciens. if [ "$DEBUTMOIS" == "true" ]; then echo -e "\nDébut du mois. \ Suppression de l'ancienne sauvegarde : $REP_DEST_SAUVE/backup.15" && /bin/rm -rf $REP_DEST_SAUVE/backup.15 && echo "Rotation mensuelle, sauvegardes hebdomadaires : \ $REP_DEST_SAUVE/backup.[8-14] -> $REP_DEST_SAUVE/backup.[9-15]" && /bin/mv $REP_DEST_SAUVE/backup.14 $REP_DEST_SAUVE/backup.15 && /bin/mv $REP_DEST_SAUVE/backup.13 $REP_DEST_SAUVE/backup.14 && /bin/mv $REP_DEST_SAUVE/backup.12 $REP_DEST_SAUVE/backup.13 && /bin/mv $REP_DEST_SAUVE/backup.11 $REP_DEST_SAUVE/backup.12 && /bin/mv $REP_DEST_SAUVE/backup.10 $REP_DEST_SAUVE/backup.11 && /bin/mv $REP_DEST_SAUVE/backup.9 $REP_DEST_SAUVE/backup.10 && /bin/mv $REP_DEST_SAUVE/backup.8 $REP_DEST_SAUVE/backup.9 # Au début de la semaine, exécute une rotation des quatre seconds plus anciens. elif [ "$DEBUTSEMAINE" == "true" ]; then echo -e "\nDébut de semaine. \ Suppression de l'ancienne sauvegarde hebdomadaire : $REP_DEST_SAUVE/backup.12" && /bin/rm -rf $REP_DEST_SAUVE/backup.12 && echo "Rotation des sauvegardes hebdomadaires : \ $REP_DEST_SAUVE/backup.[8-11] -> $REP_DEST_SAUVE/backup.[9-12]" && /bin/mv $REP_DEST_SAUVE/backup.11 $REP_DEST_SAUVE/backup.12 && /bin/mv $REP_DEST_SAUVE/backup.10 $REP_DEST_SAUVE/backup.11 && /bin/mv $REP_DEST_SAUVE/backup.9 $REP_DEST_SAUVE/backup.10 && /bin/mv $REP_DEST_SAUVE/backup.8 $REP_DEST_SAUVE/backup.9 else echo -e "\nSuppression de l'ancienne sauvegarde quotidienne : $REP_DEST_SAUVE/backup.8" && /bin/rm -rf $REP_DEST_SAUVE/backup.8 fi && # Chaque jour, rotation de huit plus anciens. echo "Rotation des sauvegardes quotidiennes : \ $REP_DEST_SAUVE/backup.[1-7] -> $REP_DEST_SAUVE/backup.[2-8]" && /bin/mv $REP_DEST_SAUVE/backup.7 $REP_DEST_SAUVE/backup.8 && /bin/mv $REP_DEST_SAUVE/backup.6 $REP_DEST_SAUVE/backup.7 && /bin/mv $REP_DEST_SAUVE/backup.5 $REP_DEST_SAUVE/backup.6 && /bin/mv $REP_DEST_SAUVE/backup.4 $REP_DEST_SAUVE/backup.5 && /bin/mv $REP_DEST_SAUVE/backup.3 $REP_DEST_SAUVE/backup.4 && /bin/mv $REP_DEST_SAUVE/backup.2 $REP_DEST_SAUVE/backup.3 && /bin/mv $REP_DEST_SAUVE/backup.1 $REP_DEST_SAUVE/backup.2 && /bin/mv $REP_DEST_SAUVE/backup.0 $REP_DEST_SAUVE/backup.1 && SUCCES=true if [ "$DEMONTE_APRES" == "TRUE" ]; then # Démonte le point de montage s'il n'était pas monté au début. cd ; sudo umount $POINT_MONTAGE && echo "$POINT_MONTAGE de nouveau démonté." fi if [ "$SUCCES" == "true" ]; then echo 'SUCCÈS !' exit 0 fi # Nous devrions avoir déjà quitté si la sauvegarde a fonctionné. echo 'ÉCHEC DE LA SAUVEGARDE ! Est-ce un test ? Le disque est-il plein ?) ' exit $E_SAUVE .

[Note]

Note

Utiliser rcp, rsync et d'autres outils similaires avec des implications de sécurité pourrait ne pas être judicieux. À la place, considérez l'utilisation de ssh, scp ou d'un script expect.

ssh

Shell sécurisé, pour se connecter sur un hôte distant et y exécuter des commandes. Cette alternative sécurisée pour telnet, rlogin, rcp et rsh utilise authentification et cryptage. Voir sa page man pour plus de détails.

Exemple 15.41. Utilisation de ssh

#!/bin/bash
# remote.bash: Utiliser ssh.

# Exemple de Michael Zick.
# Utilisé avec sa permission.


#   Présomptions:
#   ------------
#   fd-2 n'est pas capturé ( '2>/dev/null' ).
#   ssh/sshd présume que stderr ('2') sera affiché à l'utilisateur.
#
#   sshd est lancé sur votre machine.
#   Pour tout distribution 'standard', c'est probablement vrai,
#+  et sans qu'un ssh-keygen n'ait été effectué.

# Essayez ssh sur votre machine à partir de la ligne de commande :
#
# $ ssh $NOM_HOTE
# Sans configuration supplémentaire, un mot de passe vous sera demandé.
#   enter password
#   une fois fait,  $ exit
#
# Cela a-t'il fonctionné ? Si c'est la cas, vous êtes prêt pour plus d'action.

# Essayez ssh sur votre machine en tant que 'root' :
#
#   $  ssh -l root $NOM_HOTE
#   Lorsqu'un mot de passe vous est demandé, saisissez celui de root et surtout
#   pas le votre.
#          Last login: Tue Aug 10 20:25:49 2004 from localhost.localdomain
#   Saisissez 'exit' une fois terminé.

#  Les commandes ci-dessus vous donne un shell interactif.
#  Il est possible pour sshd d'être configuré dans le mode 'commande seule',
#+ mais cela dépasse le cadre de notre exemple.
#  La seule chose à noter est que ce qui suit fonctionnera dans le mode
#+ 'commande seule'.


# Une commande simple d'écriture sur stdout (local).

ls -l

# Maintenant la même commande basique sur une machine distante.
# Passez un nom d'utilisateur et d'hôte différents si vous le souhaitez :
USER=${NOM_UTILISATEUR:-$(whoami)}
HOST=${NOM_HOTE:-$(hostname)}

#  Maintenant, exécutez la commande ci-dessus sur l'hôte distant
#+ avec des communications cryptées.

ssh -l ${NOM_UTILISATEUR} ${NOM_HOTE} " ls -l "

#  Le résultat attendu est une liste du contenu du répertoire personnel de
#  l'utilisateur sur la machine distante.
#  Pour voir les différences, lancez ce script à partir d'un autre endroit que
#+ votre répertoire personnel.

#  En d'autres termes, la commande Bash est passée comme une ligne entre guillemets
#+ au shell distant, qui l'exécute sur la machine distante.
#  Dans ce cas, sshd fait  ' bash -c "ls -l" '   à votre place.

#  Pour des informations sur des thèmes comme ne pas avoir à saisir un mot de
#  passe pour chaque ligne de commande, voir
#+    man ssh
#+    man ssh-keygen
#+    man sshd_config.

exit 0

[Attention]

Attention

À l'intérieur d'une boucle, ssh pourrait avoir un comportement inattendu. D'après un message Usenet de l'archive comp.unix shell, ssh hérite de l'entrée standard (stdin) de la boucle. Pour remédier à ceci, passez à ssh l'option -n ou l'option -f.

Merci à Jason Bechtel pour cette indication.

scp

Secure copy, similaire en fonction à rcp, copie des fichiers entre deux machines différentes sur le réseau mais le fait en utilisant une authentification et avec un niveau de sécurité similaire à ssh.

Réseaux locaux

write

Utilitaire pour la communication terminal à terminal. Il permet d'envoyer des lignes à partir de votre terminal (console ou xterm) à un autre utilisateur. La commande mesg pourrait, bien sûr, être utilisée pour désactiver l'accès en écriture au terminal.

Comme write est interactif, il a peu de chances de prouver son utilité dans un script.

netconfig

Un outil en ligne de commande pour configurer un adaptateur réseau (en utilisant DHCP). Cette commande est native pour les distributions Linux basées sur la Red Hat.

Mail

mail

Envoie ou lit des courriers électroniques.

Ce client mail en ligne de commande est très simpliste et fonctionne bien comme commande embarquée dans un script.

Exemple 15.42. Un script qui envoie son fichier source

#!/bin/sh
# self-mailer.sh: Script vous envoyant un mail.

adr=${1:-`whoami`}     # Par défaut, l'utilisateur courant, si non spécifié.
#  Tapez 'self-mailer.sh wiseguy@superdupergenius.com'
#+ envoie ce script à cette adresse.
#  Tapez juste 'self-mailer.sh' (sans argument) envoie le script à la personne
#+ l'ayant appelé, par exemple bozo@localhost.localdomain.
#
#  Pour plus d'informations sur la construction ${parameter:-default},
#+ voir la section "Substitution de paramètres" du chapitre "Variables
#+ Revisitées."

# ============================================================================
  cat $0 | mail -s "Le script \"`basename $0`\" s'est envoyé lui-même à vous." "$adr"
# ============================================================================

# --------------------------------------------
#  Bonjour du script qui s'envoie par mail.
#  Une personne mal intentionnée a lancé ce script, ce qui a fait que ce mail
#+ vous a été envoyé.
#  Apparemment, certaines personnes n'ont rien de mieux à faire de leur temps.
# --------------------------------------------

echo "Le `date`, le script \"`basename $0`\" vous a été envoyé par mail sur "$adr"."

exit 0

mailto

Similaire à la commande mail, mailto envoie des mails à partir de la ligne de commande ou dans un script. Néanmoins, mailto permet aussi d'envoyer des messages MIME (multimedia).

vacation

Cet utilitaire répond automatiquement aux courriers électroniques que le destinataire est en vacances et temporairement indisponible. Ceci tourne sur le réseau, en conjonction avec sendmail, et n'est pas applicable à un compte POP.



[55] Un démon est un processus en tâche de fond non attaché à une session terminal. Les démons réalisent des services désignés soit à des moments précis soit en étant enclenchés par certains événements.

Le mot « démon » signifie fantôme en grec, et il y a certainement quelque chose de mystérieux, pratiquement surnaturel, sur la façon dont les démons UNIX travaillent silencieusement derrière la scène, réalisant leurs différentes tâches.