Aug 12 2009

Botirc, mon copain

Category: C, RéseauFaltad @ 12:56 am

Cette dernière semaine m’est venu l’envie de coder un bot, pour irc, comme ça, sur un coup de tête.

Pour être honnête, je ne savais pas du tout par où commencer, mais j’avais jeté mon dévolu sur le langage C.
Puis, je suis tombé sur cette merveilleuse chose qu’est la RFC.

Donc, si on abrège cette divine documentation, pour se connecter à un serveur, il faut, outre se connecter au serveur lui même, envoyer dans un certain ordre des commandes pour s’identifier.
On se connecte :

/*
** On se connecte d'abord au serveur. Ici, c'est se.quakenet.org
*/

sock = xsocket(AF_INET, SOCK_STREAM, 0);
sin.sin_addr.s_addr = inet_addr(host);
sin.sin_family = AF_INET;
sin.sin_port = htons(6667);
if (connect(sock, (struct sockaddr *) sin, sizeof(struct sockaddr)) == -1)
{
        perror("connect()");
        exit(errno);
}

Ensuite, la RFC nous dit qu’il faut envoyer une commande NICK, suivi d’un USER.

/*
** Envoi des identifiants au serveur.
** Le NICK est de la forme suivante : "NICK :pseudo\n"
** Et le USER, lui, est : "USER nom hôte nom de serveur :pseudo\n"
** un snprintf dans un buffer alloué suffisament peut-être intéressant.
*/

snprintf(nick, SIZE_BUFFER, "NICK :%s\n", nickname);
snprintf(user, SIZE_BUFFER, "USER %s %s %s :%s\n", name, hostname, server_name, nickname);
xsend(sock, nick, strlen(nick), 0);
xsend(sock, user, strlen(user), 0);

Attention, n’oubliez pas de mettre un caractère ‘:’ avant votre pseudo, sinon le serveur ne prendra que le dernier mot.
Maintenant que nous sommes identifié, il faut juste rejoindre le channel voulu.

/*
** Un simple message du style : "JOIN CHANNEL" suffira amplement
*/

snprintf(join, SIZE_BUFFER, "JOIN %s", channel);
xsend(sock, join, strlen(join), 0);

Bon, reste plus qu’à compiler, et à tester. En surveillant le chan avec l’aide d’un client normal, on devrait pouvoir voir le bot se connecter.
Mais non, il ne se passe rien ! C’est quoi ce binz ?

Allons voir ça de plus près avec telnet : (on rentre les commandes par l’entrée standard, telnet se charge de les envoyer au serveur)

telnet irc.quakenet.org 6667
Trying 66.225.225.66...
Connected to irc.quakenet.org.
Escape character is '^]'.
NOTICE AUTH :*** Looking up your hostname
NOTICE AUTH :*** Checking Ident
NOTICE AUTH :*** Found your hostname
NOTICE AUTH :*** No ident response
NICK Faltad
PING :4085172480
USER Faltad test test faltad
JOIN #epinantes
:servercentral.il.us.quakenet.org 451 Faltad Faltad :Register first.

On voit donc, que le serveur nous demande de nous enregistrer ! Mais comment ?
Et bien en fait, il a aussi envoyé un message de ping (ici PING :4085172480).
Il faut donc lui répondre par un PONG :4085172480.
Et hop, ca marche beaucoup mieux !

Un petit dernier truc, pour envoyer un message à une personne ou à un channel, il faut utiliser la commande suivante :
Et les messages que nous envoient les autres utilisateurs arrivent sous cette forme aussi.
:4085172480

/*
** Syntaxe : "PRIVMSG CHANNEL :message\n"
** Ne pas oublier le ':'
*/

snprintf(message, SIZE_BUFFER, "PRIVMSG %s :%s\n", channel, msg);
xsend(sock, message, strlen(message), 0);

Le bot est maintenant prêt à régner sur l’IRC, il va falloir lui trouver une occupation, et ça, c’est plus dur :)
N’hésitez pas a fouiller la RFC, pour utiliser des commandes plus ciblés (du genre KICK).

Voilà, j’espère que mon premier article n’est pas trop confus, ni moche..
Merci de m’avoir lu ! À bientôt.

PS : Le chan #epinantes sur quakenet vous attends ;)

2 Responses to “Botirc, mon copain”

  1. Korfuri says:

    Hi,

    It’s always a good idea to use either snprintf or asprintf (or asnprintf) instead of sprintf when dealing with non-fixed length messages. It’s especially nasty in a networker environment, with inputs incomming from really-not-trustable-at-all sources ;)

  2. Faltad says:

    Hello !

    That’s right, i forgot it :(
    Let’s correct it now !
    Thanks a lot.

Leave a Reply