mercredi 22 août 2012

[1/3] Python bot irc - Kit de première Analyse d'un fichier

Bonjour,

Voici la première partie de mon tutoriel sur la réalisation de mon bot irc d'analyse d’exécutable.

Beaucoup d'entre vous, vont se dire que c'est totalement inutile, pourquoi faire cela par irc, pourquoi pas juste un petit script python personnel.
Effectivement, le passage par le protocole irc aurait pu être très largement évité, mais étant donné que j'ai besoin de me familiariser avec, je me suis dit pourquoi pas faire un bot. (ce qui permettrait à tout le monde de pouvoir utiliser le bot, et ce depuis n'importe où).

Donc dans ce premier tutoriel, on va voir comment établir la connexion à un serveur irc, et faire en sorte que le bot réponde à toute la petite routine de ce protocole.

Résumé pour faire court:


  • Langage: Python
  1. Établir une connexion: en utilisant socket
  2. Traiter les réponses
  3. Rejoindre un channel
C'est parti:

Avant tout, je tiens à rappeler que j'utilise les sockets et donc qu'on va faire nos connexions à la main, il existe des libs qui traite déjà "très" bien les connexions au protocole irc (ex: irclib , tuto sdz ircbot, twisted) mais pour apprendre un protocole j'avais besoin de le voir de par moi même.

On pense à ajouter la lib socket:


import socket


Nous créons nos variables importantes:


bHost = 'irc.rizon.net'
bPort = 6667
bPseudo = 'PseudoDuBot'
bChannel = '#lechannel'


On créait une nouvelle connexion:


irc = socket.socket(socket.AF_INET,socket.SOCK_STREAM)


On resolve l'hostname:


bIp = socket.gethostbyname(bHost)


On établie enfin la connexion:


irc.connect((bIp, bPort))


A savoir que lorsqu'on se connecte à irc, il y a deux commandes que le serveur s'attend à recevoir avant de vous accepter : NICK et USER

NICK <votrePseudo>
USER <nomd'Utilisateur> <hote> <nomDeServeur> <nomReel>


irc.send('NICK %s\r\n' % bPseudo)
irc.send('USER %s %s %s :Python bot irc\r\n' (bPseudo, bPseudo, bPseudo))


J'ai mis un ":" devant Python pour lui dire qu'il va y avoir des espaces et qu'il doit en tenir compte.
Après cela, vous allez recevoir le motd du serveur de cette manière:

:server raw votrePseudo :message

Etant donnée qu'il est sur plusieurs lignes vous aurez différent raw. (exemple: 001, 002, etc..)

Les raws sont très important, c'est un nombre à 3chiffres, qui vous sont envoyé par le serveur lors de certains évènement:

Exemple:

  • 001 : Welcome du serveur
  • 375 : Début du motd
  • 376 : Fin du motd
  • 366 : Fin du names list : Quand on rejoint un channel, le serveur envoi toutes les personnes présentes sur le channel et pour signaler qu'il a fini de lister les personnes sur le channel il envoit un message avec le raw 366
Les raws sont un très bon moyen pour automatiser certaines actions.

Exemple:
  • A la fin du motd, rejoindre un channel
  • A la fin du names list, dire bonjour sur le channel
On va créer une variable 'loop' avec la valeur 1 pour ensuite réaliser une boucle infinie, qu'on pourra échapper en changeant sa valeur.

loop = 1

while loop == 1:

et on écoute dans la boucle ce que la socket a à nous dire:

data = irc.recv(4096)

Maintenant on va séparer le data par ligne et cela en utilisant split de la librairie string, et puis l'afficher


 ligne = data.split("\r")

 for i in ligne:
  i = i.strip("\n")
  print "[%s] %s" % (time.strftime('%X'), i)
  mot = i.split(' ')


J'en ai aussi profité pour créer une liste nommé 'mot' , dans laquelle on met chacun des mots de la ligne.
Ce qui va nous permettre de répondre au ping du serveur

Voici un exemple de ping reçu par le serveur:

  • PING :irc.shakeababy.net
  • PING :<serveur>
Un ping est une méthode pour vérifier que le client est toujours "vivant" en répondant "PING :serveur". Si vous ne répondez pas au bout d'un temps configuré par le serveur, alors votre connexion sera considéré comme morte et donc vous serez déconnecté.

Donc on reçoit en quelques sortes 2 mots, dont le premier est 'PING', on créait une condition pour y répondre :


  if len(mot) == 2 and mot[0] == 'PING':
   irc.send('PONG %s\r\n' % mot[1])


Voilà maintenant on se connecte, on répondra à tout les ping envoyé. Nous devons joindre le channel et c'est là qu'on va utilisé nos raws vu précédemment pour nous connecter à la fin du motd.

La ligne est de cette forme:

  • :irc.shakeababy.net 376 nowzzz :End of /MOTD command.
  • :<serveur> 376 <pseudo> :End of /MOTD command.
Donc on a plus de 2mots, dont le deuxième est 376

  if len(mot) > 2 and mot[1] == '376':
   irc.send('JOIN %s\r\n' % bChannel)

Et voilà ! 
Vous êtes connecté au serveur, vous avez rejoint le channel et vous répondez au ping.

J'admets qu'il y aurait beaucoup d'amélioration possible, comme par exemple créer une liste pour la variable bChannel, et rejoindre plusieurs channel.
Créer une fonction qui se reconnecterait en cas de perte de connexion et d'autres fonctions bien sympathique.
Vous pouvez participer en répondant à cette article.

Dans la seconde partie, nous entrerons un peu plus dans le sujet.

Code source entier: (Lien : pastie )

# -*- coding: utf-8 -*-

#import
import time
import socket
import string
 
#variables
bHost = 'irc.rizon.net'
bIp = socket.gethostbyname(bHost)
bPort = 6667
bPseudo = 'lePseudo'
bChannel = '#lechannel'

#autres variables
loop = 1

#connection
irc = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
irc.connect((bIp, bPort))

#message pour établir la connexion
irc.send('NICK %s\r\n' % bPseudo)
irc.send('USER %s %s %s :Python bot irc\r\n' % (bPseudo, bPseudo, bPseudo))

#boucle infinie
while loop == 1:
 data = irc.recv(4096)

 ligne = data.split("\r")

 for i in ligne:
  i = i.strip("\n")
  print "[%s] %s" % (time.strftime('%X'), i)
  mot = i.split(' ')

  if len(mot) > 2 and mot[1] == '376':
   irc.send('JOIN %s\r\n' % bChannel)
  

  if len(mot) == 2 and mot[0] == 'PING':
   irc.send('PONG %s\r\n' % mot[1])
nowz

Aucun commentaire:

Enregistrer un commentaire