From 49890421f8c7873f9fbf5be873141525ffede609 Mon Sep 17 00:00:00 2001 From: Mloc-Argent Date: Tue, 4 Mar 2014 10:08:17 +0000 Subject: [PATCH] Adds a C library alternative to the ircbot nudge script. This allows for more secure and stable transmission on Linux, but you might see some improvements on Windows too. Code lies in (confusingly) lib/src. nudge.c should be compiled to lib/nudge.[dll/so] and be linked against netutil.c. There's some horribly hacky code in nudge.c to assemble pickled data, but it's probably the fastest way that's still safe. Signed-off-by: Mloc-Argent --- code/controllers/configuration.dm | 5 +- code/modules/ext_scripts/irc.dm | 11 +- config/example/config.txt | 4 + {DLLSocket => lib/DLLSocket}/DLLSocket.cbp | 0 {DLLSocket => lib/DLLSocket}/compile.sh | 0 {DLLSocket => lib/DLLSocket}/main.cpp | 0 .../DLLSocket}/server_controller.py | 0 lib/src/netutil.c | 109 ++++++++++++++++++ lib/src/netutil.h | 33 ++++++ lib/src/nudge.c | 73 ++++++++++++ 10 files changed, 233 insertions(+), 2 deletions(-) rename {DLLSocket => lib/DLLSocket}/DLLSocket.cbp (100%) rename {DLLSocket => lib/DLLSocket}/compile.sh (100%) rename {DLLSocket => lib/DLLSocket}/main.cpp (100%) rename {DLLSocket => lib/DLLSocket}/server_controller.py (100%) create mode 100644 lib/src/netutil.c create mode 100644 lib/src/netutil.h create mode 100644 lib/src/nudge.c diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm index 8df9836f32f..e96323c6584 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -139,7 +139,7 @@ var/main_irc = "" var/admin_irc = "" var/python_path = "" //Path to the python executable. Defaults to "python" on windows and "/usr/bin/env python2" on unix - + var/use_lib_nudge = 0 //Use the C library nudge instead of the python nudge. /datum/configuration/New() var/list/L = typesof(/datum/game_mode) - /datum/game_mode @@ -474,6 +474,9 @@ else //probably windows, if not this should work anyway config.python_path = "python" + if("use_lib_nudge") + config.use_lib_nudge = 1 + if("allow_cult_ghostwriter") config.cult_ghostwriter = 1 diff --git a/code/modules/ext_scripts/irc.dm b/code/modules/ext_scripts/irc.dm index 3976904efb6..fc8910d79f6 100644 --- a/code/modules/ext_scripts/irc.dm +++ b/code/modules/ext_scripts/irc.dm @@ -1,6 +1,15 @@ /proc/send2irc(var/channel, var/msg) if(config.use_irc_bot && config.irc_bot_host) - ext_python("ircbot_message.py", "[config.comms_password] [config.irc_bot_host] [channel] [msg]") + if(config.use_lib_nudge) + var/nudge_lib + if(world.system_type == MS_WINDOWS) + nudge_lib = "lib\\nudge.dll" + else + nudge_lib = "lib/nudge.so" + + call(nudge_lib, "nudge")("[config.comms_password]","[config.irc_bot_host]","[channel]","[msg]") + else + ext_python("ircbot_message.py", "[config.comms_password] [config.irc_bot_host] [channel] [msg]") return /proc/send2mainirc(var/msg) diff --git a/config/example/config.txt b/config/example/config.txt index 28a803d8e7b..300c23d34f1 100644 --- a/config/example/config.txt +++ b/config/example/config.txt @@ -242,6 +242,10 @@ USEALIENWHITELIST ## Default is "python" on Windows, "/usr/bin/env python2" on UNIX. #PYTHON_PATH +## Uncomment to use the C library nudge instead of the python script. +## This helps security and stability on Linux, but you need to compile the library first. +#USE_LIB_NUDGE + ## Uncommen to allow ghosts to write in blood during Cult rounds. ALLOW_CULT_GHOSTWRITER diff --git a/DLLSocket/DLLSocket.cbp b/lib/DLLSocket/DLLSocket.cbp similarity index 100% rename from DLLSocket/DLLSocket.cbp rename to lib/DLLSocket/DLLSocket.cbp diff --git a/DLLSocket/compile.sh b/lib/DLLSocket/compile.sh similarity index 100% rename from DLLSocket/compile.sh rename to lib/DLLSocket/compile.sh diff --git a/DLLSocket/main.cpp b/lib/DLLSocket/main.cpp similarity index 100% rename from DLLSocket/main.cpp rename to lib/DLLSocket/main.cpp diff --git a/DLLSocket/server_controller.py b/lib/DLLSocket/server_controller.py similarity index 100% rename from DLLSocket/server_controller.py rename to lib/DLLSocket/server_controller.py diff --git a/lib/src/netutil.c b/lib/src/netutil.c new file mode 100644 index 00000000000..4028e89b5e0 --- /dev/null +++ b/lib/src/netutil.c @@ -0,0 +1,109 @@ +#include "netutil.h" +#include "string.h" + +int net_ready = 0; +void net_init() +{ + #ifdef _WIN32 + WSADATA wsa; + WSAStartup(MAKEWORD(2,0),&wsa); + #endif + net_ready = 1; +} + +socket_t connect_sock(char * host, char * port) +{ + if(!net_ready) + { + net_init(); + } + + socket_t out_sock = -1; + struct addrinfo addr_in; + struct addrinfo * addr_proc; + int gai_status; + + memset(&addr_in, 0, sizeof(addr_in)); + + addr_in.ai_family = AF_UNSPEC; + addr_in.ai_socktype = SOCK_STREAM; + addr_in.ai_flags = AI_PASSIVE; + + gai_status = getaddrinfo(host, port, &addr_in, &addr_proc); + + if(gai_status) + { + return -1; + } + + struct addrinfo * ai_p; + for(ai_p = addr_proc; ai_p != 0; ai_p = ai_p->ai_next) + { + out_sock = socket(ai_p->ai_family, ai_p->ai_socktype, + ai_p->ai_protocol); + + if((int)out_sock == -1) + { + continue; + } + else if(connect(out_sock, ai_p->ai_addr, ai_p->ai_addrlen) == -1) + { + close_socket(out_sock); + continue; + } + else + { + break; + } + } + + if(!out_sock) + { + freeaddrinfo(addr_proc); + return -1; + } + + freeaddrinfo(addr_proc); + return out_sock; +} + +void send_n(socket_t sock, const char * buf, size_t n) +{ + size_t to_send = n; + const char * buf_i = buf; + while(to_send) + { + int sent = send(sock, buf_i, to_send, 0); + if(sent != -1) + { + to_send -= sent; + buf_i += sent; + } + else + { + return; + } + } + return; +} + +void recv_n(socket_t sock, char * buf, size_t n) +{ + size_t total = 0; + char * buf_i = buf; + while(total < n) + { + int recved = recv(sock, buf_i, n - total, 0); + if(recved > 0) + { + total += recved; + buf_i += recved; + } + else + { + return; + } + } + return; +} + diff --git a/lib/src/netutil.h b/lib/src/netutil.h new file mode 100644 index 00000000000..6e97b1e3fab --- /dev/null +++ b/lib/src/netutil.h @@ -0,0 +1,33 @@ +#ifndef NETUTIL_H +#define NETUTIL_H + +#ifdef _WIN32 + +#include +#include +typedef SOCKET socket_t; + +#define close_socket(sock) closesocket(sock) + +#else + +#include +#include +#include +#include +typedef int socket_t; + +#define close_socket(sock) close(sock) + +#endif + +extern int net_ready; +void init_net(); + +socket_t connect_sock(char * host, char * port); + +void send_n(socket_t sock, const char * buf, size_t n); +void recv_n(socket_t sock, char * buf, size_t n); + +#endif + diff --git a/lib/src/nudge.c b/lib/src/nudge.c new file mode 100644 index 00000000000..90aa85fb5ec --- /dev/null +++ b/lib/src/nudge.c @@ -0,0 +1,73 @@ +#include +#include +#include + +#include "netutil.h" + +#ifdef _WIN32 + #define DLL_EXPORT __declspec(dllexport) +#else + #define DLL_EXPORT __attribute__ ((visibility ("default"))) +#endif + +size_t san_c(const char * input) +{ + unsigned int count = strlen(input); + + const char * i; + for(i = input; *i; i++) + { + if(*i == '\\' || *i == '\'') + { + count++; + } + } + + return count; +} + +char * san_cpy(char * out_buf, const char * in_buf) +{ + const char * i_in = in_buf; + char * i_out = out_buf; + while(*i_in) + { + if(*i_in == '\\' || *i_in == '\'') + { + *(i_out++) = '\\'; + } + *(i_out++) = *(i_in++); + } + return i_out; +} + +DLL_EXPORT const char * nudge(int n, char *v[]) +{ + if(n != 4) + { + return ""; + } + + size_t out_c = san_c(v[0]) + san_c(v[2]) + san_c(v[3]); + + char * san_out = malloc(out_c + 56); + + char * san_i = san_out; + strcpy(san_i, "(dp1\nS'ip'\np2\nS'"); + san_i += 16; + san_i = san_cpy(san_i, v[2]); + strcpy(san_i, "'\np3\nsS'data'\np4\n(lp5\nS'"); + san_i += 24; + san_i = san_cpy(san_i, v[0]); + strcpy(san_i, "'\np6\naS'"); + san_i += 8; + san_i = san_cpy(san_i, v[3]); + strcpy(san_i, "'\np7\nas."); + + socket_t nudge_sock = connect_sock(v[1], "45678"); + send_n(nudge_sock, san_out, out_c + 56); + close_socket(nudge_sock); + + return "1"; +} +