diff --git a/Makefile b/Makefile index d06b199..27a0fe8 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ CC = cc -CFLAGS = -std=c17 +CFLAGS = -std=gnu23 CFLAGS_WARNINGS = -Wall -Wextra CFLAGS_RELEASE = -O2 -fstack-protector-strong -fpie -s CFLAGS_DEBUG = -O0 -ggdb -DDEBUG -fsanitize=address -static-libasan diff --git a/src/main.c b/src/main.c index b86da5f..d132223 100644 --- a/src/main.c +++ b/src/main.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -17,12 +18,22 @@ const char *LOCALHOST = "127.0.0.1"; #define SERVERDATA_RESPONSE_VALUE 0 typedef struct { + // size of the remainder of the packet int32_t size; + // packet id (client sets, server echoes, -1 on auth failure) int32_t id; + // packet type (see the SERVERDATA_* constants) int32_t type; + // null-terminated command string (for auth and exec) or response string (from server) char body[4096]; + // yet another null byte after the body (required by protocol) + uint8_t _padding; } rcon_packet_t; +// Minimum and maximum values for the `size` field of a valid packet. +#define MIN_SIZE (sizeof(int32_t) * 2 + 2) +#define MAX_SIZE (sizeof(rcon_packet_t) - sizeof(int32_t)) + int read_env_int(const char *var) { const char* port_str = getenv(var); if (port_str == NULL) { @@ -72,34 +83,27 @@ int rcon_connect(int port) { } void send_packet(int sockfd, int32_t id, int32_t type, const char *body) { - int body_len = strlen(body); - int32_t size = 10 + body_len; + size_t body_len = strlen(body); - size_t packet_size = sizeof(int32_t) + size; + size_t packet_size = sizeof(int32_t) * 3 + body_len + 2; unsigned char *packet = malloc(packet_size); if (!packet) { perror("malloc failed"); return; } - packet[0] = size & 0xFF; - packet[1] = (size >> 8) & 0xFF; - packet[2] = (size >> 16) & 0xFF; - packet[3] = (size >> 24) & 0xFF; + int32_t size = htole32(packet_size - sizeof(int32_t)); + memcpy(packet, &size, sizeof(int32_t)); - packet[4] = id & 0xFF; - packet[5] = (id >> 8) & 0xFF; - packet[6] = (id >> 16) & 0xFF; - packet[7] = (id >> 24) & 0xFF; + int32_t id_ = htole32(id); + memcpy(packet + 4, &id_, sizeof(int32_t)); - packet[8] = type & 0xFF; - packet[9] = (type >> 8) & 0xFF; - packet[10] = (type >> 16) & 0xFF; - packet[11] = (type >> 24) & 0xFF; + int32_t type_ = htole32(type); + memcpy(packet + 8, &type_, sizeof(int32_t)); memcpy(packet + 12, body, body_len); - packet[12 + body_len] = 0; - packet[12 + body_len + 1] = 0; + packet[3 * sizeof(int32_t) + body_len] = 0; + packet[3 * sizeof(int32_t) + body_len + 1] = 0; ssize_t sent = send(sockfd, packet, packet_size, 0); if (sent < 0) { @@ -123,8 +127,9 @@ int recv_packet(int sockfd, rcon_packet_t *packet) { } return -1; } + packet->size = le32toh(packet->size); - if (packet->size < 10 || packet->size > 4110) { + if (packet->size < (int32_t)MIN_SIZE || packet->size > (int32_t)MAX_SIZE) { fprintf(stderr, "invalid packet size: %d\n", packet->size); return -1; } @@ -134,22 +139,31 @@ int recv_packet(int sockfd, rcon_packet_t *packet) { perror("recv id failed"); return -1; } + packet->id = le32toh(packet->id); bytes = recv(sockfd, &packet->type, sizeof(int32_t), MSG_WAITALL); if (bytes <= 0) { perror("recv type failed"); return -1; } + packet->type = le32toh(packet->type); - int body_size = packet->size - 10; + int body_size = packet->size - sizeof(int32_t) * 2 - 2; if (body_size > 0 && body_size < (int)sizeof(packet->body)) { - bytes = recv(sockfd, packet->body, body_size + 2, MSG_WAITALL); + bytes = recv(sockfd, packet->body, body_size, MSG_WAITALL); if (bytes <= 0) { perror("recv body failed"); return -1; } packet->body[body_size] = '\0'; + + bytes = recv(sockfd, &packet->_padding, 1, MSG_WAITALL); + if (bytes <= 0) { + perror("recv padding failed"); + return -1; + } } else { + packet->size = sizeof(int32_t) * 2 + 2; packet->body[0] = '\0'; }