Added bot plugin, it also has almost-functional botnet.

Changed configure.in's functionality so that you could tell what modules you
want to build in main irssi binary and it will create automatically the .c
files that need to call the module_init()/deinit() functions.

Fixed several minor things..


git-svn-id: http://svn.irssi.org/repos/irssi/trunk@230 dbcabf3a-b0e7-0310-adc4-f8d773084564
This commit is contained in:
Timo Sirainen 2000-05-25 11:30:47 +00:00 committed by cras
commit 76605ad0ae
41 changed files with 2809 additions and 246 deletions

View file

@ -0,0 +1,553 @@
/*
botnet-connection.c : IRC bot plugin for irssi
Copyright (C) 1999-2000 Timo Sirainen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "module.h"
#include "network.h"
#include "net-nonblock.h"
#include "signals.h"
#include "commands.h"
#include "misc.h"
#include "line-split.h"
#include "lib-config/iconfig.h"
#include "botnet.h"
#define BOTNET_RECONNECT_TIME (60*5)
static void sig_bot_read(BOT_REC *bot)
{
BOTNET_REC *botnet;
char tmpbuf[1024], *str;
int ret, recvlen, reconnect;
botnet = bot->botnet;
for (;;) {
recvlen = bot->handle == -1 ? -1 :
net_receive(bot->handle, tmpbuf, sizeof(tmpbuf));
ret = line_split(tmpbuf, recvlen, &str, (LINEBUF_REC **) &bot->buffer);
if (ret == 0)
break;
if (ret == -1) {
/* connection lost */
reconnect = !bot->disconnect && bot->uplink;
bot_destroy(bot);
if (reconnect) {
/* wasn't intentional disconnection from
our uplink, reconnect */
botnet_connect(botnet->name);
}
break;
}
fprintf(stderr, "%s\r\n", str);
signal_emit("botnet event", 2, bot, str);
}
}
static void connect_downlink(BOTNET_REC *botnet, int handle,
IPADDR *ip, const char *host)
{
BOT_DOWNLINK_REC *downlink;
BOT_REC *bot;
g_return_if_fail(botnet != NULL);
/* identify the bot who's trying to connect.. */
downlink = bot_downlink_find(botnet, ip, host);
if (downlink == NULL || downlink->password == NULL) {
/* unknown bot, close connection /
bot didn't have password, don't let it connect to us */
net_disconnect(handle);
return;
}
bot = g_new0(BOT_REC, 1);
bot->botnet = botnet;
bot->link = downlink;
g_node_append_data(botnet->bots, bot);
/* connected.. */
bot->handle = handle;
bot->read_tag = g_input_add(handle, G_INPUT_READ, (GInputFunction) sig_bot_read, bot);
}
typedef struct {
char *botnet;
IPADDR ip;
int handle;
} BOT_CONNECT_REC;
static void sig_host_got(RESOLVED_NAME_REC *name, BOT_CONNECT_REC *rec)
{
BOTNET_REC *botnet;
botnet = botnet_find(rec->botnet);
if (botnet == NULL || !botnet->connected) {
/* this botnet isn't connected anymore.. */
net_disconnect(rec->handle);
} else {
connect_downlink(botnet, rec->handle, &rec->ip,
name->error ? NULL : name->name);
}
g_free(rec->botnet);
g_free(rec);
}
static void sig_botnet_listen(BOTNET_REC *botnet)
{
BOT_CONNECT_REC *rec;
IPADDR ip;
int handle;
g_return_if_fail(botnet != NULL);
/* accept connection */
handle = net_accept(botnet->listen_handle, &ip, NULL);
if (handle == -1)
return;
rec = g_new0(BOT_CONNECT_REC, 1);
rec->botnet = g_strdup(botnet->name);
memcpy(&rec->ip, &ip, sizeof(IPADDR));
rec->handle = handle;
if (!net_gethostbyaddr_nonblock(&ip, (NET_HOST_CALLBACK) sig_host_got, rec)) {
/* failed for some reason, try without host */
connect_downlink(botnet, handle, &ip, NULL);
g_free(rec->botnet);
g_free(rec);
}
}
static int botnet_listen(BOTNET_REC *botnet)
{
IPADDR addr;
int port;
g_return_val_if_fail(botnet != NULL, FALSE);
if (botnet->port <= 0)
return FALSE;
port = botnet->port;
if (botnet->addr == NULL)
botnet->listen_handle = net_listen(NULL, &port);
else {
net_host2ip(botnet->addr, &addr);
botnet->listen_handle = net_listen(&addr, &port);
}
if (botnet->listen_handle == -1) {
g_warning("Couldn't start listening botnet\n");
return FALSE;
}
botnet->listen_tag = g_input_add(botnet->listen_handle, G_INPUT_READ,
(GInputFunction) sig_botnet_listen, botnet);
return TRUE;
}
static void sig_botnet_connected(int handle, BOT_UPLINK_REC *uplink)
{
BOTNET_REC *botnet;
BOT_REC *bot;
g_return_if_fail(uplink != NULL);
botnet = uplink->botnet;
if (handle == -1) {
/* error, try another bot */
botnet_connect(botnet->name);
return;
}
/* connected to bot */
bot = g_new0(BOT_REC, 1);
bot->botnet = botnet;
bot->link = uplink;
bot->uplink = TRUE;
bot->handle = handle;
bot->read_tag = g_input_add(handle, G_INPUT_READ, (GInputFunction) sig_bot_read, bot);
botnet->uplink = bot;
g_node_append_data(botnet->bots, bot);
/* send nick/pass */
bot_send_cmdv(bot, "PASS %s", uplink->password);
bot_send_cmdv(bot, "NICK %s", botnet->nick);
}
int botnet_connect(const char *network)
{
BOTNET_REC *botnet;
BOT_REC *bot;
BOT_UPLINK_REC *uplink, *best;
GSList *tmp;
time_t now;
g_return_val_if_fail(network != NULL, FALSE);
/* find botnet */
botnet = botnet_find(network);
if (botnet == NULL) return FALSE;
if (botnet->bots == NULL) {
/* create bot record for us */
bot = g_new0(BOT_REC, 1);
bot->botnet = botnet;
bot->nick = g_strdup(botnet->nick);
bot->priority = botnet->priority;
bot->connected = TRUE;
bot->master = TRUE;
bot->handle = -1;
bot->read_tag = -1;
botnet->connected = TRUE;
botnet->master = bot;
botnet->bots = g_node_new(bot);
}
if (botnet->listen_handle == -1) {
/* start listening */
botnet_listen(botnet);
}
/* find some bot where we can try to connect to */
now = time(NULL);
uplink = best = NULL;
for (tmp = botnet->uplinks; tmp != NULL; tmp = tmp->next) {
uplink = tmp->data;
if (uplink->last_connect+BOTNET_RECONNECT_TIME > now)
continue;
if (uplink->last_connect == 0) {
/* haven't yet tried to connect to this bot */
best = uplink;
break;
}
if (best == NULL || uplink->last_connect < best->last_connect)
best = uplink;
}
if (best == NULL)
return FALSE;
/* connect to uplink */
best->last_connect = time(NULL);
net_connect_nonblock(best->host, best->port, NULL, (NET_CALLBACK) sig_botnet_connected, best);
return TRUE;
}
static int botnet_send_botinfo(GNode *node, BOT_REC *client)
{
BOT_REC *parent, *bot;
bot = node->data;
parent = node->parent == NULL ? NULL : node->parent->data;
if (parent == NULL && client->uplink) parent = client;
bot_send_cmdv(client, "%s - BOTINFO %s %s %d", bot->botnet->nick, bot->nick,
parent != NULL ? parent->nick : "-", bot->priority);
return FALSE;
}
/* send botnet links to specified bot */
static void botnet_send_links(BOT_REC *bot, int downlinks)
{
GNode *node;
if (!downlinks) {
/* send uplinks */
if (bot->botnet->uplink == NULL)
return;
node = g_node_find(bot->botnet->bots, G_IN_ORDER,
G_TRAVERSE_ALL, bot->botnet->uplink);
if (node == NULL)
return;
g_node_traverse(node, G_LEVEL_ORDER, G_TRAVERSE_ALL, -1,
(GNodeTraverseFunc) botnet_send_botinfo, bot);
return;
}
/* send downlinks = all non-uplink nodes */
for (node = bot->botnet->bots->children; node != NULL; node = node->next) {
BOT_REC *rec = node->data;
if (rec == bot || rec->uplink || !rec->connected)
continue;
g_node_traverse(node, G_LEVEL_ORDER, G_TRAVERSE_ALL, -1,
(GNodeTraverseFunc) botnet_send_botinfo, bot);
}
}
static void botnet_connect_event_uplink(BOT_REC *bot, const char *data)
{
BOTNET_REC *botnet;
BOT_REC *ownbot;
char *str, *p;
int num;
botnet = bot->botnet;
g_return_if_fail(botnet != NULL);
if (g_strcasecmp(data, "NICKERROR") == 0) {
/* nick already in use, change it by adding a number
at the end of it */
p = botnet->nick+strlen(botnet->nick);
while (p > botnet->nick && isdigit(p[-1])) p--;
num = *p == '\0' ? 2 : atoi(p)+1; *p = '\0';
str = g_strdup_printf("%s%d", botnet->nick, num);
g_free(botnet->nick); botnet->nick = str;
ownbot = botnet->bots->data;
g_free(ownbot->nick); ownbot->nick = g_strdup(str);
/* try again.. */
bot_send_cmdv(bot, "NICK %s", botnet->nick);
return;
}
if (g_strcasecmp(data, "CONNECTED") == 0) {
/* connected, wait for SYNC command */
bot->connected = TRUE;
return;
}
/* error? what? */
}
static void botnet_event(BOT_REC *bot, const char *data)
{
BOT_DOWNLINK_REC *downlink;
g_return_if_fail(bot != NULL);
g_return_if_fail(data != NULL);
if (bot->connected)
return;
if (bot->uplink) {
botnet_connect_event_uplink(bot, data);
return;
}
downlink = bot->link;
if (!bot->pass_ok && g_strncasecmp(data, "PASS ", 5) == 0) {
/* password sent, check that it matches */
if (strcmp(data+5, downlink->password) == 0) {
/* ok, connected! */
bot->pass_ok = TRUE;
} else {
/* wrong password, disconnect */
bot_disconnect(bot);
}
return;
}
if (g_strncasecmp(data, "NICK ", 5) == 0) {
/* set bot's nick */
if (!bot->pass_ok) {
/* password has to be sent before nick, kill the
stupid bot. */
bot_disconnect(bot);
return;
}
if (g_strcasecmp(bot->botnet->nick, data+5) == 0 ||
bot_find_nick(bot->botnet, data+5) != NULL) {
/* nick already exists */
bot_send_cmd(bot, "NICKERROR");
return;
}
/* set the nick */
bot->nick = g_strdup(data+5);
bot->connected = TRUE;
bot_send_cmd(bot, "CONNECTED");
/* send info about all the bots that are connected now
to this botnet */
botnet_send_botinfo(bot->botnet->bots, bot);
botnet_send_links(bot, FALSE);
botnet_send_links(bot, TRUE);
bot_send_cmdv(bot, "%s - MASTER %s", bot->botnet->nick, bot->botnet->master->nick);
bot_send_cmdv(bot, "%s - SYNC", bot->botnet->nick);
return;
}
/* pass/nick not sent yet */
bot_send_cmd(bot, "ERROR");
}
static void botnet_event_sync(BOT_REC *bot)
{
/* send our record to host */
botnet_send_botinfo(bot->botnet->bots, bot);
/* send our downlinks to host */
botnet_send_links(bot, TRUE);
}
static BOT_REC *bot_add(BOTNET_REC *botnet, const char *nick, const char *parent)
{
GNode *node;
BOT_REC *rec;
g_return_val_if_fail(botnet != NULL, NULL);
g_return_val_if_fail(nick != NULL, NULL);
node = bot_find_nick(botnet, nick);
if (node != NULL) return node->data;
node = bot_find_nick(botnet, parent);
if (node == NULL) return NULL;
rec = g_new0(BOT_REC, 1);
rec->botnet = botnet;
rec->nick = g_strdup(nick);
rec->handle = -1;
rec->read_tag = -1;
rec->connected = TRUE;
g_node_append_data(node, rec);
return rec;
}
static void botnet_event_botinfo(BOT_REC *bot, const char *data, const char *sender)
{
char *str, *params, *nick, *parent, *priority;
BOT_REC *rec;
str = g_strdup_printf("BOTINFO %s", data);
botnet_broadcast(bot->botnet, bot, sender, str);
g_free(str);
params = cmd_get_params(data, 3, &nick, &parent, &priority);
if (*parent == '-' && parent[1] == '\0')
parent = NULL;
if (parent == NULL && bot->botnet->uplink != NULL &&
bot->botnet->uplink == bot) {
/* our uplink */
if (bot->nick == NULL) bot->nick = g_strdup(nick);
rec = bot;
} else {
rec = bot_add(bot->botnet, nick, parent);
}
if (rec != NULL) {
rec->priority = atoi(priority);
}
g_free(params);
}
static void botnet_event_botquit(BOT_REC *bot, const char *data)
{
GNode *node;
node = bot_find_nick(bot->botnet, data);
if (node != NULL) bot_destroy(node->data);
}
static void sig_bot_disconnected(BOT_REC *bot)
{
BOT_REC *master, *tmpbot;
GNode *node;
char *str;
if (!bot->botnet->connected)
return;
if (bot->connected && bot->handle != -1) {
/* send notice to rest of the botnet about quit */
str = g_strdup_printf("BOTQUIT %s", bot->nick);
botnet_broadcast(bot->botnet, bot, NULL, str);
g_free(str);
}
if (bot->master) {
/* master quit */
node = bot_find_path(bot->botnet, bot->nick);
tmpbot = node == NULL ? NULL : node->data;
if (tmpbot != NULL && tmpbot->disconnect) {
/* we lost the connection to master - find new
master for the botnet*/
master = botnet_find_master(bot->botnet, NULL);
botnet_set_master(bot->botnet, master);
str = g_strdup_printf("MASTER %s", master->nick);
botnet_broadcast(bot->botnet, bot, NULL, str);
g_free(str);
}
}
}
static int print_bot(GNode *node)
{
BOT_REC *bot = node->data;
fprintf(stderr, "%s %d %d\r\n", bot->nick, bot->connected, bot->disconnect);
return FALSE;
}
static void cmd_bots(void)
{
BOTNET_REC *botnet = botnet_find("ircnet");
fprintf(stderr, "\r\n");
g_node_traverse(botnet->bots, G_LEVEL_ORDER, G_TRAVERSE_ALL, -1,
(GNodeTraverseFunc) print_bot, NULL);
}
void botnet_connection_init(void)
{
signal_add("botnet event", (SIGNAL_FUNC) botnet_event);
signal_add("botnet event sync", (SIGNAL_FUNC) botnet_event_sync);
signal_add("botnet event botinfo", (SIGNAL_FUNC) botnet_event_botinfo);
signal_add("botnet event botquit", (SIGNAL_FUNC) botnet_event_botquit);
signal_add("bot disconnected", (SIGNAL_FUNC) sig_bot_disconnected);
command_bind("bots", NULL, (SIGNAL_FUNC) cmd_bots);
}
void botnet_connection_deinit(void)
{
signal_remove("botnet event", (SIGNAL_FUNC) botnet_event);
signal_remove("botnet event sync", (SIGNAL_FUNC) botnet_event_sync);
signal_remove("botnet event botinfo", (SIGNAL_FUNC) botnet_event_botinfo);
signal_remove("botnet event botquit", (SIGNAL_FUNC) botnet_event_botquit);
signal_remove("bot disconnected", (SIGNAL_FUNC) sig_bot_disconnected);
command_unbind("bots", (SIGNAL_FUNC) cmd_bots);
}