diff options
Diffstat (limited to 'src/common/socket.c')
-rw-r--r-- | src/common/socket.c | 134 |
1 files changed, 102 insertions, 32 deletions
diff --git a/src/common/socket.c b/src/common/socket.c index 290c7a1b3..95d8bf578 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" @@ -301,10 +302,8 @@ static uint32 send_shortlist_set[(FD_SETSIZE+31)/32];// to know if specific fd's static int create_session(int fd, RecvFunc func_recv, SendFunc func_send, ParseFunc func_parse); -#ifndef MINICORE - static int ip_rules = 1; - static int connect_check(uint32 ip); -#endif // MINICORE +static int ip_rules = 1; +static int connect_check(uint32 ip); static const char *error_msg(void) { @@ -556,12 +555,10 @@ static int connect_client(int listen_fd) setsocketopts(fd,NULL); sockt->set_nonblocking(fd, 1); -#ifndef MINICORE if( ip_rules && !connect_check(ntohl(client_address.sin_addr.s_addr)) ) { sockt->close(fd); return -1; } -#endif // MINICORE #ifndef SOCKET_EPOLL // Select Based Event Dispatcher @@ -584,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; } @@ -653,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; } @@ -814,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; @@ -825,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; @@ -871,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; @@ -881,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); @@ -893,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 @@ -1065,9 +1102,6 @@ static int do_sockets(int next) return 0; } -////////////////////////////// -#ifndef MINICORE -////////////////////////////// // IP rules and DDoS protection struct connect_history { @@ -1326,11 +1360,6 @@ static bool access_list_add(struct config_setting_t *setting, const char *list_n return true; } -////////////////////////////// -#endif // MINICORE -////////////////////////////// - -#ifndef MINICORE /** * Reads 'socket_configuration/ip_rules' and initializes required variables. * @@ -1387,9 +1416,7 @@ static bool socket_config_read_iprules(const char *filename, struct config_t *co return true; } -#endif // ! MINICORE -#ifndef MINICORE /** * Reads 'socket_configuration/ddos' and initializes required variables. * @@ -1419,7 +1446,6 @@ static bool socket_config_read_ddos(const char *filename, struct config_t *confi return true; } -#endif // ! MINICORE /** * Reads 'socket_configuration' and initializes required variables. @@ -1464,7 +1490,6 @@ static bool socket_config_read(const char *filename, bool imported) } #endif // SOCKET_EPOLL -#ifndef MINICORE { uint32 ui32 = 0; libconfig->setting_lookup_bool(setting, "debug", &access_debug); @@ -1477,7 +1502,6 @@ static bool socket_config_read(const char *filename, bool imported) retval = false; if (!socket_config_read_ddos(filename, &config, imported)) retval = false; -#endif // MINICORE // import should overwrite any previous configuration, so it should be called last if (libconfig->lookup_string(&config, "import", &import) == CONFIG_TRUE) { @@ -1496,12 +1520,10 @@ static bool socket_config_read(const char *filename, bool imported) static void socket_final(void) { int i; -#ifndef MINICORE if( connect_history ) db_destroy(connect_history); VECTOR_CLEAR(access_allow); VECTOR_CLEAR(access_deny); -#endif // MINICORE for( i = 1; i < sockt->fd_max; i++ ) if(sockt->session[i]) @@ -1686,10 +1708,8 @@ static void socket_init(void) } #endif // defined(HAVE_SETRLIMIT) && !defined(CYGWIN) -#ifndef MINICORE VECTOR_INIT(access_allow); VECTOR_INIT(access_deny); -#endif // ! MINICORE // Get initial local ips sockt->naddr_ = sockt->getips(sockt->addr_,16); @@ -1729,12 +1749,10 @@ static void socket_init(void) // should hold enough buffer (it is a vacuum so to speak) as it is never flushed. [Skotlex] create_session(0, null_recv, null_send, null_parse); -#ifndef MINICORE // Delete old connection history every 5 minutes connect_history = uidb_alloc(DB_OPT_RELEASE_DATA); timer->add_func_list(connect_check_clear, "connect_check_clear"); timer->add_interval(timer->gettick()+1000, connect_check_clear, 0, 0, 5*60*1000); -#endif // MINICORE ShowInfo("Server supports up to '"CL_WHITE"%"PRIu64""CL_RESET"' concurrent connections.\n", rlim_cur); } @@ -1818,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); @@ -2072,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 < (uint32)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; @@ -2083,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); @@ -2100,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; /* */ @@ -2122,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; } |