summaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
authorAndrei Karas <akaras@inbox.ru>2018-11-06 19:49:46 +0300
committerAndrei Karas <akaras@inbox.ru>2018-11-14 06:00:50 +0300
commit25abd43600a693a47acd755b5713b342de86a7ca (patch)
tree543ab08adc6c25287de398df13c484b32e9cae19 /src/common
parent172f8c8ac189e1f6590324eb0aca14cffdba3083 (diff)
downloadhercules-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.c56
-rw-r--r--src/common/socket.h9
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);