diff options
-rw-r--r-- | config.h | 4 | ||||
-rw-r--r-- | general_network.c | 3 | ||||
-rw-r--r-- | general_network.h | 1 | ||||
-rw-r--r-- | gnutls_network.c | 71 | ||||
-rw-r--r-- | gnutls_network.h | 1 | ||||
-rw-r--r-- | openssl_network.c | 37 | ||||
-rw-r--r-- | openssl_network.h | 1 | ||||
-rw-r--r-- | plaintext_network.c | 4 | ||||
-rw-r--r-- | plaintext_network.h | 1 | ||||
-rw-r--r-- | protocols/inspircd2.c | 45 | ||||
-rw-r--r-- | protocols/inspircd2.h | 3 |
11 files changed, 151 insertions, 20 deletions
@@ -46,6 +46,10 @@ struct server_config { char autoconnect; // = 1; size_t autoconnect_type; // = NET_TYPE_GNUTLS, + char ignore_remote_unlinks; + char ignore_remote_kills; + char ignore_local_kills; + // autoconnect only struct string address; // = "haxnet.org", struct string port; // = "4321", diff --git a/general_network.c b/general_network.c index 4012687..432faa0 100644 --- a/general_network.c +++ b/general_network.c @@ -88,6 +88,7 @@ struct network networks[NUM_NET_TYPES] = { .recv = plaintext_recv, .connect = plaintext_connect, .accept = plaintext_accept, + .shutdown = plaintext_shutdown, .close = plaintext_close, }, #endif @@ -97,6 +98,7 @@ struct network networks[NUM_NET_TYPES] = { .recv = gnutls_recv, .connect = gnutls_connect, .accept = gnutls_accept, + .shutdown = gnutls_shutdown, .close = gnutls_close, }, #endif @@ -106,6 +108,7 @@ struct network networks[NUM_NET_TYPES] = { .recv = openssl_recv, .connect = openssl_connect, .accept = openssl_accept, + .shutdown = openssl_shutdown, .close = openssl_close, }, #endif diff --git a/general_network.h b/general_network.h index dc00e43..1413741 100644 --- a/general_network.h +++ b/general_network.h @@ -42,6 +42,7 @@ struct network { int (*connect)(void **handle, struct string address, struct string port, struct string *addr_out); int (*accept)(int listen_fd, void **handle, struct string *addr); + void (*shutdown)(void *handle); void (*close)(int fd, void *handle); }; diff --git a/gnutls_network.c b/gnutls_network.c index 68cd251..54b3783 100644 --- a/gnutls_network.c +++ b/gnutls_network.c @@ -29,6 +29,8 @@ #include <arpa/inet.h> #include <errno.h> #include <gnutls/gnutls.h> +#include <poll.h> +#include <pthread.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> @@ -38,6 +40,13 @@ #include "general_network.h" #include "gnutls_network.h" +struct gnutls_handle { + gnutls_session_t session; + pthread_mutex_t mutex; + int fd; + char valid; +}; + gnutls_certificate_credentials_t gnutls_cert_creds; int init_gnutls_network(void) { @@ -56,21 +65,61 @@ int init_gnutls_network(void) { return 0; } -int gnutls_send(void *session, struct string msg) { - do { - ssize_t res; - do { - res = gnutls_record_send(*((gnutls_session_t*)session), msg.data, msg.len); - } while (res == GNUTLS_E_INTERRUPTED || res == GNUTLS_E_AGAIN); +int gnutls_send(void *handle, struct string msg) { + struct gnutls_handle *gnutls_handle = handle; + + pthread_mutex_lock(&(gnutls_handle->mutex)); + + if (!gnutls_handle->valid) + goto gnutls_send_error_unlock; - if (res < 0 || (size_t)res > msg.len) { // res > len shouldn't be possible, but is still an error - return 1; - } else if ((size_t)res == msg.len) { + struct pollfd pollfd = { + .fd = gnutls_handle->fd, + }; + do { + ssize_t gnutls_res; + int poll_res; + gnutls_res = gnutls_record_send(gnutls_handle->session, msg.data, msg.len); + if (gnutls_res <= 0) { + if (gnutls_res == GNUTLS_E_INTERRUPTED) { + continue; + } else if (gnutls_res == GNUTLS_E_AGAIN) { + pollfd.events = POLLIN | POLLOUT; + do { + poll_res = poll(&pollfd, 1, 0); + } while (poll_res < 0 && errno == EINTR); + if (poll_res < 0) + goto gnutls_send_error_unlock; + + if ((pollfd.revents & (POLLIN | POLLOUT)) == (POLLIN | POLLOUT) || (pollfd.revents & (POLLIN | POLLOUT)) == 0) + continue; + else if (pollfd.revents & POLLIN) + pollfd.events = POLLOUT; + else + pollfd.events = POLLIN; + } + } else { break; } + + do { + poll_res = poll(&pollfd, 1, PING_INTERVAL*1000); + } while (poll_res < 0 && errno == EINTR); + if (poll_res < 0) + goto gnutls_send_error_unlock; + if (poll_res == 0) // Timed out + goto gnutls_send_error_unlock; + if ((pollfd.revents & (POLLIN | POLLOUT)) == 0) + goto gnutls_send_error_unlock; } while (1); + pthread_mutex_unlock(&(gnutls_handle->mutex)); return 0; + + gnutls_send_error_unlock: + gnutls_handle->valid = 0; + pthread_mutex_unlock(&(gnutls_handle->mutex)); + return 1; } size_t gnutls_recv(void *session, char *data, size_t len, char *err) { @@ -126,7 +175,7 @@ int gnutls_connect(void **handle, struct string address, struct string port, str goto gnutls_connect_close; *handle = session; - if (gnutls_init(session, GNUTLS_CLIENT) != GNUTLS_E_SUCCESS) + if (gnutls_init(session, GNUTLS_CLIENT | GNUTLS_NONBLOCK) != GNUTLS_E_SUCCESS) goto gnutls_connect_free_session; if (gnutls_server_name_set(*session, GNUTLS_NAME_DNS, address.data, address.len) != GNUTLS_E_SUCCESS) @@ -192,7 +241,7 @@ int gnutls_accept(int listen_fd, void **handle, struct string *addr) { goto gnutls_accept_free_addr_data; *handle = session; - if (gnutls_init(session, GNUTLS_SERVER) != GNUTLS_E_SUCCESS) + if (gnutls_init(session, GNUTLS_SERVER | GNUTLS_NONBLOCK) != GNUTLS_E_SUCCESS) goto gnutls_accept_free_session; if (gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE, gnutls_cert_creds) != GNUTLS_E_SUCCESS) diff --git a/gnutls_network.h b/gnutls_network.h index c70f2e3..f4f4358 100644 --- a/gnutls_network.h +++ b/gnutls_network.h @@ -41,4 +41,5 @@ size_t gnutls_recv(void *fd, char *data, size_t len, char *err); int gnutls_connect(void **handle, struct string address, struct string port, struct string *addr_out); int gnutls_accept(int listen_fd, void **handle, struct string *addr); +void gnutls_shutdown(void *handle); void gnutls_close(int fd, void *handle); diff --git a/openssl_network.c b/openssl_network.c index 60b2189..efc2492 100644 --- a/openssl_network.c +++ b/openssl_network.c @@ -43,6 +43,7 @@ struct openssl_handle { SSL *ssl; pthread_mutex_t mutex; int fd; + char valid; }; SSL_CTX *openssl_ctx; @@ -70,6 +71,9 @@ int openssl_send(void *handle, struct string msg) { pthread_mutex_lock(&(openssl_handle->mutex)); + if (!openssl_handle->valid) + goto openssl_send_error_unlock; + struct pollfd pollfd = { .fd = openssl_handle->fd, }; @@ -91,15 +95,12 @@ int openssl_send(void *handle, struct string msg) { break; } - res = poll(&pollfd, 1, -1); // TODO: What if the buffer is never ready? But openssl demands that the send buffer remain unchanged... - if (res < 0) { - if (errno == EINTR) { - continue; - } else { - goto openssl_send_error_unlock; - } - } - if (res == 0) // Shouldn't actually happen, but checking anyways + do { + res = poll(&pollfd, 1, PING_INTERVAL*1000); + } while (res < 0 && errno == EINTR); + if (res < 0) + goto openssl_send_error_unlock; + if (res == 0) // Timed out... maybe handle differently later goto openssl_send_error_unlock; if ((pollfd.revents & (POLLIN | POLLOUT)) == 0) // Only errors returned goto openssl_send_error_unlock; @@ -109,6 +110,7 @@ int openssl_send(void *handle, struct string msg) { return 0; openssl_send_error_unlock: + openssl_handle->valid = 0; pthread_mutex_unlock(&(openssl_handle->mutex)); return 1; } @@ -122,6 +124,11 @@ size_t openssl_recv(void *handle, char *data, size_t len, char *err) { int res; do { pthread_mutex_lock(&(openssl_handle->mutex)); + if (!openssl_handle->valid) { + pthread_mutex_unlock(&(openssl_handle->mutex)); + *err = 3; + return 0; + } res = SSL_read(openssl_handle->ssl, data, len); pthread_mutex_unlock(&(openssl_handle->mutex)); if (res <= 0) { @@ -258,6 +265,8 @@ int openssl_connect(void **handle, struct string address, struct string port, st goto openssl_connect_destroy_mutex; } while (1); + openssl_handle->valid = 1; + return fd; openssl_connect_destroy_mutex: @@ -354,6 +363,8 @@ int openssl_accept(int listen_fd, void **handle, struct string *addr) { goto openssl_accept_destroy_mutex; } while (1); + openssl_handle->valid = 1; + return con_fd; openssl_accept_destroy_mutex: @@ -370,6 +381,14 @@ int openssl_accept(int listen_fd, void **handle, struct string *addr) { return -1; } +void openssl_shutdown(void *handle) { + struct openssl_handle *openssl_handle = handle; + pthread_mutex_lock(&(openssl_handle->mutex)); + shutdown(openssl_handle->fd, SHUT_RDWR); + openssl_handle->valid = 0; + pthread_mutex_unlock(&(openssl_handle->mutex)); +} + void openssl_close(int fd, void *handle) { struct openssl_handle *openssl_handle = handle; pthread_mutex_destroy(&(openssl_handle->mutex)); diff --git a/openssl_network.h b/openssl_network.h index 83f0432..3cb940a 100644 --- a/openssl_network.h +++ b/openssl_network.h @@ -41,4 +41,5 @@ size_t openssl_recv(void *handle, char *data, size_t len, char *err); int openssl_connect(void **handle, struct string address, struct string port, struct string *addr_out); int openssl_accept(int listen_fd, void **handle, struct string *addr); +void openssl_shutdown(void *handle); void openssl_close(int fd, void *handle); diff --git a/plaintext_network.c b/plaintext_network.c index ce040ce..7fe2486 100644 --- a/plaintext_network.c +++ b/plaintext_network.c @@ -162,6 +162,10 @@ int plaintext_accept(int listen_fd, void **handle, struct string *addr) { return con_fd; } +void plaintext_shutdown(void *handle) { + shutdown(*((int*)handle), SHUT_RDWR); +} + void plaintext_close(int fd, void *handle) { free(handle); close(fd); diff --git a/plaintext_network.h b/plaintext_network.h index e30e5ca..c34c7e1 100644 --- a/plaintext_network.h +++ b/plaintext_network.h @@ -41,4 +41,5 @@ size_t plaintext_recv(void *fd, char *data, size_t len, char *err); int plaintext_connect(void **handle, struct string address, struct string port, struct string *addr_out); int plaintext_accept(int listen_fd, void **handle, struct string *addr); +void plaintext_shutdown(void *handle); void plaintext_close(int fd, void *handle); diff --git a/protocols/inspircd2.c b/protocols/inspircd2.c index 0650c7d..46c9f8b 100644 --- a/protocols/inspircd2.c +++ b/protocols/inspircd2.c @@ -124,11 +124,16 @@ int init_inspircd2_protocol(void) { set_table_index(&inspircd2_protocol_init_commands, STRING("CAPAB"), &inspircd2_protocol_init_handle_capab); set_table_index(&inspircd2_protocol_init_commands, STRING("SERVER"), &inspircd2_protocol_init_handle_server); + + 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("RSQUIT"), &inspircd2_protocol_handle_rsquit); + set_table_index(&inspircd2_protocol_commands, STRING("UID"), &inspircd2_protocol_handle_uid); set_table_index(&inspircd2_protocol_commands, STRING("QUIT"), &inspircd2_protocol_handle_quit); +// set_table_index(&inspircd2_protocol_commands, STRING("KILL"), &inspircd2_protocol_handle_kill); return 0; } @@ -189,6 +194,7 @@ void * inspircd2_protocol_connection(void *type) { goto inspircd2_protocol_handle_connection_close; timeout++; + pthread_mutex_lock(&(state_lock)); networks[net].send(handle, STRING(":")); networks[net].send(handle, SID); networks[net].send(handle, STRING(" PING ")); @@ -196,6 +202,7 @@ void * inspircd2_protocol_connection(void *type) { networks[net].send(handle, STRING(" :")); networks[net].send(handle, config->sid); networks[net].send(handle, STRING("\n")); + pthread_mutex_unlock(&(state_lock)); } else { goto inspircd2_protocol_handle_connection_close; } @@ -845,6 +852,44 @@ int inspircd2_protocol_handle_squit(struct string source, size_t argc, struct st return 0; } +// [:source] RSQUIT <server name> [<reason>?] +int inspircd2_protocol_handle_rsquit(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config *config, char is_incoming) { + if (argc < 1) { + WRITES(2, STRING("[InspIRCd v2] Invalid RSQUIT recieved! (Missing parameters)\r\n")); + return -1; + } + + if (config->ignore_remote_unlinks) + return 0; + + for (size_t i = 0; i < server_list.len; i++) { + struct server_info *target = server_list.array[i].ptr; + if (target->protocol != INSPIRCD2_PROTOCOL) + continue; // TODO: Maybe actually unlink this somehow + if (!STRING_EQ(target->name, argv[0])) + continue; + + if (has_table_index(target->connected_to, SID)) { + networks[target->net].shutdown(target->handle); + } else { + struct server_info *next = get_table_index(server_list, target->next); + networks[next->net].send(next->handle, STRING(":")); + networks[next->net].send(next->handle, source); + networks[next->net].send(next->handle, STRING(" RSQUIT ")); + networks[next->net].send(next->handle, argv[0]); + if (argc > 1) { + networks[next->net].send(next->handle, STRING(" :")); + networks[next->net].send(next->handle, argv[1]); + networks[next->net].send(next->handle, STRING("\n")); + } else { + networks[next->net].send(next->handle, STRING(":\n")); + } + } + } + + 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) { diff --git a/protocols/inspircd2.h b/protocols/inspircd2.h index e31bf19..03963b6 100644 --- a/protocols/inspircd2.h +++ b/protocols/inspircd2.h @@ -58,8 +58,11 @@ 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_rsquit(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); +int inspircd2_protocol_handle_kill(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 |