diff options
Diffstat (limited to 'src/irc/bot/botnet.c')
-rw-r--r-- | src/irc/bot/botnet.c | 827 |
1 files changed, 0 insertions, 827 deletions
diff --git a/src/irc/bot/botnet.c b/src/irc/bot/botnet.c deleted file mode 100644 index 3eb038e5..00000000 --- a/src/irc/bot/botnet.c +++ /dev/null @@ -1,827 +0,0 @@ -/* - botnet.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., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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" - -void botnet_connection_init(void); -void botnet_connection_deinit(void); - -void botnet_users_deinit(void); -void botnet_users_init(void); - -GSList *botnets; - -void bot_send_cmd(BOT_REC *bot, const char *data) -{ - g_return_if_fail(bot != NULL); - g_return_if_fail(data != NULL); - - net_transmit(bot->handle, data, strlen(data)); - net_transmit(bot->handle, "\n", 1); -} - -void bot_send_cmdv(BOT_REC *bot, const char *format, ...) -{ - va_list args; - char *str; - - va_start(args, format); - - str = g_strdup_vprintf(format, args); - bot_send_cmd(bot, str); - g_free(str); - - va_end(args); -} - -static void botnet_broadcast_single(BOTNET_REC *botnet, BOT_REC *except_bot, - const char *source, const char *data) -{ - GNode *node; - char *str; - - g_return_if_fail(botnet != NULL); - g_return_if_fail(data != NULL); - - str = g_strdup_printf("%s - %s", source != NULL ? source : - botnet->nick, data); - for (node = botnet->bots->children; node != NULL; node = node->next) { - BOT_REC *rec = node->data; - - if (rec != except_bot && rec->handle != NULL) - bot_send_cmd(rec, str); - } - g_free(str); -} - -/* broadcast a message to everyone in bot network, except for `except_bot' - if it's not NULL. If botnet is NULL, the message is sent to all botnets. */ -void botnet_broadcast(BOTNET_REC *botnet, BOT_REC *except_bot, - const char *source, const char *data) -{ - GSList *tmp; - - g_return_if_fail(data != NULL); - - if (botnet != NULL) { - botnet_broadcast_single(botnet, except_bot, source, data); - return; - } - - /* broadcast to all botnets */ - for (tmp = botnets; tmp != NULL; tmp = tmp->next) { - BOTNET_REC *rec = tmp->data; - - botnet_broadcast_single(rec, except_bot, source, data); - } -} - -void botnet_send_cmd(BOTNET_REC *botnet, const char *source, - const char *target, const char *data) -{ - GNode *node; - char *str; - - g_return_if_fail(botnet != NULL); - g_return_if_fail(target != NULL); - g_return_if_fail(data != NULL); - - node = bot_find_path(botnet, target); - if (node == NULL) { - g_warning("Can't find route for target %s", target); - return; - } - - str = g_strdup_printf("%s %s %s", source != NULL ? source : - botnet->nick, target, data); - bot_send_cmd(node->data, str); - g_free(str); -} - -static void escape_buffer(char *buffer, int len) -{ - char *dest, *tempbuf, *p; - - dest = buffer; - tempbuf = p = g_malloc(len*2+2); - while (len > 0) { - if (*buffer == '\0') { - *p++ = '\\'; - *p++ = '0'; - } else if (*buffer == '\r') { - *p++ = '\\'; - *p++ = 'r'; - } else if (*buffer == '\n') { - *p++ = '\\'; - *p++ = 'n'; - } else if (*buffer == '\\') { - *p++ = '\\'; - *p++ = '\\'; - } else { - *p++ = *buffer; - } - len--; buffer++; - } - *p++ = '\0'; - - len = (int) (p-tempbuf); - memcpy(dest, tempbuf, len); - g_free(tempbuf); -} - -int botnet_send_file(BOTNET_REC *botnet, const char *target, const char *fname) -{ - GNode *node; - GString *str; - char buffer[1024]; - int f, len; - - node = bot_find_path(botnet, target); - if (node == NULL) { - g_warning("Can't find route for target %s", target); - return FALSE; - } - - f = open(fname, O_RDONLY); - if (f == -1) return FALSE; - - str = g_string_new(NULL); - - g_string_sprintf(str, "%s %s FILE %s", botnet->nick, target, g_basename(fname)); - bot_send_cmd(node->data, str->str); - - while ((len = read(f, buffer, sizeof(buffer)/2-2)) > 0) { - escape_buffer(buffer, len); - - g_string_sprintf(str, "%s %s FILE %s", botnet->nick, target, buffer); - bot_send_cmd(node->data, str->str); - } - - g_string_sprintf(str, "%s %s FILE", botnet->nick, target); - bot_send_cmd(node->data, str->str); - g_string_free(str, TRUE); - - close(f); - return TRUE; -} - -BOTNET_REC *botnet_find(const char *name) -{ - GSList *tmp; - - g_return_val_if_fail(name != NULL, NULL); - - for (tmp = botnets; tmp != NULL; tmp = tmp->next) { - BOTNET_REC *rec = tmp->data; - - if (g_strcasecmp(rec->name, name) == 0) - return rec; - } - - return NULL; -} - -typedef struct { - gconstpointer key; - int priority; - GNode *node; -} BOT_FIND_REC; - -static int gnode_find_nick(GNode *node, BOT_FIND_REC *rec) -{ - BOT_REC *bot = node->data; - - if (bot == NULL) return FALSE; - - if (bot->nick != NULL && g_strcasecmp(bot->nick, rec->key) == 0) { - rec->node = node; - return TRUE; - } - - return FALSE; -} - -GNode *bot_find_nick(BOTNET_REC *botnet, const char *nick) -{ - BOT_FIND_REC rec; - - g_return_val_if_fail(botnet != NULL, NULL); - g_return_val_if_fail(nick != NULL, NULL); - - rec.key = nick; - rec.node = NULL; - g_node_traverse(botnet->bots, 0, G_TRAVERSE_ALL, -1, - (GNodeTraverseFunc) gnode_find_nick, &rec); - return rec.node; -} - -/* Return the bot who we should send the message if we wanted `nick' to get it. */ -GNode *bot_find_path(BOTNET_REC *botnet, const char *nick) -{ - BOT_FIND_REC rec; - GNode *node; - - g_return_val_if_fail(botnet != NULL, NULL); - g_return_val_if_fail(nick != NULL, NULL); - - rec.key = nick; - rec.node = NULL; - for (node = botnet->bots->children; node != NULL; node = node->next) { - g_node_traverse(node, 0, G_TRAVERSE_ALL, -1, - (GNodeTraverseFunc) gnode_find_nick, &rec); - if (rec.node != NULL) return node; - } - return rec.node; -} - -/* check if `addr' is an IP address - this is checked to make sure that - if we have an address like "192.168.0.*", it wouldn't match to host name - 192.168.0.host.org */ -static int is_ip_mask(const char *addr) -{ - while (*addr != '\0') { - if (!i_isdigit(*addr) && *addr != '.' && - *addr != '*' && *addr != '?') return FALSE; - addr++; - } - - return TRUE; -} - -BOT_DOWNLINK_REC *bot_downlink_find(BOTNET_REC *botnet, IPADDR *ip, const char *host) -{ - GSList *tmp, *tmp2; - char ipname[MAX_IP_LEN]; - - g_return_val_if_fail(botnet != NULL, NULL); - g_return_val_if_fail(ip != NULL, NULL); - - net_ip2host(ip, ipname); - - for (tmp = botnet->downlinks; tmp != NULL; tmp = tmp->next) { - BOT_DOWNLINK_REC *rec = tmp->data; - - for (tmp2 = rec->valid_addrs; tmp2 != NULL; tmp2 = tmp2->next) { - if (match_wildcards(tmp2->data, ipname)) - return rec; - if (match_wildcards(tmp2->data, host) && - !is_ip_mask(tmp2->data)) - return rec; - } - } - - return NULL; -} - -static int gnode_find_master(GNode *node, BOT_FIND_REC *rec) -{ - BOT_REC *bot = node->data; - - if (bot == NULL) return FALSE; - - if (!bot->disconnect && bot->priority > rec->priority) { - rec->node = node; - return TRUE; - } - - return FALSE; -} - -BOT_REC *botnet_find_master(BOTNET_REC *botnet, BOT_REC *old_master) -{ - BOT_FIND_REC rec; - - g_return_val_if_fail(botnet != NULL, NULL); - - rec.node = NULL; - rec.priority = old_master == NULL ? -1 : old_master->priority; - g_node_traverse(botnet->bots, 0, G_TRAVERSE_ALL, -1, - (GNodeTraverseFunc) gnode_find_master, &rec); - return rec.node == NULL ? old_master : rec.node->data; -} - -void botnet_set_master(BOTNET_REC *botnet, BOT_REC *bot) -{ - g_return_if_fail(botnet != NULL); - g_return_if_fail(bot != NULL); - - if (botnet->master != NULL) - botnet->master->master = FALSE; - - bot->master = TRUE; - botnet->master = bot; -} - -void bot_nick_destroy(BOT_CHANNEL_REC *rec, NICK_REC *nick) -{ - g_return_if_fail(rec != NULL); - g_return_if_fail(nick != NULL); - - rec->nicks = g_slist_remove(rec->nicks, nick); - - g_free(nick->nick); - g_free_not_null(nick->realname); - g_free_not_null(nick->host); - g_free(nick); -} - -void bot_channel_destroy(BOT_IRCNET_REC *ircnet, BOT_CHANNEL_REC *rec) -{ - g_return_if_fail(ircnet != NULL); - g_return_if_fail(rec != NULL); - - ircnet->channels = g_slist_remove(ircnet->channels, rec); - - while (rec->nicks != NULL) - bot_nick_destroy(rec, rec->nicks->data); - - g_slist_foreach(rec->banlist, (GFunc) g_free, NULL); - g_slist_foreach(rec->ebanlist, (GFunc) g_free, NULL); - g_slist_foreach(rec->invitelist, (GFunc) g_free, NULL); - - g_slist_free(rec->banlist); - g_slist_free(rec->ebanlist); - g_slist_free(rec->invitelist); - - g_free_not_null(rec->mode); - g_free_not_null(rec->key); - g_free(rec->name); - g_free(rec); -} - -void bot_ircnet_destroy(BOT_REC *bot, BOT_IRCNET_REC *rec) -{ - g_return_if_fail(bot != NULL); - g_return_if_fail(rec != NULL); - - bot->ircnets = g_slist_remove(bot->ircnets, bot); - - while (rec->channels != NULL) - bot_channel_destroy(rec, rec->channels->data); - - g_free(rec->tag); - g_free(rec->ircnet); - g_free(rec->server); - g_free(rec->nick); - g_free(rec); -} - -void bot_disconnect(BOT_REC *bot) -{ - bot->disconnect = TRUE; - - signal_emit("bot disconnected", 1, bot); - - if (bot->read_tag != -1) { - g_source_remove(bot->read_tag); - bot->read_tag = -1; - } - if (bot->handle != NULL) { - net_disconnect(bot->handle); - bot->handle = NULL; - } -} - -static void bot_mark_disconnect(GNode *node) -{ - BOT_REC *bot = node->data; - - bot->disconnect = TRUE; -} - -#define bot_mark_disconnects(node) \ - g_node_traverse(node, G_LEVEL_ORDER, G_TRAVERSE_ALL, -1, \ - (GNodeTraverseFunc) bot_mark_disconnect, NULL) - -void bot_destroy(BOT_REC *bot) -{ - GNode *node; - - g_return_if_fail(bot != NULL); - - node = g_node_find(bot->botnet->bots, 0, G_TRAVERSE_ALL, bot); - if (node != NULL) { - if (!bot->disconnect) - bot_mark_disconnects(node); - } - - bot_disconnect(bot); - - if (node != NULL) { - while (node->children != NULL) - bot_destroy(node->children->data); - g_node_destroy(node); - } - - if (bot->botnet->uplink == bot) - bot->botnet->uplink = NULL; - if (bot->botnet->master == bot) - bot->botnet->master = NULL; - - while (bot->ircnets != NULL) - bot_ircnet_destroy(bot, bot->ircnets->data); - - line_split_free(bot->buffer); - g_free_not_null(bot->nick); - g_free(bot); -} - -void bot_downlink_destroy(BOT_DOWNLINK_REC *rec) -{ - rec->botnet->downlinks = g_slist_remove(rec->botnet->downlinks, rec); - - g_slist_foreach(rec->valid_addrs, (GFunc) g_free, NULL); - g_slist_free(rec->valid_addrs); - - g_free_not_null(rec->password); - g_free(rec); -} - -void bot_uplink_destroy(BOT_UPLINK_REC *rec) -{ - rec->botnet->uplinks = g_slist_remove(rec->botnet->uplinks, rec); - - g_free(rec->host); - g_free_not_null(rec->password); - g_free(rec); -} - -void botnet_disconnect(BOTNET_REC *botnet) -{ - botnet->connected = FALSE; - - bot_destroy(botnet->bots->data); - botnet->bots = NULL; - - if (botnet->listen_tag != -1) { - g_source_remove(botnet->listen_tag); - botnet->listen_tag = -1; - } - if (botnet->listen_handle != NULL) { - net_disconnect(botnet->listen_handle); - botnet->listen_handle = NULL; - } -} - -static void botnet_destroy(BOTNET_REC *botnet) -{ - botnets = g_slist_remove(botnets, botnet); - - while (botnet->uplinks != NULL) - bot_uplink_destroy(botnet->uplinks->data); - while (botnet->downlinks != NULL) - bot_downlink_destroy(botnet->downlinks->data); - - botnet_disconnect(botnet); - - g_free_not_null(botnet->addr); - g_free(botnet->name); - g_free(botnet->nick); - g_free(botnet); -} - -static void botnet_event(BOT_REC *bot, const char *data) -{ - char *source, *target, *command, *args, *event; - void *free_arg; - - if (!bot->connected) - return; - - if (!cmd_get_params(data, &free_arg, 4 | PARAM_FLAG_GETREST, - &source, &target, &command, &args)) - return; - - if (*target == '-' && target[1] == '\0') - target = NULL; - g_strdown(command); - - event = g_strconcat("botnet event ", command, NULL); - signal_emit(event, 4, bot, args, source, target); - g_free(event); - - cmd_params_free(free_arg); -} - -/* broadcast the signal forward */ -static void botnet_event_broadcast(BOT_REC *bot, const char *data) -{ - char *source, *target, *command; - void *free_arg; - - if (!bot->connected) - return; - - if (!cmd_get_params(data, &free_arg, 3 | PARAM_FLAG_GETREST, - &source, &target, &command)) - return; - - if (g_strcasecmp(target, bot->botnet->nick) == 0) { - /* message was for us */ - cmd_params_free(free_arg); - return; - } - - if (*target == '-' && target[1] == '\0') { - /* broadcast */ - botnet_broadcast(bot->botnet, bot, source, command); - } else { - /* send to specified target */ - botnet_send_cmd(bot->botnet, source, target, command); - } - - cmd_params_free(free_arg); -} - -static void botnet_event_master(BOT_REC *bot, const char *data, const char *sender) -{ - BOTNET_REC *botnet; - BOT_REC *master; - GNode *node; - char *str; - - botnet = bot->botnet; - - node = bot_find_nick(bot->botnet, data); - master = node == NULL ? NULL : node->data; - master = botnet_find_master(bot->botnet, master); - g_return_if_fail(master != NULL); - - if (node == NULL || node->data != master) { - /* no, we don't agree with that master - - send our own to everyone. */ - bot = NULL; - } - - botnet_set_master(botnet, master); - - str = g_strdup_printf("MASTER %s", master->nick); - botnet_broadcast(botnet, bot, sender, str); - g_free(str); - - signal_stop_by_name("botnet event"); -} - -static int unescape_data(const char *input, char *output) -{ - int len; - - len = 0; - while (*input != '\0') { - if (*input != '\\') - *output++ = *input; - else { - input++; - g_return_val_if_fail(*input != '\0', len); - switch (*input) { - case '\\': - *output++ = '\\'; - break; - case '0': - *output++ = '\0'; - break; - case 'r': - *output++ = '\r'; - break; - case 'n': - *output++ = '\n'; - break; - } - } - input++; - len++; - } - - return len; -} - -static void botnet_event_file(BOT_REC *bot, const char *data, const char *sender, const char *target) -{ - GNode *node; - char *tempbuf, *str; - int len; - - if (g_strcasecmp(target, bot->botnet->nick) != 0) - return; - - node = bot_find_nick(bot->botnet, sender); - g_return_if_fail(node != NULL); - - bot = node->data; - if (bot->file_handle <= 0) { - /* first line - data contains file name */ - str = g_strdup_printf("%s/%s", get_irssi_dir(), data); - bot->file_handle = open(str, O_CREAT|O_TRUNC|O_WRONLY, 0600); - g_free(str); - } else if (*data == '\0') { - /* no data - end of file */ - if (bot->file_handle > 0) { - close(bot->file_handle); - bot->file_handle = -1; - } - } else { - /* file data */ - tempbuf = g_malloc(strlen(data)*2+2); - len = unescape_data(data, tempbuf); - write(bot->file_handle, tempbuf, len); - g_free(tempbuf); - } -} - -static void botnet_config_read_ips(BOT_DOWNLINK_REC *rec, CONFIG_NODE *node) -{ - GSList *tmp; - - g_return_if_fail(rec != NULL); - g_return_if_fail(node != NULL); - - node = config_node_section(node, "valid_addrs", -1); - tmp = node == NULL ? NULL : node->value; - for (; tmp != NULL; tmp = tmp->next) { - node = tmp->data; - rec->valid_addrs = g_slist_append(rec->valid_addrs, g_strdup(node->value)); - } -} - -static void botnet_config_read_uplink(BOTNET_REC *botnet, CONFIG_NODE *node) -{ - BOT_UPLINK_REC *rec; - char *value; - - g_return_if_fail(botnet != NULL); - g_return_if_fail(node != NULL); - - value = config_node_get_str(node, "host", NULL); - if (value == NULL) return; /* host required */ - - rec = g_new0(BOT_UPLINK_REC, 1); - rec->botnet = botnet; - rec->host = g_strdup(value); - rec->port = config_node_get_int(node, "port", DEFAULT_BOTNET_PORT); - rec->password = g_strdup(config_node_get_str(node, "password", NULL)); - - botnet->uplinks = g_slist_append(botnet->uplinks, rec); -} - -static void botnet_config_read_downlink(BOTNET_REC *botnet, CONFIG_NODE *node) -{ - BOT_DOWNLINK_REC *rec; - - g_return_if_fail(botnet != NULL); - g_return_if_fail(node != NULL); - - rec = g_new0(BOT_DOWNLINK_REC, 1); - - botnet_config_read_ips(rec, node); - if (rec->valid_addrs == NULL) { - g_free(rec); - return; - } - - rec->botnet = botnet; - rec->password = g_strdup(config_node_get_str(node, "password", NULL)); - botnet->downlinks = g_slist_append(botnet->downlinks, rec); -} - -static void botnet_config_read_botnet(CONFIG_NODE *node) -{ - CONFIG_NODE *subnode; - BOTNET_REC *botnet; - GSList *tmp; - - g_return_if_fail(node != NULL); - - if (node->key == NULL || node->value == NULL) - return; - - /* New botnet */ - botnet = g_new0(BOTNET_REC, 1); - botnet->name = g_strdup(node->key); - botnet->nick = g_strdup(config_node_get_str(node, "nick", "bot")); - botnet->priority = config_node_get_int(node, "priority", DEFAULT_BOTNET_PRIORITY); - botnet->autoconnect = config_node_get_bool(node, "autoconnect", FALSE); - - botnet->addr = g_strdup(config_node_get_str(node, "listen_addr", NULL)); - botnet->port = config_node_get_int(node, "listen_port", DEFAULT_BOTNET_PORT); - - botnet->listen_tag = -1; - - /* read uplinks */ - subnode = config_node_section(node, "uplinks", -1); - tmp = subnode == NULL ? NULL : subnode->value; - for (; tmp != NULL; tmp = tmp->next) - botnet_config_read_uplink(botnet, tmp->data); - - /* read downlinks */ - subnode = config_node_section(node, "downlinks", -1); - tmp = subnode == NULL ? NULL : subnode->value; - for (; tmp != NULL; tmp = tmp->next) - botnet_config_read_downlink(botnet, tmp->data); - - botnets = g_slist_append(botnets, botnet); -} - -static void botnet_config_read(void) -{ - CONFIG_REC *config; - CONFIG_NODE *node; - GSList *tmp; - char *fname; - - /* Read botnets from ~/.irssi/botnets */ - fname = g_strdup_printf("%s/botnets", get_irssi_dir()); - config = config_open(fname, -1); - g_free(fname); - - if (config == NULL) - return; - - config_parse(config); - - node = config_node_traverse(config, "botnets", FALSE); - tmp = node == NULL ? NULL : node->value; - for (; tmp != NULL; tmp = tmp->next) - botnet_config_read_botnet(tmp->data); - config_close(config); -} - -/* FIXME: this command is just temporary */ -static void cmd_botnet(const char *data) -{ - BOTNET_REC *botnet; - char *str; - - botnet = botnets->data; - - str = g_strdup_printf("BCAST %s", data); - botnet_broadcast(botnet, NULL, NULL, str); - g_free(str); -} - -static void autoconnect_botnets(void) -{ - GSList *tmp; - - for (tmp = botnets; tmp != NULL; tmp = tmp->next) { - BOTNET_REC *rec = tmp->data; - - if (rec->autoconnect) - botnet_connect(rec); - } -} - -void botnet_init(void) -{ - botnet_config_read(); - botnet_connection_init(); - botnet_users_init(); - - signal_add("botnet event", (SIGNAL_FUNC) botnet_event); - signal_add_last("botnet event", (SIGNAL_FUNC) botnet_event_broadcast); - signal_add("botnet event master", (SIGNAL_FUNC) botnet_event_master); - signal_add("botnet event file", (SIGNAL_FUNC) botnet_event_file); - command_bind("botnet", NULL, (SIGNAL_FUNC) cmd_botnet); - - autoconnect_botnets(); -} - -void botnet_deinit(void) -{ - while (botnets) - botnet_destroy(botnets->data); - - botnet_connection_deinit(); - botnet_users_deinit(); - - signal_remove("botnet event", (SIGNAL_FUNC) botnet_event); - signal_remove("botnet event", (SIGNAL_FUNC) botnet_event_broadcast); - signal_remove("botnet event master", (SIGNAL_FUNC) botnet_event_master); - signal_remove("botnet event file", (SIGNAL_FUNC) botnet_event_file); - command_unbind("botnet", (SIGNAL_FUNC) cmd_botnet); -} |