diff options
Diffstat (limited to 'src/common/socket.c')
-rw-r--r-- | src/common/socket.c | 107 |
1 files changed, 100 insertions, 7 deletions
diff --git a/src/common/socket.c b/src/common/socket.c index fd86414d6..025776172 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; } @@ -810,7 +811,36 @@ static int rfifoskip(int fd, size_t len) if (s->rdata_size < s->rdata_pos + len) { ShowError("RFIFOSKIP: skipped past end of read buffer! Adjusting from %"PRIuS" to %"PRIuS" (session #%d)\n", len, RFIFOREST(fd), fd); + Assert_report(0); len = RFIFOREST(fd); + } else { + const size_t lenRest = RFIFOREST(fd); + if (s->flag.validate == 1 && len == lenRest) { + if (lenRest >= 2) { + const uint32 cmd = (uint32)RFIFOW(fd, 0); + if (cmd < MIN_PACKET_DB || cmd > MAX_PACKET_DB) { + ShowError("Skip wrong packet id: 0x%04X\n", cmd); + Assert_report(0); + } else { + int packet_len = packets->db[cmd]; + if (packet_len == -1) { + if (lenRest < 4) { + ShowError("Skip packet with size smaller than 4\n"); + Assert_report(0); + } else { + packet_len = RFIFOW(fd, 2); + if (packet_len != lenRest) { + ShowError("Skip packet 0x%04X with dynamic size %"PRIuS", but must be size %d\n", cmd, lenRest, packet_len); + Assert_report(0); + } + } + } else if (packet_len != lenRest) { + ShowError("Skip packet 0x%04X with size %"PRIuS", but must be size %d\n", cmd, lenRest, packet_len); + Assert_report(0); + } + } + } + } } s->rdata_pos = s->rdata_pos + len; @@ -821,14 +851,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 +895,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 +909,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); @@ -889,6 +921,15 @@ static int wfifoset(int fd, size_t len) return 0; } +static void wfifohead(int fd, size_t len) +{ + Assert_retv(fd >= 0); + + sockt->session[fd]->last_head_size = (uint32)len; + if (sockt->session[fd]->wdata_size + len > sockt->session[fd]->max_wdata) + sockt->realloc_writefifo(fd, len); +} + static int do_sockets(int next) { #ifndef SOCKET_EPOLL @@ -1795,6 +1836,11 @@ static void socket_datasync(int fd, bool send) { sizeof(struct guild_castle) }, { sizeof(struct fame_list) }, { PACKETVER }, + { PACKETVER_MAIN_NUM }, + { PACKETVER_RE_NUM }, + { PACKETVER_ZERO_NUM }, + { PACKETVER_AD_NUM }, + { PACKETVER_SAK_NUM }, }; unsigned short i; unsigned int alen = ARRAYLENGTH(data_list); @@ -2049,6 +2095,50 @@ 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 uint32 cmd = (uint32)WFIFOW(fd, 0); + const uint32 last_head_size = sockt->session[fd]->last_head_size; + sockt->session[fd]->last_head_size = 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 4\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); + } + if (last_head_size < packet_len) { + ShowError("Reserved too small packet buffer for packet 0x%04X with size %u, but must be size %d\n", cmd, last_head_size, packet_len); + Assert_retv(0); + } +} + void socket_defaults(void) { sockt = &sockt_s; @@ -2060,6 +2150,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); @@ -2077,6 +2168,7 @@ void socket_defaults(void) sockt->realloc_fifo = realloc_fifo; sockt->realloc_writefifo = realloc_writefifo; sockt->wfifoset = wfifoset; + sockt->wfifohead = wfifohead; sockt->rfifoskip = rfifoskip; sockt->close = socket_close; /* */ @@ -2099,4 +2191,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; } |