diff options
author | Test_User <hax@andrewyu.org> | 2024-06-10 23:20:14 -0400 |
---|---|---|
committer | Test_User <hax@andrewyu.org> | 2024-06-10 23:20:14 -0400 |
commit | 47d7e30f6acb1c170c8e5e15f2656b89a33384f7 (patch) | |
tree | d5b8c7e0641b77647b6e44c4c37ed4664e468299 | |
parent | 5534441086cee3130c95460e22ed29bff44cbaef (diff) | |
download | haxircd-47d7e30f6acb1c170c8e5e15f2656b89a33384f7.tar.gz haxircd-47d7e30f6acb1c170c8e5e15f2656b89a33384f7.zip |
Mostly complete user tracking added
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | general_network.c | 200 | ||||
-rw-r--r-- | general_network.h | 50 | ||||
-rw-r--r-- | protocols.c | 2 | ||||
-rw-r--r-- | protocols.h | 6 | ||||
-rw-r--r-- | protocols/inspircd2.c | 349 | ||||
-rw-r--r-- | protocols/inspircd2.h | 23 | ||||
-rw-r--r-- | server_network.c | 42 | ||||
-rw-r--r-- | server_network.h | 23 |
9 files changed, 625 insertions, 72 deletions
@@ -28,7 +28,7 @@ INCLUDEFLAGS = -CFLAGS += $(INCLUDEFLAGS) -D_REENTRANT -ggdb3 -Wall -Wextra -Wsign-conversion -Wno-unused-parameter -std=gnu99 +CFLAGS += $(INCLUDEFLAGS) -D_REENTRANT -ggdb3 -Wall -Wextra -Wsign-conversion -Wno-unused-parameter -Wno-implicit-fallthrough -std=gnu99 LDFLAGS = -lpthread diff --git a/general_network.c b/general_network.c index 5987e98..6df6ba8 100644 --- a/general_network.c +++ b/general_network.c @@ -27,6 +27,8 @@ // OTHER DEALINGS IN THE SOFTWARE. #include <arpa/inet.h> +#include <stdlib.h> +#include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netdb.h> @@ -108,6 +110,7 @@ struct network networks[NUM_NET_TYPES] = { }; struct table server_list = {0}; +struct table user_list = {0}; // TODO: Proper string handling int resolve(struct string address, struct string port, struct sockaddr *sockaddr) { @@ -130,7 +133,6 @@ int resolve(struct string address, struct string port, struct sockaddr *sockaddr return success; } -// TODO: May leak memory on failure, not currently an issue since this failing currently just results in program exit anyways int init_general_network(void) { for (size_t i = 1; i < UCHAR_MAX + 1; i++) { if (casemap[i] == 0) { @@ -138,5 +140,201 @@ int init_general_network(void) { } } + server_list.array = malloc(0); + + struct server_info *own_info; + own_info = malloc(sizeof(*own_info)); + if (!own_info) { + free(server_list.array); + return 1; + } + + own_info->sid.data = malloc(SID.len); + if (!own_info->sid.data) { + free(server_list.array); + free(own_info); + return 1; + } + memcpy(own_info->sid.data, SID.data, SID.len); + own_info->sid.len = SID.len; + + own_info->name.data = malloc(SERVER_NAME.len); + if (!own_info->name.data) { + free(server_list.array); + free(own_info->sid.data); + free(own_info); + return 1; + } + memcpy(own_info->name.data, SERVER_NAME.data, SERVER_NAME.len); + own_info->name.len = SERVER_NAME.len; + + own_info->fullname.data = malloc(SERVER_FULLNAME.len); + if (!own_info->fullname.data) { + free(server_list.array); + free(own_info->name.data); + free(own_info->sid.data); + free(own_info); + return 1; + } + memcpy(own_info->fullname.data, SERVER_FULLNAME.data, SERVER_FULLNAME.len); + own_info->fullname.len = SERVER_FULLNAME.len; + + if (set_table_index(&server_list, SID, own_info) != 0) { + free(server_list.array); + free(own_info->fullname.data); + free(own_info->name.data); + free(own_info->sid.data); + free(own_info); + return 1; + } + + own_info->next = SID; + own_info->connected_to = (struct table){.array = malloc(0), .len = 0}; + own_info->user_list = (struct table){.array = malloc(0), .len = 0}; + own_info->distance = 0; + own_info->net = 0; + own_info->protocol = 0; + + user_list.array = malloc(0); + return 0; } + +int add_user(struct string from, struct string attached_to, struct string uid, struct string nick, struct string fullname, struct string ident, struct string vhost, struct string host, struct string address, size_t user_ts, size_t nick_ts, void *handle, size_t protocol, size_t net) { + struct server_info *attached = get_table_index(server_list, attached_to); + if (!attached) + return 1; + + if (has_table_index(user_list, uid)) + return 1; + + struct user_info *new_info; + new_info = malloc(sizeof(*new_info)); + if (!new_info) + return 1; + + new_info->user_ts = user_ts; + new_info->nick_ts = nick_ts; + + new_info->protocol = protocol; + new_info->net = net; + new_info->handle = handle; + + new_info->server = attached->sid; + + new_info->uid.data = malloc(uid.len); + if (!new_info->uid.data) + goto add_user_free_info; + memcpy(new_info->uid.data, uid.data, uid.len); + new_info->uid.len = uid.len; + + new_info->nick.data = malloc(nick.len); + if (!new_info->nick.data) + goto add_user_free_uid; + memcpy(new_info->nick.data, nick.data, nick.len); + new_info->nick.len = nick.len; + + new_info->fullname.data = malloc(fullname.len); + if (!new_info->fullname.data && fullname.len != 0) + goto add_user_free_nick; + memcpy(new_info->fullname.data, fullname.data, fullname.len); + new_info->fullname.len = fullname.len; + + new_info->ident.data = malloc(ident.len); + if (!new_info->ident.data) + goto add_user_free_fullname; + memcpy(new_info->ident.data, ident.data, ident.len); + new_info->ident.len = ident.len; + + new_info->vhost.data = malloc(vhost.len); + if (!new_info->vhost.data) + goto add_user_free_ident; + memcpy(new_info->vhost.data, vhost.data, vhost.len); + new_info->vhost.len = vhost.len; + + new_info->host.data = malloc(host.len); + if (!new_info->host.data) + goto add_user_free_vhost; + memcpy(new_info->host.data, host.data, host.len); + new_info->host.len = host.len; + + new_info->address.data = malloc(address.len); + if (!new_info->address.data) + goto add_user_free_host; + memcpy(new_info->address.data, address.data, address.len); + new_info->address.len = address.len; + + if (set_table_index(&user_list, uid, new_info) != 0) + goto add_user_free_address; + + if (set_table_index(&(attached->user_list), uid, new_info) != 0) + goto add_user_remove_user_list; + + new_info->channel_list.array = malloc(0); + new_info->channel_list.len = 0; + +#ifdef USE_SERVER +#ifdef USE_HAXIRCD_PROTOCOL + protocols[HAXIRCD_PROTOCOL].propagate_new_user(from, new_info); +#endif +#ifdef USE_INSPIRCD2_PROTOCOL + protocols[INSPIRCD2_PROTOCOL].propagate_new_user(from, new_info); +#endif +#endif + + return 0; + + add_user_remove_user_list: + remove_table_index(&user_list, uid); + add_user_free_address: + free(new_info->address.data); + add_user_free_host: + free(new_info->host.data); + add_user_free_vhost: + free(new_info->vhost.data); + add_user_free_ident: + free(new_info->ident.data); + add_user_free_fullname: + free(new_info->fullname.data); + add_user_free_nick: + free(new_info->nick.data); + add_user_free_uid: + free(new_info->uid.data); + add_user_free_info: + free(new_info); + + return 1; +} + +void remove_user(struct string from, struct user_info *user, struct string reason, char propagate) { +#ifdef USE_SERVER + if (propagate) { +#ifdef USE_HAXIRCD_PROTOCOL + protocols[HAXIRCD_PROTOCOL].propagate_remove_user(from, user, reason); +#endif +#ifdef USE_INSPIRCD2_PROTOCOL + protocols[INSPIRCD2_PROTOCOL].propagate_remove_user(from, user, reason); +#endif + } +#endif + + remove_table_index(&user_list, user->uid); + + struct server_info *server = get_table_index(server_list, user->server); + if (server) { + remove_table_index(&(server->user_list), user->uid); + } + + // TODO: Channel cleanup code hereish + clear_table(&(user->channel_list)); + free(user->channel_list.array); + + free(user->uid.data); + free(user->nick.data); + free(user->fullname.data); + free(user->ident.data); + free(user->vhost.data); + free(user->host.data); + free(user->address.data); + free(user); +} diff --git a/general_network.h b/general_network.h index 202f877..6b76256 100644 --- a/general_network.h +++ b/general_network.h @@ -45,10 +45,57 @@ struct network { void (*close)(int fd, void *handle); }; +struct server_info { + struct string sid; + struct string name; + struct string fullname; + + struct string next; // Self for self, else which server we should send a message to to get to this server + + struct table connected_to; // List of servers that this server is connected to + + struct table user_list; + + void *handle; + + size_t protocol; + size_t net; + + size_t distance; +}; + +struct user_info { + struct string uid; + struct string nick; + struct string fullname; + + struct string ident; + + struct string vhost; + struct string host; + struct string address; + + size_t user_ts; + size_t nick_ts; + + struct string server; + + struct table channel_list; + + void *handle; + + size_t protocol; + size_t net; +}; + int resolve(struct string address, struct string port, struct sockaddr *sockaddr); int init_general_network(void); +int add_user(struct string from, struct string attached_to, struct string uid, struct string nick, struct string fullname, struct string ident, struct string vhost, struct string host, struct string address, size_t user_ts, size_t nick_ts, void *handle, size_t protocol, size_t net); +// Does not propagate, but will inform local clients about it +void remove_user(struct string from, struct user_info *user, struct string reason, char propagate); + extern char casemap[UCHAR_MAX+1]; #define CASEMAP(x) (casemap[(unsigned char)x]) @@ -64,3 +111,6 @@ extern char casemap[UCHAR_MAX+1]; #define NUM_NET_TYPES 3 extern struct network networks[NUM_NET_TYPES]; + +extern struct table server_list; +extern struct table user_list; diff --git a/protocols.c b/protocols.c index 1adb383..04dd2f9 100644 --- a/protocols.c +++ b/protocols.c @@ -41,6 +41,8 @@ struct protocol protocols[NUM_PROTOCOLS] = { .propagate_new_server = inspircd2_protocol_propagate_new_server, .propagate_unlink = inspircd2_protocol_propagate_unlink, + .propagate_new_user = inspircd2_protocol_propagate_new_user, + .propagate_remove_user = inspircd2_protocol_propagate_remove_user, .do_unlink = inspircd2_protocol_do_unlink, }, diff --git a/protocols.h b/protocols.h index 3b4aca3..723d971 100644 --- a/protocols.h +++ b/protocols.h @@ -33,10 +33,12 @@ struct protocol { void * (*autoconnect)(void *config); void (*update_propagations)(void); - void (*propagate_new_server)(struct string from, struct string attached_to, struct string sid, struct server_info *info); + void (*propagate_new_server)(struct string from, struct string attached_to, struct server_info *info); void (*propagate_unlink)(struct string from, struct server_info *a, struct server_info *b, size_t protocol); + void (*propagate_new_user)(struct string from, struct user_info *info); + void (*propagate_remove_user)(struct string from, struct user_info *info, struct string reason); - void (*do_unlink)(struct server_info *a, struct server_info *b); + void (*do_unlink)(struct string from, struct server_info *a, struct server_info *b); }; #ifdef USE_HAXIRCD_PROTOCOL diff --git a/protocols/inspircd2.c b/protocols/inspircd2.c index 496c0d0..883dbc5 100644 --- a/protocols/inspircd2.c +++ b/protocols/inspircd2.c @@ -43,6 +43,81 @@ struct table inspircd2_protocol_init_commands = {0}; struct table inspircd2_protocol_commands = {0}; +char inspircd2_protocol_user_mode_types[UCHAR_MAX+1] = { + ['c'] = MODE_TYPE_NOARGS, + ['d'] = MODE_TYPE_NOARGS, + ['g'] = MODE_TYPE_NOARGS, + ['h'] = MODE_TYPE_NOARGS, + ['i'] = MODE_TYPE_NOARGS, + ['k'] = MODE_TYPE_NOARGS, + ['o'] = MODE_TYPE_NOARGS, + ['r'] = MODE_TYPE_NOARGS, + ['s'] = MODE_TYPE_MODE, + ['w'] = MODE_TYPE_NOARGS, + ['x'] = MODE_TYPE_NOARGS, + ['z'] = MODE_TYPE_NOARGS, + ['B'] = MODE_TYPE_NOARGS, + ['D'] = MODE_TYPE_NOARGS, + ['G'] = MODE_TYPE_NOARGS, + ['H'] = MODE_TYPE_NOARGS, + ['I'] = MODE_TYPE_NOARGS, + ['L'] = MODE_TYPE_NOARGS, + ['N'] = MODE_TYPE_NOARGS, + ['O'] = MODE_TYPE_NOARGS, + ['R'] = MODE_TYPE_NOARGS, + ['S'] = MODE_TYPE_NOARGS, + ['T'] = MODE_TYPE_NOARGS, + ['W'] = MODE_TYPE_NOARGS, +}; + +char inspircd2_protocol_channel_mode_types[UCHAR_MAX+1] = { + ['a'] = MODE_TYPE_USERS, + ['b'] = MODE_TYPE_MULTIPLE, + ['c'] = MODE_TYPE_NOARGS, + ['d'] = MODE_TYPE_REPLACE, + ['e'] = MODE_TYPE_MULTIPLE, + ['f'] = MODE_TYPE_REPLACE, + ['g'] = MODE_TYPE_REPLACE, + ['h'] = MODE_TYPE_USERS, + ['i'] = MODE_TYPE_NOARGS, + ['j'] = MODE_TYPE_REPLACE, + ['k'] = MODE_TYPE_REPLACE, + ['l'] = MODE_TYPE_REPLACE, + ['m'] = MODE_TYPE_NOARGS, + ['n'] = MODE_TYPE_NOARGS, + ['o'] = MODE_TYPE_USERS, + ['p'] = MODE_TYPE_NOARGS, + ['q'] = MODE_TYPE_USERS, + ['r'] = MODE_TYPE_NOARGS, + ['s'] = MODE_TYPE_NOARGS, + ['t'] = MODE_TYPE_NOARGS, + ['u'] = MODE_TYPE_NOARGS, + ['v'] = MODE_TYPE_USERS, + ['w'] = MODE_TYPE_MULTIPLE, + ['z'] = MODE_TYPE_NOARGS, + ['A'] = MODE_TYPE_NOARGS, + ['B'] = MODE_TYPE_NOARGS, + ['C'] = MODE_TYPE_NOARGS, + ['D'] = MODE_TYPE_NOARGS, + ['E'] = MODE_TYPE_REPLACE, + ['F'] = MODE_TYPE_REPLACE, + ['G'] = MODE_TYPE_NOARGS, + ['H'] = MODE_TYPE_REPLACE, + ['I'] = MODE_TYPE_MULTIPLE, + ['J'] = MODE_TYPE_REPLACE, + ['K'] = MODE_TYPE_NOARGS, + ['L'] = MODE_TYPE_REPLACE, + ['M'] = MODE_TYPE_NOARGS, + ['N'] = MODE_TYPE_NOARGS, + ['O'] = MODE_TYPE_NOARGS, + ['P'] = MODE_TYPE_NOARGS, + ['Q'] = MODE_TYPE_NOARGS, + ['R'] = MODE_TYPE_NOARGS, + ['S'] = MODE_TYPE_NOARGS, + ['T'] = MODE_TYPE_NOARGS, + ['X'] = MODE_TYPE_MULTIPLE, +}; + int init_inspircd2_protocol(void) { inspircd2_protocol_commands.array = malloc(0); @@ -52,6 +127,8 @@ int init_inspircd2_protocol(void) { set_table_index(&inspircd2_protocol_commands, STRING("PING"), &inspircd2_protocol_handle_ping); set_table_index(&inspircd2_protocol_commands, STRING("SERVER"), &inspircd2_protocol_handle_server); set_table_index(&inspircd2_protocol_commands, STRING("SQUIT"), &inspircd2_protocol_handle_squit); + set_table_index(&inspircd2_protocol_commands, STRING("UID"), &inspircd2_protocol_handle_uid); + set_table_index(&inspircd2_protocol_commands, STRING("QUIT"), &inspircd2_protocol_handle_quit); return 0; } @@ -159,7 +236,7 @@ void * inspircd2_protocol_connection(void *type) { offset++; if (msg_len == offset) { - WRITES(2, STRING("Protocol violation: empty message.\r\n\n")); + WRITES(2, STRING("[InspIRCd v2] Protocol violation: empty message.\r\n\n")); goto inspircd2_protocol_handle_connection_close; } @@ -180,11 +257,16 @@ void * inspircd2_protocol_connection(void *type) { source.len++; } if (source.len == 0) { - WRITES(2, STRING("Protocol violation: source prefix but no source.\r\n\n")); + WRITES(2, STRING("[InspIRCd v2] Protocol violation: source prefix but no source.\r\n\n")); goto inspircd2_protocol_handle_connection_close; } if (!found || offset >= msg_len) { - WRITES(2, STRING("Protocol violation: source but no command.\r\n\n")); + WRITES(2, STRING("[InspIRCd v2] Protocol violation: source but no command.\r\n\n")); + goto inspircd2_protocol_handle_connection_close; + } + + if (STRING_EQ(source, SID)) { + WRITES(2, STRING("[InspIRCd v2] Protocol violation: other server sent us as source!\r\n\n")); goto inspircd2_protocol_handle_connection_close; } } else { @@ -372,7 +454,7 @@ void inspircd2_protocol_update_propagations(void) { inspircd2_protocol_update_propagations_inner(self); } -void inspircd2_protocol_propagate_new_server(struct string from, struct string attached_to, struct string sid, struct server_info *info) { +void inspircd2_protocol_propagate_new_server(struct string from, struct string attached_to, struct server_info *info) { struct server_info *self = get_table_index(server_list, SID); for (size_t i = 0; i < self->connected_to.len; i++) { @@ -390,13 +472,13 @@ void inspircd2_protocol_propagate_new_server(struct string from, struct string a networks[adjacent->net].send(adjacent->handle, STRING(" SERVER ")); networks[adjacent->net].send(adjacent->handle, info->name); networks[adjacent->net].send(adjacent->handle, STRING(" * 0 ")); - networks[adjacent->net].send(adjacent->handle, sid); + networks[adjacent->net].send(adjacent->handle, info->sid); networks[adjacent->net].send(adjacent->handle, STRING(" :")); networks[adjacent->net].send(adjacent->handle, info->fullname); networks[adjacent->net].send(adjacent->handle, STRING("\n")); networks[adjacent->net].send(adjacent->handle, STRING(":")); - networks[adjacent->net].send(adjacent->handle, sid); + networks[adjacent->net].send(adjacent->handle, info->sid); networks[adjacent->net].send(adjacent->handle, STRING(" BURST ")); time_t current = time(0); @@ -404,14 +486,14 @@ void inspircd2_protocol_propagate_new_server(struct string from, struct string a char err = unsigned_to_str((size_t)current, ¤t_time); if (current < 0 || err) { - networks[adjacent->net].send(adjacent->handle, STRING("0")); + networks[adjacent->net].send(adjacent->handle, STRING("1")); } else { networks[adjacent->net].send(adjacent->handle, current_time); free(current_time.data); } networks[adjacent->net].send(adjacent->handle, STRING("\n:")); - networks[adjacent->net].send(adjacent->handle, sid); + networks[adjacent->net].send(adjacent->handle, info->sid); networks[adjacent->net].send(adjacent->handle, STRING(" ENDBURST\n")); } } @@ -446,7 +528,74 @@ void inspircd2_protocol_propagate_unlink(struct string from, struct server_info } } -void inspircd2_protocol_do_unlink_inner(struct server_info *target) { +void inspircd2_protocol_propagate_new_user(struct string from, struct user_info *info) { + struct server_info *self = get_table_index(server_list, SID); + + for (size_t i = 0; i < self->connected_to.len; i++) { + struct server_info *adjacent = self->connected_to.array[i].ptr; + if (adjacent->protocol != INSPIRCD2_PROTOCOL || STRING_EQ(from, adjacent->sid)) + continue; + + networks[adjacent->net].send(adjacent->handle, STRING(":")); + networks[adjacent->net].send(adjacent->handle, info->server); + networks[adjacent->net].send(adjacent->handle, STRING(" UID ")); + networks[adjacent->net].send(adjacent->handle, info->uid); + networks[adjacent->net].send(adjacent->handle, STRING(" ")); + + struct string timestamp; + char err = unsigned_to_str(info->nick_ts, ×tamp); + + if (err) { + networks[adjacent->net].send(adjacent->handle, STRING("1")); // TODO: Better fallback + } else { + networks[adjacent->net].send(adjacent->handle, timestamp); + free(timestamp.data); + } + + networks[adjacent->net].send(adjacent->handle, STRING(" ")); + networks[adjacent->net].send(adjacent->handle, info->nick); + networks[adjacent->net].send(adjacent->handle, STRING(" ")); + networks[adjacent->net].send(adjacent->handle, info->host); + networks[adjacent->net].send(adjacent->handle, STRING(" ")); + networks[adjacent->net].send(adjacent->handle, info->vhost); + networks[adjacent->net].send(adjacent->handle, STRING(" ")); + networks[adjacent->net].send(adjacent->handle, info->ident); + networks[adjacent->net].send(adjacent->handle, STRING(" ")); + networks[adjacent->net].send(adjacent->handle, info->address); + networks[adjacent->net].send(adjacent->handle, STRING(" ")); + + err = unsigned_to_str(info->user_ts, ×tamp); + + if (err) { + networks[adjacent->net].send(adjacent->handle, STRING("1")); + } else { + networks[adjacent->net].send(adjacent->handle, timestamp); + free(timestamp.data); + } + + networks[adjacent->net].send(adjacent->handle, STRING(" + :")); + networks[adjacent->net].send(adjacent->handle, info->fullname); + networks[adjacent->net].send(adjacent->handle, STRING("\n")); + } +} + +void inspircd2_protocol_propagate_remove_user(struct string from, struct user_info *info, struct string reason) { + struct server_info *self = get_table_index(server_list, SID); + + for (size_t i = 0; i < self->connected_to.len; i++) { + struct server_info *adjacent = self->connected_to.array[i].ptr; + if (adjacent->protocol != INSPIRCD2_PROTOCOL || STRING_EQ(from, adjacent->sid)) + continue; + + networks[adjacent->net].send(adjacent->handle, STRING(":")); + networks[adjacent->net].send(adjacent->handle, info->uid); + networks[adjacent->net].send(adjacent->handle, STRING(" QUIT :")); + networks[adjacent->net].send(adjacent->handle, reason); + networks[adjacent->net].send(adjacent->handle, STRING("\n")); + } +} + +void inspircd2_protocol_do_unlink_inner(struct string from, struct server_info *target, struct string reason) { target->distance = 1; // Reusing distance for `have passed`, since its set to 0 bc severed anyways unsigned char i = 0; @@ -456,25 +605,36 @@ void inspircd2_protocol_do_unlink_inner(struct server_info *target) { i = 1; continue; } - inspircd2_protocol_do_unlink_inner(adjacent); - remove_table_index(&(target->connected_to), adjacent->sid); - remove_table_index(&(server_list), adjacent->sid); - free_server(adjacent); + inspircd2_protocol_do_unlink_inner(from, adjacent, reason); + remove_server(from, adjacent, reason); } } -void inspircd2_protocol_do_unlink(struct server_info *a, struct server_info *b) { +void inspircd2_protocol_do_unlink(struct string from, struct server_info *a, struct server_info *b) { + char valid; + struct string reason; + reason.data = malloc(a->name.len + 1 + b->name.len); + if (!reason.data) { + valid = 0; + reason = STRING("*.net *.split"); + } else { + valid = 1; + memcpy(reason.data, a->name.data, a->name.len); + reason.data[a->name.len] = ' '; + memcpy(&(reason.data[a->name.len + 1]), b->name.data, b->name.len); + reason.len = a->name.len + 1 + b->name.len; + } + if (a->distance == 0 && !STRING_EQ(a->sid, SID)) { - inspircd2_protocol_do_unlink_inner(a); - remove_table_index(&(b->connected_to), a->sid); - remove_table_index(&(server_list), a->sid); - free_server(a); + inspircd2_protocol_do_unlink_inner(from, a, reason); + remove_server(from, a, reason); } else { - inspircd2_protocol_do_unlink_inner(b); - remove_table_index(&(a->connected_to), b->sid); - remove_table_index(&(server_list), b->sid); - free_server(b); + inspircd2_protocol_do_unlink_inner(from, b, reason); + remove_server(from, b, reason); } + + if (valid) + free(reason.data); } void inspircd2_protocol_introduce_servers_to_inner(size_t net, void *handle, struct string source, struct server_info *target) { @@ -582,6 +742,49 @@ int inspircd2_protocol_init_handle_server(struct string source, size_t argc, str inspircd2_protocol_introduce_servers_to(net, handle); + for (size_t i = 0; i < user_list.len; i++) { + struct user_info *user = user_list.array[i].ptr; + + networks[net].send(handle, STRING(":")); + networks[net].send(handle, user->server); + networks[net].send(handle, STRING(" UID ")); + networks[net].send(handle, user->uid); + networks[net].send(handle, STRING(" ")); + + struct string timestamp; + char err = unsigned_to_str(user->nick_ts, ×tamp); + + if (err) { + return -1; + } + networks[net].send(handle, timestamp); + free(timestamp.data); + + networks[net].send(handle, STRING(" ")); + networks[net].send(handle, user->nick); + networks[net].send(handle, STRING(" ")); + networks[net].send(handle, user->host); + networks[net].send(handle, STRING(" ")); + networks[net].send(handle, user->vhost); + networks[net].send(handle, STRING(" ")); + networks[net].send(handle, user->ident); + networks[net].send(handle, STRING(" ")); + networks[net].send(handle, user->address); + networks[net].send(handle, STRING(" ")); + + err = unsigned_to_str(user->nick_ts, ×tamp); + + if (err) { + return -1; + } + networks[net].send(handle, timestamp); + free(timestamp.data); + + networks[net].send(handle, STRING(" + :")); + networks[net].send(handle, user->fullname); + networks[net].send(handle, STRING("\n")); + } + networks[net].send(handle, STRING(":")); networks[net].send(handle, SID); networks[net].send(handle, STRING(" ENDBURST\n")); @@ -621,6 +824,11 @@ int inspircd2_protocol_handle_server(struct string source, size_t argc, struct s return -1; } + if (has_table_index(server_list, argv[3])) { + WRITES(2, STRING("[InspIRCd v2] Duplicate SERVER attempted to be created!\r\n")); + return -1; + } + if (add_server(config->sid, source, argv[3], argv[0], argv[4], INSPIRCD2_PROTOCOL, net, handle) != 0) { WRITES(2, STRING("ERROR: Unable to add server!\r\n")); return -1; @@ -655,3 +863,100 @@ int inspircd2_protocol_handle_squit(struct string source, size_t argc, struct st return 0; } + +// [:source] UID <UID> <nick_ts> <nick> <host> <vhost> <ident> <address> <user_ts> <modes> [<mode args>] <fullname> +int inspircd2_protocol_handle_uid(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config *config, char is_incoming) { + if (argc < 10) { + WRITES(2, STRING("[InspIRCd v2] Invalid UID recieved! (Missing parameters)\r\n")); + return -1; + } + + if (has_table_index(user_list, argv[0])) { + WRITES(2, STRING("[InspIRCd v2] Duplicate UID attempted to be created!\r\n")); + return -1; + } + + char dir = '?'; + size_t arg_i = 9; + size_t mode_i = 0; + + while (1) { + if (argv[8].len <= mode_i) + break; + switch(argv[8].data[mode_i]) { + case '+': + case '-': + dir = argv[8].data[mode_i]; + break; + default: + if (dir == '?') { + WRITES(2, STRING("[InspIRCd v2] Invalid UID recieved! (Mode direction not set)\r\n")); + return -1; + } + + switch(inspircd2_protocol_user_mode_types[(unsigned char)argv[8].data[mode_i]]) { + case MODE_TYPE_NOARGS: + break; + case MODE_TYPE_REPLACE: + case MODE_TYPE_MODE: + if (dir == '-') // Shouldn't actually happen here, but whatever + break; + case MODE_TYPE_MULTIPLE: + arg_i++; + break; + default: + WRITES(2, STRING("[InspIRCd v2] Invalid UID recieved! (Unknown mode given)\r\n")); + return -1; + } + } + + mode_i++; + } + + if (arg_i >= argc) { + WRITES(2, STRING("[InspIRCd v2] Invalid UID recieved! (Missing mode arguments)\r\n")); + return -1; + } + + char err; + size_t nick_ts = str_to_unsigned(argv[1], &err); + if (err) { + WRITES(2, STRING("[InspIRCd v2] Invalid UID recieved! (Invalid nick timestamp)\r\n")); + return -1; + } + + size_t user_ts = str_to_unsigned(argv[7], &err); + if (err) { + WRITES(2, STRING("[InspIRCd v2] Invalid UID recieved! (Invalid user timestamp)\r\n")); + return -1; + } + + if (add_user(config->sid, source, argv[0], argv[2], argv[arg_i], argv[5], argv[4], argv[3], argv[6], user_ts, nick_ts, 0, 0, 0) != 0) { + WRITES(2, STRING("ERROR: Unable to add user!\r\n")); + return -1; + } + + return 0; +} + +// :source QUIT <reason> +int inspircd2_protocol_handle_quit(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config *config, char is_incoming) { + struct string reason; + if (argc < 1) + reason = STRING(""); + else + reason = argv[0]; + + struct user_info *user = get_table_index(user_list, source); + if (!user) + return 0; // Maybe KILLed or something + + if (STRING_EQ(user->server, SID)) { + WRITES(2, STRING("[InspIRCd v2] Invalid QUIT recieved! (Attempting to quit a local user)\r\n")); + return -1; + } + + remove_user(config->sid, user, reason, 1); + + return 0; +} diff --git a/protocols/inspircd2.h b/protocols/inspircd2.h index 48a6f59..e31bf19 100644 --- a/protocols/inspircd2.h +++ b/protocols/inspircd2.h @@ -41,14 +41,16 @@ void * inspircd2_protocol_connection(void *type); void * inspircd2_protocol_autoconnect(void *type); void inspircd2_protocol_update_propagations(void); -void inspircd2_protocol_propagate_new_server(struct string from, struct string attached_to, struct string sid, struct server_info *info); +void inspircd2_protocol_propagate_new_server(struct string from, struct string attached_to, struct server_info *info); void inspircd2_protocol_propagate_unlink(struct string from, struct server_info *a, struct server_info *b, size_t protocol); +void inspircd2_protocol_propagate_new_user(struct string from, struct user_info *info); +void inspircd2_protocol_propagate_remove_user(struct string from, struct user_info *info, struct string reason); -void inspircd2_protocol_do_unlink(struct server_info *a, struct server_info *b); +void inspircd2_protocol_do_unlink(struct string from, struct server_info *a, struct server_info *b); void inspircd2_protocol_update_propagations_inner(struct server_info *source); -void inspircd2_protocol_do_unlink_inner(struct server_info *source); +void inspircd2_protocol_do_unlink_inner(struct string from, struct server_info *source, struct string reason); int inspircd2_protocol_init_handle_server(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config **config, char is_incoming); int inspircd2_protocol_init_handle_capab(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config **config, char is_incoming); @@ -56,3 +58,18 @@ int inspircd2_protocol_init_handle_capab(struct string source, size_t argc, stru int inspircd2_protocol_handle_ping(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config *config, char is_incoming); int inspircd2_protocol_handle_server(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config *config, char is_incoming); int inspircd2_protocol_handle_squit(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config *config, char is_incoming); +int inspircd2_protocol_handle_uid(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config *config, char is_incoming); +int inspircd2_protocol_handle_quit(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config *config, char is_incoming); + +#define MODE_TYPE_UNKNOWN 0 +#define MODE_TYPE_NOARGS 1 +#define MODE_TYPE_REPLACE 2 +#define MODE_TYPE_MULTIPLE 3 + +// Channel modes only, goes away when the related user leaves +#define MODE_TYPE_USERS 4 + +// Used for e.g. snomasks +#define MODE_TYPE_MODE 5 +extern char inspircd2_protocol_user_mode_types[UCHAR_MAX+1]; +extern char inspircd2_protocol_channel_mode_types[UCHAR_MAX+1]; diff --git a/server_network.c b/server_network.c index 7f481ec..ea92d3c 100644 --- a/server_network.c +++ b/server_network.c @@ -53,25 +53,6 @@ int init_server_network(void) { } } - server_list.array = malloc(0); - - struct server_info *own_info; - own_info = malloc(sizeof(*own_info)); - own_info->sid.data = malloc(SID.len); - if (!own_info->sid.data) - return 1; - memcpy(own_info->sid.data, SID.data, SID.len); - own_info->sid.len = SID.len; - - own_info->next = SID; - own_info->connected_to = (struct table){.array = malloc(0), .len = 0}; - own_info->user_list = (struct table){.array = malloc(0), .len = 0}; - own_info->distance = 0; - own_info->net = 0; - own_info->protocol = 0; - if (set_table_index(&server_list, SID, own_info) != 0) - return 1; - return 0; } @@ -241,10 +222,10 @@ int add_server(struct string from, struct string attached_to, struct string sid, protocols[protocol].update_propagations(); #ifdef USE_HAXIRCD_PROTOCOL - protocols[HAXIRCD_PROTOCOL].propagate_new_server(from, attached_to, sid, new_info); + protocols[HAXIRCD_PROTOCOL].propagate_new_server(from, attached_to, new_info); #endif #ifdef USE_INSPIRCD2_PROTOCOL - protocols[INSPIRCD2_PROTOCOL].propagate_new_server(from, attached_to, sid, new_info); + protocols[INSPIRCD2_PROTOCOL].propagate_new_server(from, attached_to, new_info); #endif return 0; @@ -267,6 +248,8 @@ int add_server(struct string from, struct string attached_to, struct string sid, void free_server(struct server_info *server) { free(server->sid.data); + free(server->name.data); + free(server->fullname.data); clear_table(&(server->connected_to)); free(server->connected_to.array); clear_table(&(server->user_list)); @@ -275,6 +258,21 @@ void free_server(struct server_info *server) { free(server); } +void remove_server(struct string from, struct server_info *server, struct string reason) { + while (server->user_list.len != 0) { + remove_user(from, server->user_list.array[0].ptr, reason, 0); + } + + for (size_t i = 0; i < server->connected_to.len; i++) { + struct server_info *adjacent = server->connected_to.array[i].ptr; + remove_table_index(&(adjacent->connected_to), server->sid); + } + + remove_table_index(&(server_list), server->sid); + + free_server(server); +} + void update_all_propagations(void) { #ifdef USE_HAXIRCD_PROTOCOL protocols[HAXIRCD_PROTOCOL].update_propagations(); @@ -300,5 +298,5 @@ void unlink_server(struct string from, struct server_info *a, struct server_info protocols[INSPIRCD2_PROTOCOL].propagate_unlink(from, a, b, protocol); #endif - protocols[protocol].do_unlink(a, b); + protocols[protocol].do_unlink(from, a, b); } diff --git a/server_network.h b/server_network.h index ac4a23e..8b6457e 100644 --- a/server_network.h +++ b/server_network.h @@ -28,6 +28,7 @@ #include <stddef.h> +#include "general_network.h" #include "haxstring.h" #include "table.h" @@ -45,25 +46,6 @@ struct server_connection_info { void *handle; }; -struct server_info { - struct string sid; - struct string name; - struct string fullname; - - struct string next; // Self for self, else which server we should send a message to to get to this server - - struct table connected_to; // List of servers that this server is connected to - - struct table user_list; - - void *handle; - - size_t protocol; - size_t net; - - size_t distance; -}; - int init_server_network(void); int start_server_network(void); int start_server_network_threads(size_t net); @@ -74,10 +56,9 @@ void * handle_server_thread(void *type); int add_server(struct string from, struct string attached_to, struct string sid, struct string name, struct string fullname, size_t protocol, size_t net, void *handle); void free_server(struct server_info *server); +void remove_server(struct string from, struct server_info *server, struct string reason); void update_all_propagations(void); void unlink_server(struct string from, struct server_info *a, struct server_info *b, size_t protocol); extern struct table server_config; - -extern struct table server_list; |