diff options
author | Andrei Karas <akaras@inbox.ru> | 2018-11-06 19:49:46 +0300 |
---|---|---|
committer | Andrei Karas <akaras@inbox.ru> | 2018-11-14 06:00:50 +0300 |
commit | 25abd43600a693a47acd755b5713b342de86a7ca (patch) | |
tree | 543ab08adc6c25287de398df13c484b32e9cae19 /src/common | |
parent | 172f8c8ac189e1f6590324eb0aca14cffdba3083 (diff) | |
download | hercules-25abd43600a693a47acd755b5713b342de86a7ca.tar.gz hercules-25abd43600a693a47acd755b5713b342de86a7ca.tar.bz2 hercules-25abd43600a693a47acd755b5713b342de86a7ca.tar.xz hercules-25abd43600a693a47acd755b5713b342de86a7ca.zip |
Add send packet validation for connections between server and clients.
Diffstat (limited to 'src/common')
-rw-r--r-- | src/common/socket.c | 56 | ||||
-rw-r--r-- | src/common/socket.h | 9 |
2 files changed, 56 insertions, 9 deletions
diff --git a/src/common/socket.c b/src/common/socket.c index fd86414d6..5f74ccf2f 100644 --- a/src/common/socket.c +++ b/src/common/socket.c @@ -30,6 +30,7 @@ #include "common/memmgr.h" #include "common/mmo.h" #include "common/nullpo.h" +#include "common/packets.h" #include "common/showmsg.h" #include "common/strlib.h" #include "common/timer.h" @@ -580,6 +581,7 @@ static int connect_client(int listen_fd) create_session(fd, recv_to_fifo, send_from_fifo, default_func_parse); sockt->session[fd]->client_addr = ntohl(client_address.sin_addr.s_addr); + sockt->session[fd]->flag.validate = sockt->validate; return fd; } @@ -649,7 +651,6 @@ static int make_listen_bind(uint32 ip, uint16 port) create_session(fd, connect_client, null_send, null_parse); sockt->session[fd]->client_addr = 0; // just listens sockt->session[fd]->rdata_tick = 0; // disable timeouts on this socket - return fd; } @@ -821,14 +822,12 @@ static int rfifoskip(int fd, size_t len) } /// advance the WFIFO cursor (marking 'len' bytes for sending) -static int wfifoset(int fd, size_t len) +static int wfifoset(int fd, size_t len, bool validate) { - size_t newreserve; - struct socket_data* s; - if (!sockt->session_is_valid(fd)) return 0; - s = sockt->session[fd]; + + struct socket_data* s = sockt->session[fd]; if (s == NULL || s->wdata == NULL) return 0; @@ -867,6 +866,10 @@ static int wfifoset(int fd, size_t len) } } + + if (validate && s->flag.validate == 1) + sockt->validateWfifo(fd, len); + s->wdata_size += len; #ifdef SHOW_SERVER_STATS socket_data_qo += len; @@ -877,7 +880,7 @@ static int wfifoset(int fd, size_t len) // always keep a WFIFO_SIZE reserve in the buffer // For inter-server connections, let the reserve be 1/4th of the link size. - newreserve = s->flag.server ? FIFOSIZE_SERVERLINK / 4 : WFIFO_SIZE; + size_t newreserve = s->flag.server ? FIFOSIZE_SERVERLINK / 4 : WFIFO_SIZE; // readjust the buffer to include the chosen reserve sockt->realloc_writefifo(fd, newreserve); @@ -2049,6 +2052,43 @@ static void socket_net_config_read(const char *filename) return; } +static void socket_validateWfifo(int fd, size_t len) +{ + if (len < 2) { + ShowError("Sent packet with size smaller than 2\n"); + Assert_retv(0); + return; + } + const uint cmd = (uint)WFIFOW(fd, 0); + if (cmd < MIN_PACKET_DB || cmd > MAX_PACKET_DB) { + ShowError("Sent wrong packet id: 0x%04X\n", cmd); + Assert_retv(0); + return; + } + if (len > 65535) { + ShowError("Sent packet with size bigger than 65535\n"); + Assert_retv(0); + return; + } + int packet_len = packets->db[cmd]; + const int len2 = (int)len; + if (packet_len == -1) { + if (len2 < 4) { + ShowError("Sent packet with size smaller than 2\n"); + Assert_retv(0); + return; + } + packet_len = WFIFOW(fd, 2); + if (packet_len != len2) { + ShowError("Sent packet 0x%04X with dynamic size %d, but must be size %d \n", cmd, len2, packet_len); + Assert_retv(0); + } + } else if (packet_len != len2) { + ShowError("Sent packet 0x%04X with size %d, but must be size %d \n", cmd, len2, packet_len); + Assert_retv(0); + } +} + void socket_defaults(void) { sockt = &sockt_s; @@ -2060,6 +2100,7 @@ void socket_defaults(void) /* */ memset(&sockt->addr_, 0, sizeof(sockt->addr_)); sockt->naddr_ = 0; + sockt->validate = false; /* */ VECTOR_INIT(sockt->lan_subnets); VECTOR_INIT(sockt->allowed_ips); @@ -2099,4 +2140,5 @@ void socket_defaults(void) sockt->trusted_ip_check = socket_trusted_ip_check; sockt->net_config_read_sub = socket_net_config_read_sub; sockt->net_config_read = socket_net_config_read; + sockt->validateWfifo = socket_validateWfifo; } diff --git a/src/common/socket.h b/src/common/socket.h index 3c082e718..2d497ebfc 100644 --- a/src/common/socket.h +++ b/src/common/socket.h @@ -73,7 +73,8 @@ struct config_setting_t; } \ } while(0) -#define WFIFOSET(fd, len) (sockt->wfifoset(fd, len)) +#define WFIFOSET(fd, len) (sockt->wfifoset(fd, len, true)) +#define WFIFOSET2(fd, len) (sockt->wfifoset(fd, len, false)) #define RFIFOSKIP(fd, len) (sockt->rfifoskip(fd, len)) /* [Ind/Hercules] */ @@ -122,6 +123,7 @@ struct socket_data { unsigned char eof : 1; unsigned char server : 1; unsigned char ping : 2; + unsigned char validate : 1; } flag; uint32 client_addr; // remote client address @@ -178,9 +180,11 @@ struct socket_interface { /* */ time_t stall_time; time_t last_tick; + /* */ uint32 addr_[16]; // ip addresses of local host (host byte order) int naddr_; // # of ip addresses + bool validate; struct socket_data **session; @@ -200,9 +204,10 @@ struct socket_interface { int (*make_connection) (uint32 ip, uint16 port, struct hSockOpt *opt); int (*realloc_fifo) (int fd, unsigned int rfifo_size, unsigned int wfifo_size); int (*realloc_writefifo) (int fd, size_t addition); - int (*wfifoset) (int fd, size_t len); + int (*wfifoset) (int fd, size_t len, bool validate); int (*rfifoskip) (int fd, size_t len); void (*close) (int fd); + void (*validateWfifo) (int fd, size_t len); /* */ bool (*session_is_valid) (int fd); bool (*session_is_active) (int fd); |