aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--config.h4
-rw-r--r--general_network.c3
-rw-r--r--general_network.h1
-rw-r--r--gnutls_network.c71
-rw-r--r--gnutls_network.h1
-rw-r--r--openssl_network.c37
-rw-r--r--openssl_network.h1
-rw-r--r--plaintext_network.c4
-rw-r--r--plaintext_network.h1
-rw-r--r--protocols/inspircd2.c45
-rw-r--r--protocols/inspircd2.h3
11 files changed, 151 insertions, 20 deletions
diff --git a/config.h b/config.h
index 421c554..383ac83 100644
--- a/config.h
+++ b/config.h
@@ -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