diff options
-rw-r--r-- | .gitignore | 7 | ||||
-rw-r--r-- | LICENSE.c | 27 | ||||
-rw-r--r-- | LICENSE.h | 27 | ||||
-rw-r--r-- | Makefile | 271 | ||||
-rw-r--r-- | config.h | 78 | ||||
-rw-r--r-- | general_network.c | 138 | ||||
-rw-r--r-- | general_network.h | 72 | ||||
-rw-r--r-- | gnutls_network.c | 234 | ||||
-rw-r--r-- | gnutls_network.h | 44 | ||||
-rw-r--r-- | haxstring.h | 43 | ||||
-rw-r--r-- | haxstring_utils.c | 75 | ||||
-rw-r--r-- | haxstring_utils.h | 34 | ||||
-rw-r--r-- | main.c | 125 | ||||
-rw-r--r-- | main.h | 34 | ||||
-rw-r--r-- | openssl_network.c | 379 | ||||
-rw-r--r-- | openssl_network.h | 44 | ||||
-rw-r--r-- | plaintext_network.c | 168 | ||||
-rw-r--r-- | plaintext_network.h | 44 | ||||
-rw-r--r-- | protocols.c | 42 | ||||
-rw-r--r-- | protocols.h | 43 | ||||
-rw-r--r-- | protocols/inspircd2.c | 341 | ||||
-rw-r--r-- | protocols/inspircd2.h | 41 | ||||
-rw-r--r-- | server_network.c | 162 | ||||
-rw-r--r-- | server_network.h | 51 | ||||
-rw-r--r-- | table.c | 185 | ||||
-rw-r--r-- | table.h | 48 |
26 files changed, 2757 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8c4fba9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +config.c +*.o +.*.swp +haxserv +core +.makeopts +output diff --git a/LICENSE.c b/LICENSE.c new file mode 100644 index 0000000..708783d --- /dev/null +++ b/LICENSE.c @@ -0,0 +1,27 @@ +// One of the code files for HaxServ +// +// Written by: Test_User <hax@andrewyu.org> +// +// This is free and unencumbered software released into the public +// domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. +// +// In jurisdictions that recognize copyright laws, the author or authors +// of this software dedicate any and all copyright interest in the +// software to the public domain. We make this dedication for the benefit +// of the public at large and to the detriment of our heirs and +// successors. We intend this dedication to be an overt act of +// relinquishment in perpetuity of all present and future rights to this +// software under copyright law. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. diff --git a/LICENSE.h b/LICENSE.h new file mode 100644 index 0000000..a10cafb --- /dev/null +++ b/LICENSE.h @@ -0,0 +1,27 @@ +// Written by: Test_User <hax@andrewyu.org> +// +// This is free and unencumbered software released into the public +// domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. +// +// In jurisdictions that recognize copyright laws, the author or authors +// of this software dedicate any and all copyright interest in the +// software to the public domain. We make this dedication for the benefit +// of the public at large and to the detriment of our heirs and +// successors. We intend this dedication to be an overt act of +// relinquishment in perpetuity of all present and future rights to this +// software under copyright law. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#pragma once diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..4bc5184 --- /dev/null +++ b/Makefile @@ -0,0 +1,271 @@ +# Makefile for HaxServ +# +# Written by: Test_User <hax@andrewyu.org> +# +# This is free and unencumbered software released into the public +# domain. +# +# Anyone is free to copy, modify, publish, use, compile, sell, or +# distribute this software, either in source code form or as a compiled +# binary, for any purpose, commercial or non-commercial, and by any +# means. +# +# In jurisdictions that recognize copyright laws, the author or authors +# of this software dedicate any and all copyright interest in the +# software to the public domain. We make this dedication for the benefit +# of the public at large and to the detriment of our heirs and +# successors. We intend this dedication to be an overt act of +# relinquishment in perpetuity of all present and future rights to this +# software under copyright law. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. + +INCLUDEFLAGS = + +CFLAGS += $(INCLUDEFLAGS) -D_REENTRANT -ggdb3 -Wall -Wextra -Wsign-conversion -Wno-unused-parameter -std=gnu99 + +LDFLAGS = -lpthread + +.makeopts: + > .makeopts + +include .makeopts + +rebuild = 0 + +# tabs not allowed :( +ifneq ($(PLAINTEXT_CLIENT),) +ifneq ($(PLAINTEXT_CLIENT),$(LAST_PLAINTEXT_CLIENT)) +rebuild = 1 +endif +else +PLAINTEXT_CLIENT = $(LAST_PLAINTEXT_CLIENT) +endif + +ifneq ($(PLAINTEXT_SERVER),) +ifneq ($(PLAINTEXT_SERVER),$(LAST_PLAINTEXT_SERVER)) +rebuild = 1 +endif +else +PLAINTEXT_SERVER = $(LAST_PLAINTEXT_SERVER) +endif + +ifneq ($(GNUTLS_CLIENT),) +ifneq ($(GNUTLS_CLIENT),$(LAST_GNUTLS_CLIENT)) +rebuild = 1 +endif +else +GNUTLS_CLIENT = $(LAST_GNUTLS_CLIENT) +endif + +ifneq ($(GNUTLS_SERVER),) +ifneq ($(GNUTLS_SERVER),$(LAST_GNUTLS_SERVER)) +rebuild = 1 +endif +else +GNUTLS_SERVER = $(LAST_GNUTLS_SERVER) +endif + +ifneq ($(OPENSSL_CLIENT),) +ifneq ($(OPENSSL_CLIENT),$(LAST_OPENSSL_CLIENT)) +rebuild = 1 +endif +else +OPENSSL_CLIENT = $(LAST_OPENSSL_CLIENT) +endif + +ifneq ($(OPENSSL_SERVER),) +ifneq ($(OPENSSL_SERVER),$(LAST_OPENSSL_SERVER)) +rebuild = 1 +endif +else +OPENSSL_SERVER = $(LAST_OPENSSL_SERVER) +endif + +ifneq ($(INSPIRCD2_PROTOCOL),) +ifneq ($(INSPIRCD2_PROTOCOL),$(LAST_INSPIRCD2_PROTOCOL)) +rebuild = 1 +endif +else +INSPIRCD2_PROTOCOL = $(LAST_INSPIRCD2_PROTOCOL) +endif + +ifneq ($(SAFE_STACK),) +ifneq ($(SAFE_STACK),$(LAST_SAFE_STACK)) +rebuild = 1 +endif +else +SAFE_STACK = $(LAST_SAFE_STACK) +endif + +ifneq ($(CFLAGS),) +ifneq ($(CFLAGS),$(LAST_CFLAGS)) +rebuild = 1 +endif +else +CFLAGS = $(LAST_CFLAGS) +endif + +ifneq ($(CC),) +ifneq ($(CC),$(LAST_CC)) +rebuild = 1 +endif +else +CC = $(LAST_CC) +endif + +ifeq ($(rebuild),1) +$(shell printf '%s\n' 'LAST_PLAINTEXT_CLIENT = $(PLAINTEXT_CLIENT)' > .makeopts) +$(shell printf '%s\n' 'LAST_PLAINTEXT_SERVER = $(PLAINTEXT_SERVER)' >> .makeopts) +$(shell printf '%s\n' 'LAST_GNUTLS_CLIENT = $(GNUTLS_CLIENT)' >> .makeopts) +$(shell printf '%s\n' 'LAST_GNUTLS_SERVER = $(GNUTLS_SERVER)' >> .makeopts) +$(shell printf '%s\n' 'LAST_OPENSSL_CLIENT = $(OPENSSL_CLIENT)' >> .makeopts) +$(shell printf '%s\n' 'LAST_OPENSSL_SERVER = $(OPENSSL_SERVER)' >> .makeopts) +$(shell printf '%s\n' 'LAST_INSPIRCD2_PROTOCOL = $(INSPIRCD2_PROTOCOL)' >> .makeopts) +$(shell printf '%s\n' 'LAST_SAFE_STACK = $(SAFE_STACK)' >> .makeopts) +$(shell printf '%s\n' 'LAST_CFLAGS = $(CFLAGS)' >> .makeopts) +$(shell printf '%s\n' 'LAST_CC = $(CC)' >> .makeopts) +endif + +USE_PLAINTEXT = 0 +USE_CLIENT = 0 +USE_GNUTLS = 0 +USE_SERVER = 0 + +ifeq ($(PLAINTEXT_CLIENT),1) +CFLAGS += -DUSE_PLAINTEXT_CLIENT +USE_CLIENT = 1 +USE_PLAINTEXT = 1 +endif + +ifeq ($(PLAINTEXT_SERVER),1) +CFLAGS += -DUSE_PLAINTEXT_SERVER +USE_SERVER = 1 +USE_PLAINTEXT = 1 +endif + +ifeq ($(GNUTLS_CLIENT),1) +CFLAGS += -DUSE_GNUTLS_CLIENT +USE_CLIENT = 1 +USE_GNUTLS = 1 +endif + +ifeq ($(GNUTLS_SERVER),1) +CFLAGS += -DUSE_GNUTLS_SERVER +USE_SERVER = 1 +USE_GNUTLS = 1 +endif + +ifeq ($(OPENSSL_CLIENT),1) +CFLAGS += -DUSE_OPENSSL_CLIENT +USE_CLIENT = 1 +USE_OPENSSL = 1 +endif + +ifeq ($(OPENSSL_SERVER),1) +CFLAGS += -DUSE_OPENSSL_SERVER +USE_SERVER = 1 +USE_OPENSSL = 1 +endif + + +OFILES = config.o general_network.o haxstring_utils.o main.o protocols.o table.o + +ifeq ($(USE_CLIENT),1) +OFILES += client_network.o +CFLAGS += -DUSE_CLIENT +endif + +ifeq ($(USE_SERVER),1) +OFILES += server_network.o +CFLAGS += -DUSE_SERVER +endif + +ifeq ($(USE_PLAINTEXT),1) +OFILES += plaintext_network.o +CFLAGS += -DUSE_PLAINTEXT +endif + +ifeq ($(USE_GNUTLS),1) +OFILES += gnutls_network.o +CFLAGS += -DUSE_GNUTLS $(shell pkg-config gnutls --cflags) +LDFLAGS += $(shell pkg-config gnutls --libs) +endif + +ifeq ($(USE_OPENSSL),1) +OFILES += openssl_network.o +CFLAGS += -DUSE_OPENSSL $(shell pkg-config openssl --cflags) +LDFLAGS += $(shell pkg-config openssl --libs) +endif + +ifeq ($(SAFE_STACK),1) +CFLAGS += -fstack-check +endif + + + +ifeq ($(INSPIRCD2_PROTOCOL),1) +ifneq ($(USE_SERVER),1) +$(error You must have some form of server transport layer enabled if you hope to use the inspircd2 protocol) +endif +OFILES += protocols/inspircd2.o +CFLAGS += -DUSE_INSPIRCD2_PROTOCOL +endif + + +DEPS = $(shell $(CC) $(CFLAGS) -M -MT $(1).o $(1).c | sed -z 's/\\\n //g') .makeopts Makefile + + +.PHONY: all clean +all: haxserv + +haxserv: $(OFILES) .makeopts Makefile + $(CC) $(OFILES) -o $@ $(LDFLAGS) + +%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ + +$(call DEPS,config) + +$(call DEPS,general_network) + +$(call DEPS,haxstring_utils) + +$(call DEPS,main) + +$(call DEPS,protocols) + +$(call DEPS,table) + +ifeq ($(USE_PLAINTEXT),1) +$(call DEPS,plaintext_network) +endif + +ifeq ($(USE_GNUTLS),1) +$(call DEPS,gnutls_network) +endif + +ifeq ($(USE_OPENSSL),1) +$(call DEPS,openssl_network) +endif + +ifeq ($(USE_CLIENT),1) +$(call DEPS,client_network) +endif + +ifeq ($(USE_SERVER),1) +$(call DEPS,server_network) +endif + +ifeq ($(INSPIRCD2_PROTOCOL),1) +$(call DEPS,protocols/inspircd2) +endif + +clean: + $(RM) -r haxserv *.o protocols/*.o diff --git a/config.h b/config.h new file mode 100644 index 0000000..d80357c --- /dev/null +++ b/config.h @@ -0,0 +1,78 @@ +// One of the headers for HaxServ +// +// Written by: Test_User <hax@andrewyu.org> +// +// This is free and unencumbered software released into the public +// domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. +// +// In jurisdictions that recognize copyright laws, the author or authors +// of this software dedicate any and all copyright interest in the +// software to the public domain. We make this dedication for the benefit +// of the public at large and to the detriment of our heirs and +// successors. We intend this dedication to be an overt act of +// relinquishment in perpetuity of all present and future rights to this +// software under copyright law. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#pragma once + +#include <time.h> + +#include "general_network.h" +#include "protocols.h" + +#ifdef USE_SERVER +struct server_config { + struct string name; // = STRING("hax.example.org"), + struct string sid; // = STRING("100"), + + struct string in_pass; // = STRING("blah blah blah"), + struct string out_pass; // = STRING("some other thing"), + + size_t protocol; // = HAXIRCD_PROTOCOL, + + char autoconnect; // = 1; + size_t autoconnect_type; // = NET_TYPE_GNUTLS, + + // autoconnect only + struct string address; // = "haxnet.org", + struct string port; // = "4321", +}; +extern struct server_config server_config[]; // = {{...}, ...}; +extern size_t server_config_len; // = sizeof(server_config)/sizeof(*server_config); +#endif + +extern struct string SID; // = STRING("200"); +extern struct string SERVER_NAME; // = STRING("me.example.org"); +extern struct string SERVER_FULLNAME; // = STRING("My random server"); + +extern time_t PING_INTERVAL; // = 60; + +#ifdef USE_GNUTLS +extern char GNUTLS_USE_SYSTEM_TRUST; // = 1; +extern char *GNUTLS_CERT_PATH; // = "/etc/keys/crt.pem" +extern char *GNUTLS_KEY_PATH; // = "/etc/keys/key.pem" +#endif + +#ifdef USE_OPENSSL +extern char OPENSSL_USE_SYSTEM_TRUST; // = 1; +extern char *OPENSSL_CERT_PATH; // = "/etc/keys/crt.pem" +extern char *OPENSSL_KEY_PATH; // = "/etc/keys/key.pem" +#endif + +#ifdef USE_SERVER +extern unsigned short SERVER_PORTS[NUM_NET_TYPES][NUM_PROTOCOLS]; // = 7000 +extern size_t SERVER_LISTEN[NUM_NET_TYPES][NUM_PROTOCOLS]; // = 16 +#endif diff --git a/general_network.c b/general_network.c new file mode 100644 index 0000000..f6375d9 --- /dev/null +++ b/general_network.c @@ -0,0 +1,138 @@ +// One of the code files for HaxServ +// +// Written by: Test_User <hax@andrewyu.org> +// +// This is free and unencumbered software released into the public +// domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. +// +// In jurisdictions that recognize copyright laws, the author or authors +// of this software dedicate any and all copyright interest in the +// software to the public domain. We make this dedication for the benefit +// of the public at large and to the detriment of our heirs and +// successors. We intend this dedication to be an overt act of +// relinquishment in perpetuity of all present and future rights to this +// software under copyright law. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#include <arpa/inet.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netdb.h> + +#include "general_network.h" + +#ifdef USE_PLAINTEXT +#include "plaintext_network.h" +#endif +#ifdef USE_GNUTLS +#include "gnutls_network.h" +#endif +#ifdef USE_OPENSSL +#include "openssl_network.h" +#endif + +char casemap[UCHAR_MAX+1] = { + ['a'] = 'A', + ['b'] = 'B', + ['c'] = 'C', + ['d'] = 'D', + ['e'] = 'E', + ['f'] = 'F', + ['g'] = 'G', + ['h'] = 'H', + ['i'] = 'I', + ['j'] = 'J', + ['k'] = 'K', + ['l'] = 'L', + ['m'] = 'M', + ['n'] = 'N', + ['o'] = 'O', + ['p'] = 'P', + ['q'] = 'Q', + ['r'] = 'R', + ['s'] = 'S', + ['t'] = 'Y', + ['u'] = 'U', + ['v'] = 'V', + ['w'] = 'W', + ['x'] = 'X', + ['y'] = 'Y', + ['z'] = 'Z', + ['{'] = '[', + ['}'] = ']', + ['|'] = '\\', + ['^'] = '~', +}; + +struct network networks[NUM_NET_TYPES] = { +#ifdef USE_PLAINTEXT + [NET_TYPE_PLAINTEXT] = { + .send = plaintext_send, + .recv = plaintext_recv, + .connect = plaintext_connect, + .accept = plaintext_accept, + .close = plaintext_close, + }, +#endif +#ifdef USE_GNUTLS + [NET_TYPE_GNUTLS] = { + .send = gnutls_send, + .recv = gnutls_recv, + .connect = gnutls_connect, + .accept = gnutls_accept, + .close = gnutls_close, + }, +#endif +#ifdef USE_OPENSSL + [NET_TYPE_OPENSSL] = { + .send = openssl_send, + .recv = openssl_recv, + .connect = openssl_connect, + .accept = openssl_accept, + .close = openssl_close, + }, +#endif +}; + +// TODO: Proper string handling +int resolve(struct string address, struct string port, struct sockaddr *sockaddr) { + int success; + struct addrinfo hints = { + .ai_family = AF_INET, + .ai_socktype = SOCK_STREAM, + .ai_protocol = IPPROTO_TCP, + .ai_flags = AI_NUMERICSERV | AI_ADDRCONFIG, + }; + struct addrinfo *info; + + success = getaddrinfo(address.data, port.data, &hints, &info); + + if (success == 0) { + *sockaddr = *(info->ai_addr); + freeaddrinfo(info); + } + + return success; +} + +int init_general_network(void) { + for (size_t i = 1; i < UCHAR_MAX + 1; i++) { + if (casemap[i] == 0) { + casemap[i] = i; + } + } + + return 0; +} diff --git a/general_network.h b/general_network.h new file mode 100644 index 0000000..cb3e9a7 --- /dev/null +++ b/general_network.h @@ -0,0 +1,72 @@ +// One of the headers for HaxServ +// +// Written by: Test_User <hax@andrewyu.org> +// +// This is free and unencumbered software released into the public +// domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. +// +// In jurisdictions that recognize copyright laws, the author or authors +// of this software dedicate any and all copyright interest in the +// software to the public domain. We make this dedication for the benefit +// of the public at large and to the detriment of our heirs and +// successors. We intend this dedication to be an overt act of +// relinquishment in perpetuity of all present and future rights to this +// software under copyright law. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#pragma once + +#include <limits.h> +#include <stddef.h> +#include <sys/socket.h> + +#include "haxstring.h" +#include "table.h" + +struct network { + int (*send)(void *handle, struct string msg); + size_t (*recv)(void *handle, char *data, size_t len, char *err); + + 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 (*close)(int fd, void *handle); +}; + +struct server_info { + struct string sid; + + struct table user_list; +}; + +int resolve(struct string address, struct string port, struct sockaddr *sockaddr); + +int init_general_network(void); + +extern char casemap[UCHAR_MAX+1]; +#define CASEMAP(x) (casemap[(unsigned char)x]) + +#ifdef USE_PLAINTEXT +#define NET_TYPE_PLAINTEXT 0 +#endif +#ifdef USE_GNUTLS +#define NET_TYPE_GNUTLS 1 +#endif +#ifdef USE_OPENSSL +#define NET_TYPE_OPENSSL 2 +#endif + +#define NUM_NET_TYPES 3 +extern struct network networks[NUM_NET_TYPES]; diff --git a/gnutls_network.c b/gnutls_network.c new file mode 100644 index 0000000..5105ce1 --- /dev/null +++ b/gnutls_network.c @@ -0,0 +1,234 @@ +// One of the code files for HaxServ +// +// Written by: Test_User <hax@andrewyu.org> +// +// This is free and unencumbered software released into the public +// domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. +// +// In jurisdictions that recognize copyright laws, the author or authors +// of this software dedicate any and all copyright interest in the +// software to the public domain. We make this dedication for the benefit +// of the public at large and to the detriment of our heirs and +// successors. We intend this dedication to be an overt act of +// relinquishment in perpetuity of all present and future rights to this +// software under copyright law. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#include <arpa/inet.h> +#include <errno.h> +#include <gnutls/gnutls.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <unistd.h> + +#include "config.h" +#include "general_network.h" +#include "gnutls_network.h" + +gnutls_certificate_credentials_t gnutls_cert_creds; + +int init_gnutls_network(void) { + if (gnutls_global_init() < 0) + return 1; + + if (gnutls_certificate_allocate_credentials(&gnutls_cert_creds) != GNUTLS_E_SUCCESS) + return 2; + + if (GNUTLS_USE_SYSTEM_TRUST && (gnutls_certificate_set_x509_system_trust(gnutls_cert_creds) < 0)) + return 3; + + if (gnutls_certificate_set_x509_key_file(gnutls_cert_creds, GNUTLS_CERT_PATH, GNUTLS_KEY_PATH, GNUTLS_X509_FMT_PEM) < 0) + return 4; + + 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); + + if (res < 0 || (size_t)res > msg.len) { // res > len shouldn't be possible, but is still an error + return 1; + } else if (res > 0) { + msg.len -= (size_t)res; + msg.data += (size_t)res; + } + } while (msg.len > 0); + + return 0; +} + +size_t gnutls_recv(void *session, char *data, size_t len, char *err) { + ssize_t res; + do { + res = gnutls_record_recv(*((gnutls_session_t*)session), data, len); + } while (res < 0 && (res == -GNUTLS_E_INTERRUPTED || res == -GNUTLS_E_AGAIN)); + + if (res < 0) { + if (res == -GNUTLS_E_TIMEDOUT) { + *err = 1; + } else { + *err = 3; + } + return 0; + } else if (res == 0) { + *err = 2; + return 0; + } + *err = 0; + + return (size_t)res; +} + +int gnutls_connect(void **handle, struct string address, struct string port, struct string *addr_out) { + struct sockaddr sockaddr; + if (resolve(address, port, &sockaddr) != 0) + return -1; + + int fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (fd == -1) + return -1; + + { + struct timeval timeout = { + .tv_sec = PING_INTERVAL, + .tv_usec = 0, + }; + + setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); + } + + int res; + do { + res = connect(fd, &sockaddr, sizeof(sockaddr)); + } while (res < 0 && errno == EINTR); + if (res < 0) + goto gnutls_connect_close; + + gnutls_session_t *session; + session = malloc(sizeof(*session)); + if (session == 0) + goto gnutls_connect_close; + *handle = session; + + if (gnutls_init(session, GNUTLS_CLIENT) != GNUTLS_E_SUCCESS) + goto gnutls_connect_free_session; + + if (gnutls_server_name_set(*session, GNUTLS_NAME_DNS, address.data, address.len) != GNUTLS_E_SUCCESS) + goto gnutls_connect_deinit_session; + + if (gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE, gnutls_cert_creds) != GNUTLS_E_SUCCESS) + goto gnutls_connect_deinit_session; + + if (gnutls_set_default_priority(*session) != GNUTLS_E_SUCCESS) + goto gnutls_connect_deinit_session; + + gnutls_transport_set_int(*session, fd); + + gnutls_handshake_set_timeout(*session, PING_INTERVAL * 1000); + gnutls_record_set_timeout(*session, PING_INTERVAL * 1000); + + do { + res = gnutls_handshake(*session); + } while (res == -GNUTLS_E_INTERRUPTED || res == -GNUTLS_E_AGAIN); + if (res < 0) + goto gnutls_connect_deinit_session; + + addr_out->data = malloc(sizeof(sockaddr)); + if (!addr_out->data) + goto gnutls_connect_deinit_session; + + memcpy(addr_out->data, &sockaddr, sizeof(sockaddr)); + addr_out->len = sizeof(sockaddr); + + return fd; + + gnutls_connect_deinit_session: + gnutls_deinit(*session); + gnutls_connect_free_session: + free(session); + gnutls_connect_close: + close(fd); + return -1; +} + +int gnutls_accept(int listen_fd, void **handle, struct string *addr) { + struct sockaddr address; + socklen_t address_len = sizeof(address); + + int con_fd; + do { + con_fd = accept(listen_fd, &address, &address_len); + } while (con_fd == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK || errno == ENETDOWN || errno == EPROTO || errno == ENOPROTOOPT || errno == EHOSTDOWN || errno == ENONET || errno == EHOSTUNREACH || errno == EOPNOTSUPP || errno == ENETUNREACH)); + + if (con_fd == -1) + return -1; + + addr->data = malloc(address_len); + if (addr->data == 0 && address_len != 0) + goto gnutls_accept_close; + + memcpy(addr->data, &address, address_len); + addr->len = address_len; + + gnutls_session_t *session; + session = malloc(sizeof(*session)); + if (!session) + goto gnutls_accept_free_addr_data; + *handle = session; + + if (gnutls_init(session, GNUTLS_SERVER) != GNUTLS_E_SUCCESS) + goto gnutls_accept_free_session; + + if (gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE, gnutls_cert_creds) != GNUTLS_E_SUCCESS) + goto gnutls_accept_deinit_session; + + if (gnutls_set_default_priority(*session) != GNUTLS_E_SUCCESS) + goto gnutls_accept_deinit_session; + + gnutls_transport_set_int(*session, con_fd); + + gnutls_handshake_set_timeout(*session, PING_INTERVAL * 1000); + gnutls_record_set_timeout(*session, PING_INTERVAL * 1000); + + int res; + do { + res = gnutls_handshake(*session); + } while (res == -GNUTLS_E_INTERRUPTED || res == -GNUTLS_E_AGAIN); + if (res != GNUTLS_E_SUCCESS) + goto gnutls_accept_deinit_session; + + return con_fd; + + gnutls_accept_deinit_session: + gnutls_deinit(*session); + gnutls_accept_free_session: + free(session); + gnutls_accept_free_addr_data: + free(addr->data); + gnutls_accept_close: + close(con_fd); + return -1; +} + +void gnutls_close(int fd, void *handle) { + gnutls_deinit(*((gnutls_session_t*)handle)); + free(handle); + close(fd); +} diff --git a/gnutls_network.h b/gnutls_network.h new file mode 100644 index 0000000..c70f2e3 --- /dev/null +++ b/gnutls_network.h @@ -0,0 +1,44 @@ +// One of the headers for HaxServ +// +// Written by: Test_User <hax@andrewyu.org> +// +// This is free and unencumbered software released into the public +// domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. +// +// In jurisdictions that recognize copyright laws, the author or authors +// of this software dedicate any and all copyright interest in the +// software to the public domain. We make this dedication for the benefit +// of the public at large and to the detriment of our heirs and +// successors. We intend this dedication to be an overt act of +// relinquishment in perpetuity of all present and future rights to this +// software under copyright law. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#pragma once + +#include <stddef.h> + +#include "haxstring.h" +#include "general_network.h" + +int init_gnutls_network(void); + +int gnutls_send(void *fd, struct string msg); +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_close(int fd, void *handle); diff --git a/haxstring.h b/haxstring.h new file mode 100644 index 0000000..f78c343 --- /dev/null +++ b/haxstring.h @@ -0,0 +1,43 @@ +// Hax's strings +// +// Written by: Test_User <hax@andrewyu.org> +// +// This is free and unencumbered software released into the public +// domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. +// +// In jurisdictions that recognize copyright laws, the author or authors +// of this software dedicate any and all copyright interest in the +// software to the public domain. We make this dedication for the benefit +// of the public at large and to the detriment of our heirs and +// successors. We intend this dedication to be an overt act of +// relinquishment in perpetuity of all present and future rights to this +// software under copyright law. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#pragma once + +#include <stddef.h> + +struct string { + char *data; + size_t len; +}; + +#define STRING(x) (struct string){x, sizeof(x)-1} +#define NULSTR(x) (struct string){x, strlen(x)} + +#define STRING_EQ(x, y) (x.len == y.len && memcmp(x.data, y.data, x.len) == 0) + +#define WRITES(x, y) write(x, y.data, y.len) diff --git a/haxstring_utils.c b/haxstring_utils.c new file mode 100644 index 0000000..2fed747 --- /dev/null +++ b/haxstring_utils.c @@ -0,0 +1,75 @@ +// Hax's string utils +// +// Written by: Test_User <hax@andrewyu.org> +// +// This is free and unencumbered software released into the public +// domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. +// +// In jurisdictions that recognize copyright laws, the author or authors +// of this software dedicate any and all copyright interest in the +// software to the public domain. We make this dedication for the benefit +// of the public at large and to the detriment of our heirs and +// successors. We intend this dedication to be an overt act of +// relinquishment in perpetuity of all present and future rights to this +// software under copyright law. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#include <stddef.h> + +#include "haxstring.h" +#include "haxstring_utils.h" + +size_t str_to_unsigned(struct string str, char *err) { + if (str.len == 0) { + *err = 1; + return 0; + } + + size_t val = 0; + while (str.len > 0) { + switch(str.data[0]) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (val > ((size_t)-1)/10) { + *err = 1; + return 0; + } + val *= 10; + if (val > (-((size_t)((unsigned char)str.data[0] - 0x30) + 1))) { + *err = 1; + return 0; + } + val += (unsigned char)str.data[0] - 0x30; + break; + default: + *err = 1; + return 0; + } + + str.data++; + str.len--; + } + + *err = 0; + return val; +} diff --git a/haxstring_utils.h b/haxstring_utils.h new file mode 100644 index 0000000..5023141 --- /dev/null +++ b/haxstring_utils.h @@ -0,0 +1,34 @@ +// Header for hax's string utils +// +// Written by: Test_User <hax@andrewyu.org> +// +// This is free and unencumbered software released into the public +// domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. +// +// In jurisdictions that recognize copyright laws, the author or authors +// of this software dedicate any and all copyright interest in the +// software to the public domain. We make this dedication for the benefit +// of the public at large and to the detriment of our heirs and +// successors. We intend this dedication to be an overt act of +// relinquishment in perpetuity of all present and future rights to this +// software under copyright law. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#pragma once + +#include <stddef.h> +#include "haxstring.h" + +size_t str_to_unsigned(struct string str, char *err); @@ -0,0 +1,125 @@ +// "Main" file for haxserv +// +// Written by: Test_User <hax@andrewyu.org> +// +// This is free and unencumbered software released into the public +// domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. +// +// In jurisdictions that recognize copyright laws, the author or authors +// of this software dedicate any and all copyright interest in the +// software to the public domain. We make this dedication for the benefit +// of the public at large and to the detriment of our heirs and +// successors. We intend this dedication to be an overt act of +// relinquishment in perpetuity of all present and future rights to this +// software under copyright law. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#include <signal.h> +#include <pthread.h> + +#include "config.h" +#include "general_network.h" +#include "main.h" + +#ifdef USE_PLAINTEXT +#include "plaintext_network.h" +#endif +#ifdef USE_GNUTLS +#include "gnutls_network.h" +#endif +#ifdef USE_OPENSSL +#include "openssl_network.h" +#endif + +#ifdef USE_SERVER +#include "server_network.h" +#endif +#ifdef USE_CLIENT +#include "client_network.h" +#endif + +#ifdef USE_INSPIRCD2_PROTOCOL +#include "protocols/inspircd2.h" +#endif + +pthread_attr_t pthread_attr; +pthread_mutexattr_t pthread_mutexattr; + +pthread_mutex_t state_lock = PTHREAD_MUTEX_INITIALIZER; + +int main(void) { + if (init_general_network() != 0) + return 1; + +#ifdef USE_SERVER + if (init_server_network() != 0) + return 1; +#endif + +#ifdef USE_CLIENT + if (init_client_network() != 0) + return 1; +#endif + +#ifdef USE_PLAINTEXT + if (init_plaintext_network() != 0) // there's not really anything to do ahead of time with plain tcp networking, this is just here for consistency (and will probably be optimized out by the compiler) + return 1; +#endif + +#ifdef USE_GNUTLS + if (init_gnutls_network() != 0) + return 1; +#endif + +#ifdef USE_OPENSSL + if (init_openssl_network() != 0) + return 1; +#endif + +#ifdef USE_INSPIRCD2_PROTOCOL + if (init_inspircd2_protocol() != 0) + return 1; +#endif + + { + struct sigaction tmp = { + .sa_handler = SIG_IGN, + }; + sigaction(SIGPIPE, &tmp, 0); + } + + if (pthread_attr_init(&pthread_attr) != 0) + return 1; + + if (pthread_mutexattr_init(&pthread_mutexattr) != 0) + return 1; + + if (pthread_attr_setdetachstate(&pthread_attr, PTHREAD_CREATE_DETACHED) != 0) // shouldn't actually happen + return 1; + +#ifdef USE_CLIENT + if (start_client_network() != 0) + return 1; +#endif + +#ifdef USE_SERVER + if (start_server_network() != 0) + return 1; +#endif + + pthread_exit(0); + + return 0; +} @@ -0,0 +1,34 @@ +// Written by: Test_User <hax@andrewyu.org> +// +// This is free and unencumbered software released into the public +// domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. +// +// In jurisdictions that recognize copyright laws, the author or authors +// of this software dedicate any and all copyright interest in the +// software to the public domain. We make this dedication for the benefit +// of the public at large and to the detriment of our heirs and +// successors. We intend this dedication to be an overt act of +// relinquishment in perpetuity of all present and future rights to this +// software under copyright law. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#pragma once + +extern pthread_attr_t pthread_attr; +extern pthread_mutexattr_t pthread_mutexattr; + +extern pthread_mutex_t state_lock; + +int main(void); diff --git a/openssl_network.c b/openssl_network.c new file mode 100644 index 0000000..60b2189 --- /dev/null +++ b/openssl_network.c @@ -0,0 +1,379 @@ +// One of the code files for HaxServ +// +// Written by: Test_User <hax@andrewyu.org> +// +// This is free and unencumbered software released into the public +// domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. +// +// In jurisdictions that recognize copyright laws, the author or authors +// of this software dedicate any and all copyright interest in the +// software to the public domain. We make this dedication for the benefit +// of the public at large and to the detriment of our heirs and +// successors. We intend this dedication to be an overt act of +// relinquishment in perpetuity of all present and future rights to this +// software under copyright law. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#include <arpa/inet.h> +#include <errno.h> +#include <fcntl.h> +#include <openssl/ssl.h> +#include <openssl/tls1.h> +#include <poll.h> +#include <pthread.h> +#include <unistd.h> + +#include "config.h" +#include "main.h" +#include "openssl_network.h" + +struct openssl_handle { + SSL *ssl; + pthread_mutex_t mutex; + int fd; +}; + +SSL_CTX *openssl_ctx; + +int init_openssl_network(void) { + SSL_library_init(); + + openssl_ctx = SSL_CTX_new(TLS_method()); + if (SSL_CTX_use_certificate_file(openssl_ctx, OPENSSL_CERT_PATH, SSL_FILETYPE_PEM) != 1) + return 1; + if (SSL_CTX_use_PrivateKey_file(openssl_ctx, OPENSSL_KEY_PATH, SSL_FILETYPE_PEM) != 1) + return 1; + + if (OPENSSL_USE_SYSTEM_TRUST) { + if (SSL_CTX_set_default_verify_paths(openssl_ctx) != 1) { + return 1; + } + } + + return 0; +} + +int openssl_send(void *handle, struct string msg) { + struct openssl_handle *openssl_handle = handle; + + pthread_mutex_lock(&(openssl_handle->mutex)); + + struct pollfd pollfd = { + .fd = openssl_handle->fd, + }; + int res; + do { + res = SSL_write(openssl_handle->ssl, msg.data, msg.len); + if (res <= 0) { + switch(SSL_get_error(openssl_handle->ssl, res)) { + case SSL_ERROR_WANT_READ: + pollfd.events = POLLIN; + break; + case SSL_ERROR_WANT_WRITE: + pollfd.events = POLLOUT; + break; + default: + goto openssl_send_error_unlock; + } + } else { + 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 + goto openssl_send_error_unlock; + if ((pollfd.revents & (POLLIN | POLLOUT)) == 0) // Only errors returned + goto openssl_send_error_unlock; + } while (1); + + pthread_mutex_unlock(&(openssl_handle->mutex)); + return 0; + + openssl_send_error_unlock: + pthread_mutex_unlock(&(openssl_handle->mutex)); + return 1; +} + +size_t openssl_recv(void *handle, char *data, size_t len, char *err) { + struct openssl_handle *openssl_handle = handle; + + struct pollfd pollfd = { + .fd = openssl_handle->fd, + }; + int res; + do { + pthread_mutex_lock(&(openssl_handle->mutex)); + res = SSL_read(openssl_handle->ssl, data, len); + pthread_mutex_unlock(&(openssl_handle->mutex)); + if (res <= 0) { + switch(SSL_get_error(openssl_handle->ssl, res)) { + case SSL_ERROR_WANT_READ: + pollfd.events = POLLIN; + break; + case SSL_ERROR_WANT_WRITE: + pollfd.events = POLLOUT; + break; + default: + *err = 3; + return 0; + } + } else { + break; + } + + res = poll(&pollfd, 1, PING_INTERVAL*1000); + if (res == 0) { // Timeout + *err = 1; + return 0; + } + if (res == -1) { + if (errno != EINTR) { + continue; + } else { + *err = 3; + return 0; + } + } + if ((pollfd.revents & (POLLIN | POLLOUT)) == 0) { // Only errors returned + if (pollfd.revents & POLLHUP) { + *err = 2; + } else { + *err = 3; + } + + return 0; + } + } while (1); + + *err = 0; + return (size_t)res; +} + +int openssl_connect(void **handle, struct string address, struct string port, struct string *addr_out) { + struct sockaddr sockaddr; + if (resolve(address, port, &sockaddr) != 0) + return -1; + + int fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (fd == -1) + return -1; + + { + struct timeval timeout = { + .tv_sec = PING_INTERVAL, + .tv_usec = 0, + }; + + setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); + } + + int res; + do { + res = connect(fd, &sockaddr, sizeof(sockaddr)); + } while (res < 0 && errno == EINTR); + if (res < 0) + goto openssl_connect_close; + + int flags = fcntl(fd, F_GETFL); + if (flags == -1) + goto openssl_connect_close; + if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) + goto openssl_connect_close; + + addr_out->data = malloc(sizeof(sockaddr)); + if (!addr_out->data) + goto openssl_connect_close; + memcpy(addr_out->data, &sockaddr, sizeof(sockaddr)); + addr_out->len = sizeof(sockaddr); + + struct openssl_handle *openssl_handle; + openssl_handle = malloc(sizeof(*openssl_handle)); + if (!openssl_handle) + goto openssl_connect_free_addr_data; + *handle = openssl_handle; + + openssl_handle->fd = fd; + + openssl_handle->ssl = SSL_new(openssl_ctx); + if (!openssl_handle->ssl) + goto openssl_connect_free_openssl_handle; + SSL_set_fd(openssl_handle->ssl, fd); + + res = pthread_mutex_init(&(openssl_handle->mutex), &(pthread_mutexattr)); + if (res != 0) + goto openssl_connect_free_ssl; + + struct pollfd pollfd = { + .fd = fd, + }; + do { + res = SSL_connect(openssl_handle->ssl); + if (res == 0) + goto openssl_connect_destroy_mutex; + if (res < 0) { + switch(SSL_get_error(openssl_handle->ssl, res)) { + case SSL_ERROR_WANT_READ: + pollfd.events = POLLIN; + break; + case SSL_ERROR_WANT_WRITE: + pollfd.events = POLLOUT; + break; + default: + goto openssl_connect_destroy_mutex; + } + } else { + break; + } + + res = poll(&pollfd, 1, PING_INTERVAL*1000); + if (res == 0) // Timeout + goto openssl_connect_destroy_mutex; + if (res == -1) { + if (errno != EINTR) { + continue; + } else { + goto openssl_connect_destroy_mutex; + } + } + if ((pollfd.revents & (POLLIN | POLLOUT)) == 0) // Only errors returned + goto openssl_connect_destroy_mutex; + } while (1); + + return fd; + + openssl_connect_destroy_mutex: + pthread_mutex_destroy(&(openssl_handle->mutex)); + openssl_connect_free_ssl: + SSL_free(openssl_handle->ssl); + openssl_connect_free_openssl_handle: + free(openssl_handle); + openssl_connect_free_addr_data: + free(addr_out->data); + openssl_connect_close: + close(fd); + + return -1; +} + +int openssl_accept(int listen_fd, void **handle, struct string *addr) { + struct sockaddr address; + socklen_t address_len = sizeof(address); + + int con_fd; + do { + con_fd = accept(listen_fd, &address, &address_len); + } while (con_fd == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK || errno == ENETDOWN || errno == EPROTO || errno == ENOPROTOOPT || errno == EHOSTDOWN || errno == ENONET || errno == EHOSTUNREACH || errno == EOPNOTSUPP || errno == ENETUNREACH)); + + if (con_fd == -1) + return -1; + + int flags = fcntl(con_fd, F_GETFL); + if (flags == -1) + goto openssl_accept_close; + if (fcntl(con_fd, F_SETFL, flags | O_NONBLOCK) == -1) + goto openssl_accept_close; + + addr->data = malloc(address_len); + if (addr->data == 0 && address_len != 0) + goto openssl_accept_close; + + memcpy(addr->data, &address, address_len); + addr->len = address_len; + + struct openssl_handle *openssl_handle; + openssl_handle = malloc(sizeof(*openssl_handle)); + if (!openssl_handle) + goto openssl_accept_free_addr_data; + + *handle = openssl_handle; + + openssl_handle->fd = con_fd; + + openssl_handle->ssl = SSL_new(openssl_ctx); + if (!openssl_handle->ssl) + goto openssl_accept_free_openssl_handle; + + SSL_set_fd(openssl_handle->ssl, con_fd); + + int res = pthread_mutex_init(&(openssl_handle->mutex), &(pthread_mutexattr)); + if (res != 0) + goto openssl_accept_free_ssl; + + struct pollfd pollfd = { + .fd = con_fd, + }; + do { + res = SSL_accept(openssl_handle->ssl); + if (res == 0) + goto openssl_accept_destroy_mutex; + if (res < 0) { + switch(SSL_get_error(openssl_handle->ssl, res)) { + case SSL_ERROR_WANT_READ: + pollfd.events = POLLIN; + break; + case SSL_ERROR_WANT_WRITE: + pollfd.events = POLLOUT; + break; + default: + goto openssl_accept_destroy_mutex; + } + } else { + break; + } + + res = poll(&pollfd, 1, PING_INTERVAL*1000); + if (res == 0) // Timeout + goto openssl_accept_destroy_mutex; + if (res == -1) { + if (errno != EINTR) { + continue; + } else { + goto openssl_accept_destroy_mutex; + } + } + if ((pollfd.revents & (POLLIN | POLLOUT)) == 0) // Only errors returned + goto openssl_accept_destroy_mutex; + } while (1); + + return con_fd; + + openssl_accept_destroy_mutex: + pthread_mutex_destroy(&(openssl_handle->mutex)); + openssl_accept_free_ssl: + SSL_free(openssl_handle->ssl); + openssl_accept_free_openssl_handle: + free(openssl_handle); + openssl_accept_free_addr_data: + free(addr->data); + openssl_accept_close: + close(con_fd); + + return -1; +} + +void openssl_close(int fd, void *handle) { + struct openssl_handle *openssl_handle = handle; + pthread_mutex_destroy(&(openssl_handle->mutex)); + SSL_free(openssl_handle->ssl); + free(openssl_handle); + close(fd); +} diff --git a/openssl_network.h b/openssl_network.h new file mode 100644 index 0000000..83f0432 --- /dev/null +++ b/openssl_network.h @@ -0,0 +1,44 @@ +// One of the headers for HaxServ +// +// Written by: Test_User <hax@andrewyu.org> +// +// This is free and unencumbered software released into the public +// domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. +// +// In jurisdictions that recognize copyright laws, the author or authors +// of this software dedicate any and all copyright interest in the +// software to the public domain. We make this dedication for the benefit +// of the public at large and to the detriment of our heirs and +// successors. We intend this dedication to be an overt act of +// relinquishment in perpetuity of all present and future rights to this +// software under copyright law. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#pragma once + +#include <stddef.h> + +#include "haxstring.h" +#include "general_network.h" + +int init_openssl_network(void); + +int openssl_send(void *handle, struct string msg); +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_close(int fd, void *handle); diff --git a/plaintext_network.c b/plaintext_network.c new file mode 100644 index 0000000..ce040ce --- /dev/null +++ b/plaintext_network.c @@ -0,0 +1,168 @@ +// One of the code files for HaxServ +// +// Written by: Test_User <hax@andrewyu.org> +// +// This is free and unencumbered software released into the public +// domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. +// +// In jurisdictions that recognize copyright laws, the author or authors +// of this software dedicate any and all copyright interest in the +// software to the public domain. We make this dedication for the benefit +// of the public at large and to the detriment of our heirs and +// successors. We intend this dedication to be an overt act of +// relinquishment in perpetuity of all present and future rights to this +// software under copyright law. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#include <arpa/inet.h> +#include <errno.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <unistd.h> + +#include "config.h" +#include "general_network.h" +#include "haxstring.h" +#include "plaintext_network.h" + +int init_plaintext_network(void) { + return 0; +} + +int plaintext_send(void *fd, struct string msg) { + do { + ssize_t res; + do { + res = send(*((int*)fd), msg.data, msg.len, 0); + } while (res == -1 && (errno == EINTR)); + + if (res < 0 || (size_t)res > msg.len) { // res > len shouldn't be possible, but is still an error + return 1; + } else if (res > 0) { + msg.len -= (size_t)res; + msg.data += (size_t)res; + } + } while (msg.len > 0); + + return 0; +} + +size_t plaintext_recv(void *fd, char *data, size_t len, char *err) { + ssize_t res; + do { + res = recv(*((int*)fd), data, len, 0); + } while (res == -1 && (errno == EINTR)); + + if (res == -1) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { + *err = 1; + } else { + *err = 3; + } + return 0; + } else if (res == 0) { + *err = 2; + return 0; + } + *err = 0; + + return (size_t)res; +} + +int plaintext_connect(void **handle, struct string address, struct string port, struct string *addr_out) { + struct sockaddr sockaddr; + if (resolve(address, port, &sockaddr) != 0) + return -1; + + int fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (fd == -1) + return -1; + + { + struct timeval timeout = { + .tv_sec = PING_INTERVAL, + .tv_usec = 0, + }; + + setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); + } + + int res; + do { + res = connect(fd, &sockaddr, sizeof(sockaddr)); + } while (res < 0 && errno == EINTR); + if (res < 0) { + close(fd); + return -1; + } + + *handle = malloc(sizeof(fd)); + if (!handle) { + close(fd); + return -1; + } + *((int*)*handle) = fd; + + addr_out->data = malloc(sizeof(sockaddr)); + if (!addr_out->data) { + free(handle); + close(fd); + return -1; + } + memcpy(addr_out->data, &sockaddr, sizeof(sockaddr)); + addr_out->len = sizeof(sockaddr); + + return fd; +} + +int plaintext_accept(int listen_fd, void **handle, struct string *addr) { + struct sockaddr address; + socklen_t address_len = sizeof(address); + + int con_fd; + do { + con_fd = accept(listen_fd, &address, &address_len); + } while (con_fd == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK || errno == ENETDOWN || errno == EPROTO || errno == ENOPROTOOPT || errno == EHOSTDOWN || errno == ENONET || errno == EHOSTUNREACH || errno == EOPNOTSUPP || errno == ENETUNREACH)); + + if (con_fd == -1) + return -1; + + addr->data = malloc(address_len); + if (addr->data == 0 && address_len != 0) { + close(con_fd); + return -1; + } + + memcpy(addr->data, &address, address_len); + addr->len = address_len; + + *handle = malloc(sizeof(con_fd)); + if (!handle) { + free(addr->data); + close(con_fd); + return -1; + } + *((int*)*handle) = con_fd; + + return con_fd; +} + +void plaintext_close(int fd, void *handle) { + free(handle); + close(fd); +} diff --git a/plaintext_network.h b/plaintext_network.h new file mode 100644 index 0000000..e30e5ca --- /dev/null +++ b/plaintext_network.h @@ -0,0 +1,44 @@ +// One of the headers for HaxServ +// +// Written by: Test_User <hax@andrewyu.org> +// +// This is free and unencumbered software released into the public +// domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. +// +// In jurisdictions that recognize copyright laws, the author or authors +// of this software dedicate any and all copyright interest in the +// software to the public domain. We make this dedication for the benefit +// of the public at large and to the detriment of our heirs and +// successors. We intend this dedication to be an overt act of +// relinquishment in perpetuity of all present and future rights to this +// software under copyright law. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#pragma once + +#include <stddef.h> + +#include "haxstring.h" +#include "general_network.h" + +int init_plaintext_network(void); + +int plaintext_send(void *fd, struct string msg); +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_close(int fd, void *handle); diff --git a/protocols.c b/protocols.c new file mode 100644 index 0000000..eb1e6f4 --- /dev/null +++ b/protocols.c @@ -0,0 +1,42 @@ +// One of the code files for HaxServ +// +// Written by: Test_User <hax@andrewyu.org> +// +// This is free and unencumbered software released into the public +// domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. +// +// In jurisdictions that recognize copyright laws, the author or authors +// of this software dedicate any and all copyright interest in the +// software to the public domain. We make this dedication for the benefit +// of the public at large and to the detriment of our heirs and +// successors. We intend this dedication to be an overt act of +// relinquishment in perpetuity of all present and future rights to this +// software under copyright law. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#include "protocols.h" + +#ifdef USE_INSPIRCD2_PROTOCOL +#include "protocols/inspircd2.h" +#endif + +struct protocol protocols[NUM_PROTOCOLS] = { +#ifdef USE_INSPIRCD2_PROTOCOL + [INSPIRCD2_PROTOCOL] = { + .handle_connection = inspircd2_protocol_handle_connection, + .autoconnect = inspircd2_protocol_autoconnect, + }, +#endif +}; diff --git a/protocols.h b/protocols.h new file mode 100644 index 0000000..ae06ebf --- /dev/null +++ b/protocols.h @@ -0,0 +1,43 @@ +// Written by: Test_User <hax@andrewyu.org> +// +// This is free and unencumbered software released into the public +// domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. +// +// In jurisdictions that recognize copyright laws, the author or authors +// of this software dedicate any and all copyright interest in the +// software to the public domain. We make this dedication for the benefit +// of the public at large and to the detriment of our heirs and +// successors. We intend this dedication to be an overt act of +// relinquishment in perpetuity of all present and future rights to this +// software under copyright law. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#pragma once + +struct protocol { + void * (*handle_connection)(void *info); + void * (*autoconnect)(void *config); +}; + +#ifdef USE_HAXIRCD_PROTOCOL +#define HAXIRCD_PROTOCOL 0 +#endif +#ifdef USE_INSPIRCD2_PROTOCOL +#define INSPIRCD2_PROTOCOL 1 +#endif + +#define NUM_PROTOCOLS 2 + +extern struct protocol protocols[NUM_PROTOCOLS]; diff --git a/protocols/inspircd2.c b/protocols/inspircd2.c new file mode 100644 index 0000000..4bb79c8 --- /dev/null +++ b/protocols/inspircd2.c @@ -0,0 +1,341 @@ +// One of the code files for HaxServ +// +// Written by: Test_User <hax@andrewyu.org> +// +// This is free and unencumbered software released into the public +// domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. +// +// In jurisdictions that recognize copyright laws, the author or authors +// of this software dedicate any and all copyright interest in the +// software to the public domain. We make this dedication for the benefit +// of the public at large and to the detriment of our heirs and +// successors. We intend this dedication to be an overt act of +// relinquishment in perpetuity of all present and future rights to this +// software under copyright law. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#include <pthread.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "../config.h" +#include "../general_network.h" +#include "../haxstring.h" +#include "../main.h" +#include "../server_network.h" +#include "inspircd2.h" + +struct table inspircd2_protocol_init_commands = {0}; +struct table inspircd2_protocol_commands = {0}; + +int init_inspircd2_protocol(void) { + inspircd2_protocol_commands.array = malloc(0); + + 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); + + return 0; +} + +void * inspircd2_protocol_handle_connection(void *type) { + struct string address; + size_t net; + char is_incoming; + int fd; + void *handle; + struct server_config *config; + + char ready = 0; + + { + struct server_connection_info *t = type; + address = t->address; + fd = t->fd; + handle = t->handle; + config = t->config; + net = t->type->net_type; + is_incoming = t->type->is_incoming; + if (is_incoming) + free(type); + } + + struct string full_msg = {.data = malloc(0), .len = 0}; // TODO: move this down below after incoming connections are handled + + if (is_incoming) { + WRITES(2, STRING("InspIRCd v2 protocol handling does not yet support incoming connections!\r\n")); + goto inspircd2_protocol_handle_connection_close; + } else { + networks[net].send(handle, STRING("CAPAB START 1202\nCAPAB END\n")); + + networks[net].send(handle, STRING("SERVER ")); + networks[net].send(handle, SERVER_NAME); + networks[net].send(handle, STRING(" ")); + networks[net].send(handle, config->out_pass); + networks[net].send(handle, STRING(" 0 ")); + networks[net].send(handle, SID); + networks[net].send(handle, STRING(" :")); + networks[net].send(handle, SERVER_FULLNAME); + networks[net].send(handle, STRING("\n")); + } + + while (1) { + size_t msg_len; + size_t old_len; + { + char data[512]; + unsigned char timeout = 0; + size_t new_len; + while (1) { + char err; + new_len = networks[net].recv(handle, data, sizeof(data), &err); + if (err >= 2) { // Connection closed, or some uncorrected error + goto inspircd2_protocol_handle_connection_close; + } else if (err == 1) { // Timed out + if (timeout > 0) + goto inspircd2_protocol_handle_connection_close; + timeout++; + // TODO: Ping the server + } else { + break; + } + } + old_len = full_msg.len; + full_msg.len += new_len; + void *tmp = realloc(full_msg.data, full_msg.len); + if (!tmp && full_msg.len + new_len != 0) + goto inspircd2_protocol_handle_connection_close; + full_msg.data = tmp; + memcpy(full_msg.data + old_len, data, new_len); + } + + while (1) { + char found = 0; + for (size_t i = old_len; i < full_msg.len; i++) { + if (full_msg.data[i] == '\n') { + found = 1; + msg_len = i; + break; + } + } + if (!found) + break; + old_len = 0; + + struct string line = {.data = full_msg.data, .len = msg_len}; + + WRITES(2, STRING("[inspircd2] [server -> us] Got `")); + WRITES(2, line); + WRITES(2, STRING("'\r\n")); + + size_t offset = 0; + while (offset < msg_len && full_msg.data[offset] == ' ') + offset++; + + if (msg_len == offset) { + WRITES(2, STRING("Protocol violation: empty message.\r\n\n")); + goto inspircd2_protocol_handle_connection_close; + } + + struct string source; + if (full_msg.data[offset] == ':') { + source.data = full_msg.data + offset + 1; + found = 0; + source.len = 0; + for (size_t i = offset + 1; i < msg_len; i++) { + if (full_msg.data[i] == ' ') { + found = 1; + source.len = i - offset - 1; + offset = i + 1; + while (offset < msg_len && full_msg.data[offset] == ' ') + offset++; + break; + } + source.len++; + } + if (source.len == 0) { + WRITES(2, STRING("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")); + goto inspircd2_protocol_handle_connection_close; + } + } else { + source = (struct string){0}; + } + + struct string command; + command.data = full_msg.data + offset; + found = 0; + for (size_t i = offset; i < msg_len; i++) { + if (full_msg.data[i] == ' ') { + found = 1; + command.len = i - offset; + offset = i + 1; + while (offset < msg_len && full_msg.data[offset] == ' ') + offset++; + break; + } + } + if (!found) { + command.len = msg_len - offset; + offset = msg_len; + } + + size_t argc = 0; + size_t old_offset = offset; + while (offset < msg_len) { + if (full_msg.data[offset] == ':') { + argc++; + break; + } + + while (offset < msg_len && full_msg.data[offset] != ' ') + offset++; + + argc++; + + while (offset < msg_len && full_msg.data[offset] == ' ') + offset++; + } + offset = old_offset; + + struct string argv[argc]; // TODO: Maybe dynamically allocate this if it exceeds some number that probably shouldn't be put on the stack + for (size_t i = 0; offset < msg_len;) { + if (full_msg.data[offset] == ':') { + argv[i].data = full_msg.data + offset + 1; + argv[i].len = msg_len - offset - 1; + break; + } + + argv[i].data = full_msg.data + offset; + size_t start = offset; + + while (offset < msg_len && full_msg.data[offset] != ' ') + offset++; + + argv[i].len = offset - start; + + while (offset < msg_len && full_msg.data[offset] == ' ') + offset++; + + i++; + } + + WRITES(2, STRING("Source: `")); + WRITES(2, source); + WRITES(2, STRING("'\r\nCommand: `")); + WRITES(2, command); + WRITES(2, STRING("'\r\n")); + if (argc > 0) { + WRITES(2, STRING("Args:\r\n")); + for (size_t i = 0; i < argc; i++) { + WRITES(2, STRING("\t`")); + WRITES(2, argv[i]); + WRITES(2, STRING("'\r\n")); + } + } + + pthread_mutex_lock(&state_lock); + + int (*func)(struct string source, size_t argc, struct string *argv, void *handle, char is_incoming); + if (!ready) + func = get_table_index(inspircd2_protocol_init_commands, command); + else + func = get_table_index(inspircd2_protocol_commands, command); + + if (!func) { + WRITES(2, STRING("WARNING: Command is unknown, ignoring.\r\n\n")); + goto inspircd2_protocol_handle_connection_unlock_next; + } + + int res = func(source, argc, argv, handle, is_incoming); + if (res < 0) // Disconnect + goto inspircd2_protocol_handle_connection_unlock_close; + else if (res > 0) // Connection is now "ready" + ready = 1; + + inspircd2_protocol_handle_connection_unlock_next: + pthread_mutex_unlock(&state_lock); + inspircd2_protocol_handle_connection_next: + memmove(full_msg.data, full_msg.data + msg_len + 1, full_msg.len - msg_len - 1); + full_msg.len -= msg_len + 1; + void *tmp = realloc(full_msg.data, full_msg.len); + if (tmp || full_msg.len == 0) + full_msg.data = tmp; + } + } + + inspircd2_protocol_handle_connection_unlock_close: + pthread_mutex_unlock(&state_lock); + inspircd2_protocol_handle_connection_close: + free(full_msg.data); + + networks[net].close(fd, handle); + free(address.data); + + return 0; +} + +void * inspircd2_protocol_autoconnect(void *tmp) { + struct server_config *config = tmp; + + struct server_connection_info *info; + info = malloc(sizeof(*info)); + if (!info) + return 0; + + struct server_network_info *type; + type = malloc(sizeof(*type)); + if (!type) { + free(info); + return 0; + } + + type->net_type = config->autoconnect_type; + type->protocol = INSPIRCD2_PROTOCOL; + type->is_incoming = 0; + info->type = type; + info->config = config; + + time_t last_time = 0; + while (1) { + for (time_t current = time(NULL); current < last_time + 60; current = time(NULL)) + sleep(60 - (current - last_time)); + last_time = time(NULL); + + info->fd = networks[type->net_type].connect(&(info->handle), config->address, config->port, &(info->address)); + if (info->fd == -1) + continue; + + inspircd2_protocol_handle_connection(info); + } +} + +int inspircd2_protocol_init_handle_server(struct string source, size_t argc, struct string *argv, void *handle, char is_incoming) { + if (argc < 5) { + WRITES(2, STRING("Invalid SERVER recieved! (Missing parameters)\r\n")); + return -1; + } + + if (is_incoming) { + // TODO: set SID + } else { + } + + return 0; +} diff --git a/protocols/inspircd2.h b/protocols/inspircd2.h new file mode 100644 index 0000000..45cac84 --- /dev/null +++ b/protocols/inspircd2.h @@ -0,0 +1,41 @@ +// Written by: Test_User <hax@andrewyu.org> +// +// This is free and unencumbered software released into the public +// domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. +// +// In jurisdictions that recognize copyright laws, the author or authors +// of this software dedicate any and all copyright interest in the +// software to the public domain. We make this dedication for the benefit +// of the public at large and to the detriment of our heirs and +// successors. We intend this dedication to be an overt act of +// relinquishment in perpetuity of all present and future rights to this +// software under copyright law. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#pragma once + +#include <stddef.h> + +#include "../haxstring.h" + +extern struct table inspircd2_protocol_init_commands; +extern struct table inspircd2_protocol_commands; + +int init_inspircd2_protocol(void); + +void * inspircd2_protocol_handle_connection(void *type); +void * inspircd2_protocol_autoconnect(void *type); + +int inspircd2_protocol_init_handle_server(struct string source, size_t argc, struct string *argv, void *handle, char is_incoming); diff --git a/server_network.c b/server_network.c new file mode 100644 index 0000000..aed6a41 --- /dev/null +++ b/server_network.c @@ -0,0 +1,162 @@ +// One of the code files for HaxServ +// +// Written by: Test_User <hax@andrewyu.org> +// +// This is free and unencumbered software released into the public +// domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. +// +// In jurisdictions that recognize copyright laws, the author or authors +// of this software dedicate any and all copyright interest in the +// software to the public domain. We make this dedication for the benefit +// of the public at large and to the detriment of our heirs and +// successors. We intend this dedication to be an overt act of +// relinquishment in perpetuity of all present and future rights to this +// software under copyright law. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#include <arpa/inet.h> +#include <pthread.h> +#include <stdlib.h> +#include <unistd.h> + +#include "config.h" +#include "main.h" +#include "protocols.h" +#include "server_network.h" + +#ifdef USE_PLAINTEXT_SERVER +#include "plaintext_network.h" +#endif +#ifdef USE_GNUTLS_SERVER +#include "gnutls_network.h" +#endif + +int init_server_network(void) { + return 0; +} + +int start_server_network(void) { +#ifdef USE_PLAINTEXT_SERVER + if (start_server_network_threads(NET_TYPE_PLAINTEXT) != 0) + return 1; +#endif +#ifdef USE_GNUTLS_SERVER + if (start_server_network_threads(NET_TYPE_GNUTLS) != 0) + return 1; +#endif +#ifdef USE_OPENSSL_SERVER + if (start_server_network_threads(NET_TYPE_OPENSSL) != 0) + return 1; +#endif + + pthread_t trash; + for (size_t i = 0; i < server_config_len; i++) { + if (server_config[i].autoconnect) { + if (pthread_create(&trash, &pthread_attr, protocols[server_config[i].protocol].autoconnect, &(server_config[i])) != 0) { + return 1; + } + } + } + + return 0; +} + +int start_server_network_threads(size_t net) { + pthread_t trash; // Not actually used, so discard + struct server_network_info *type; +#ifdef USE_INSPIRCD2_PROTOCOL + type = malloc(sizeof(*type)); + if (!type) + return 1; + type->net_type = net; + type->protocol = INSPIRCD2_PROTOCOL; + type->is_incoming = 1; + if (pthread_create(&trash, &pthread_attr, server_accept_thread, type) != 0) { + free(type); + return 1; + } +#endif + return 0; +} + +void * server_accept_thread(void *type) { + size_t net; + size_t protocol; + { + struct server_network_info *t = type; + net = t->net_type; + protocol = t->protocol; + } + + // Check if there is actually an incoming server connection configured using this net+protocol, and if not just return from this thread; some excess may have been spawned + { + char found = 0; + for (size_t i = 0; i < server_config_len; i++) { + if (server_config[i].protocol == protocol && !(server_config[i].autoconnect)) { // TODO: Don't make autoconnect conflict with incoming connections + found = 1; + break; + } + } + if (!found) + return 0; + } + + int listen_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (listen_fd < 0) + return 0; + + { + int one = 1; + setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); + } + + { + struct sockaddr_in sockaddr = { + .sin_family = AF_INET, + }; + + sockaddr.sin_port = htons(SERVER_PORTS[net][protocol]); + size_t listen_number = SERVER_LISTEN[net][protocol]; + + if (bind(listen_fd, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) != 0) + return 0; + + listen(listen_fd, listen_number); + } + + while (1) { + struct string address; + void *con_handle; + int con_fd = networks[net].accept(listen_fd, &con_handle, &address); + if (con_fd == -1) + continue; // TODO: Handle error + + pthread_t trash; + struct server_connection_info *info; + info = malloc(sizeof(*info)); + if (!info) { + networks[net].close(con_fd, con_handle); + continue; + } + info->address = address; + info->type = type; + info->fd = con_fd; + info->handle = con_handle; + if (pthread_create(&trash, &pthread_attr, protocols[protocol].handle_connection, info) != 0) { + free(info); + networks[net].close(con_fd, con_handle); + } + } +} diff --git a/server_network.h b/server_network.h new file mode 100644 index 0000000..b07424d --- /dev/null +++ b/server_network.h @@ -0,0 +1,51 @@ +// Written by: Test_User <hax@andrewyu.org> +// +// This is free and unencumbered software released into the public +// domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. +// +// In jurisdictions that recognize copyright laws, the author or authors +// of this software dedicate any and all copyright interest in the +// software to the public domain. We make this dedication for the benefit +// of the public at large and to the detriment of our heirs and +// successors. We intend this dedication to be an overt act of +// relinquishment in perpetuity of all present and future rights to this +// software under copyright law. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#pragma once + +#include <stddef.h> + +struct server_network_info { + size_t net_type; + size_t protocol; + char is_incoming; +}; + +struct server_connection_info { + struct string address; + struct server_config *config; + struct server_network_info *type; + int fd; + void *handle; +}; + +int init_server_network(void); +int start_server_network(void); +int start_server_network_threads(size_t net); + +void * server_accept_thread(void *type); + +void * handle_server_thread(void *type); @@ -0,0 +1,185 @@ +// My table library thing +// +// Written by: Test_User <hax@andrewyu.org> +// +// This is free and unencumbered software released into the public +// domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. +// +// In jurisdictions that recognize copyright laws, the author or authors +// of this software dedicate any and all copyright interest in the +// software to the public domain. We make this dedication for the benefit +// of the public at large and to the detriment of our heirs and +// successors. We intend this dedication to be an overt act of +// relinquishment in perpetuity of all present and future rights to this +// software under copyright law. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#include <string.h> +#include <errno.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> + +#include "haxstring.h" +#include "table.h" + +// currently going with a binary lookup... + +static inline int compare(struct string a, struct string b) { + size_t len; + if (a.len > b.len) + len = b.len; + else + len = a.len; + + int val = memcmp(a.data, b.data, len); + + if (val == 0 && a.len != b.len) + return 1; + else + return val; +} + +static inline size_t search(struct table tbl, struct string name, char *exists) { + if (tbl.len == 0) { + *exists = 0; + return 0; + } + + size_t low = 0, high = tbl.len - 1; + + size_t mid = high/2; + + while (low != high) { + int val = compare(tbl.array[mid].name, name); + + if (val == 0) { + *exists = 1; + return mid; + } else if (val > 0) { + low = mid + 1; + if (mid > low) + break; + if (low > high) + low = high; + } else { + high = mid - 1; + if (mid < high) + break; + if (high < low) + high = low; + } + + mid = low + ((high-low)/2); + } + + int val = compare(tbl.array[mid].name, name); + if (val > 0) { + *exists = 0; + return mid+1; + } else if (val == 0) { + *exists = 1; + return mid; + } else { + *exists = 0; + return mid; + } +} + +int set_table_index(struct table *tbl, struct string name, void *ptr) { + char exists; + size_t index = search(*tbl, name, &exists); + + if (index == tbl->len) { + void *tmp = realloc(tbl->array, sizeof(*(tbl->array)) * (tbl->len+1)); + if (tmp == 0) + return 1; + + tbl->array = tmp; + + tbl->len++; + } else if (!exists) { + void *tmp = realloc(tbl->array, sizeof(*(tbl->array)) * (tbl->len+1)); + if (tmp == 0) + return 1; + + tbl->array = tmp; + + memmove(&(tbl->array[index+1]), &(tbl->array[index]), (tbl->len - index) * sizeof(*(tbl->array))); + tbl->len++; + } else { + tbl->array[index].ptr = ptr; + + return 0; // don't overwrite old allocated name + } + + char *data = malloc(name.len); + if (data == 0) + return 1; + + memcpy(data, name.data, name.len); + + tbl->array[index] = (struct table_index){{data, name.len}, ptr}; + + return 0; +} + +void * get_table_index(struct table tbl, struct string name) { + char exists; + size_t index = search(tbl, name, &exists); + if (!exists) + return 0; + + return tbl.array[index].ptr; +} + +char has_table_index(struct table tbl, struct string name) { + char exists; + search(tbl, name, &exists); + return exists; +} + +void * remove_table_index(struct table *tbl, struct string name) { + char exists; + size_t index = search(*tbl, name, &exists); + + if (!exists) + return 0; + + void *ptr = tbl->array[index].ptr; + free(tbl->array[index].name.data); + + memmove(&(tbl->array[index]), &(tbl->array[index+1]), (tbl->len - index - 1) * sizeof(*(tbl->array))); + tbl->len--; + + void *tmp = realloc(tbl->array, sizeof(*(tbl->array)) * tbl->len); + if (tmp || (tbl->len == 0)) + tbl->array = tmp; + // else: realloc failed on shrinking... so now we have a table that's allocated a bit too big, not much of an issue + + return ptr; +} + +void clear_table(struct table *tbl) { + for (size_t i = 0; i < tbl->len; i++) + free(tbl->array[i].name.data); + + tbl->array = realloc(tbl->array, 0); + tbl->len = 0; +} + +size_t get_table_offset(struct table tbl, struct string name, char *exists) { + return search(tbl, name, exists); +} @@ -0,0 +1,48 @@ +// Header for my table library thing +// +// Written by: Test_User <hax@andrewyu.org> +// +// This is free and unencumbered software released into the public +// domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. +// +// In jurisdictions that recognize copyright laws, the author or authors +// of this software dedicate any and all copyright interest in the +// software to the public domain. We make this dedication for the benefit +// of the public at large and to the detriment of our heirs and +// successors. We intend this dedication to be an overt act of +// relinquishment in perpetuity of all present and future rights to this +// software under copyright law. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#pragma once + +#include "haxstring.h" + +struct table_index { + struct string name; + void *ptr; +}; + +struct table { + struct table_index *array; + size_t len; +}; + +extern int set_table_index(struct table *tbl, struct string name, void *ptr); +extern void * get_table_index(struct table tbl, struct string name); +extern char has_table_index(struct table tbl, struct string name); +extern void * remove_table_index(struct table *tbl, struct string name); // returns same as get_table_index +extern void clear_table(struct table *tbl); +extern size_t get_table_offset(struct table tbl, struct string name, char *exists); |