From 2bdbca1e885af9504d8ec7322e1efd7623b5bd97 Mon Sep 17 00:00:00 2001 From: Jonas Gunz Date: Wed, 30 Sep 2020 21:02:12 +0200 Subject: initial --- .gitignore | 2 ++ Makefile | 39 +++++++++++++++++++++++++ src/main.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/rcon.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/rcon.h | 41 ++++++++++++++++++++++++++ 5 files changed, 262 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 src/main.c create mode 100644 src/rcon.c create mode 100644 src/rcon.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..722a501 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +build/ +obj/ diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..3c18490 --- /dev/null +++ b/Makefile @@ -0,0 +1,39 @@ +CC = clang +CFLAGS = -Wall +LDFLAGS = +BUILDDIR = build +SOURCEDIR = src +OBJECTDIR = obj + +OUTPUT = program + +SRCS = $(wildcard $(SOURCEDIR)/*.c) +OBJS = $(SRCS:.c=.o) +OBJ = $(OBJS:$(SOURCEDIR)/%=$(OBJECTDIR)/%) + +build: dir $(OBJ) + @echo LD $(OBJ) + @$(CC) $(CFLAGS) -o $(BUILDDIR)/$(OUTPUT) $(OBJ) $(LDFLAGS) + +debug: CFLAGS += -g -D _DEBUG +debug: build; + +dir: + @mkdir -p $(OBJECTDIR) + @mkdir -p $(BUILDDIR) + +$(OBJECTDIR)/%.o: $(SOURCEDIR)/%.c + @echo CC $< + @$(CC) $(CFLAGS) -c $< -o $@ + +.PHONY: clean +clean: + @echo RM $(OBJ) + @echo RM $(BUILDDIR)/$(OUTPUT) + @rm -df $(OBJ) + @rm -Rdf $(BUILDDIR) $(OBJECTDIR) + +all: clean build + +run: build + @$(BUILDDIR)/$(OUTPUT) diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..c4cc3a1 --- /dev/null +++ b/src/main.c @@ -0,0 +1,83 @@ +/* + * src/main.c + * (c) 2020 Jonas Gunz + * License: +*/ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "rcon.h" + +typedef struct program_params_s { + char* host; + char* port; + char* password; + char* command; +} program_params_t; + +program_params_t parse_args ( int argc, char* argv[] ); + +int main( int argc, char* argv[] ) { + program_params_t args = parse_args( argc, argv ); + + int sock = -1; + int ret = 0; + struct addrinfo hints, *result, *iter; + char recvbuf [ RCON_RECV_PKGSIZE ]; + char sendbuf [ RCON_SEND_PKGSIZE ]; + + memset ( &hints, 0, sizeof( struct addrinfo ) ); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + ret = getaddrinfo ( args.host, args.port, &hints, &result ); + if ( ret ) { + fprintf ( stderr, "getaddrinfo: %s\n", gai_strerror(ret) ); + exit ( EXIT_FAILURE ); + } + + for ( iter = result; iter != NULL; iter = iter->ai_next ) { + sock = socket( result->ai_family, result->ai_socktype, result->ai_protocol ); + if ( socket < 0 ) + continue; + + if ( connect ( sock, iter->ai_addr, iter->ai_addrlen ) != -1 ) + break; + + close (sock); + } + + if ( ! iter ) { + fprintf ( stderr, "Connection failed.\n" ); + exit ( EXIT_FAILURE ); + } + + fprintf ( stderr, "Connection successful.\n" ); + + rcon_packet_t pack = {0,1337,RCON_LOGIN,args.password, strlen(args.password)}, rcon_result; + + ret = send ( sock, sendbuf, ret, 0 ); + + ret = recv ( sock, recvbuf, RCON_RECV_PKGSIZE, 0); + rcon_parse_packet ( &rcon_result, recvbuf, ret ); + + close (sock); + + //printf("%s\n%s", sendbuf, recvbuf); + + return 0; +} + +program_params_t parse_args ( int argc, char* argv[] ) { + program_params_t ret = { "127.0.0.1", "25575", "1234", "list" }; + return ret; +} diff --git a/src/rcon.c b/src/rcon.c new file mode 100644 index 0000000..a302d12 --- /dev/null +++ b/src/rcon.c @@ -0,0 +1,97 @@ +/* + * src/rcon.c + * (c) 2020 Jonas Gunz + * License: +*/ + +/* + * Length int Length of remainder of packet + * Request ID int Client-generated ID + * Type int 3 for login, 2 to run a command, 0 for a multi-packet response + * Payload byte[] ASCII text + * 2-byte pad byte^2 Two null bytes + * + * sizeof int: 4B + * Little Endian + * + * LOGIN 3 + * LOGINFAIL -1 + * COMMAND 2 + * RESPONSE 0 + */ + +#include "rcon.h" + +static char* rcon_errors[] = { + "No Error.", + "Undefined Error.", + "Login Denied.", + "Buffer size incorrect.", + "Malformed packet recieved." +}; + +static int rcon_write_int ( char* _buffer, int _len, int32_t _data ) { + if ( _len < 4 ) + return -1; + + for (int i = 0; i < 4; i++) + _buffer[i] = (char)(_data >> (i*8)); + + return 4; +} + +static int rcon_read_int ( char* _buffer, int _len, int32_t* _out ) { + if ( _len < 4 ) + return -1; + + *_out = 0; + for (int i = 0; i < 4; i++) + *_out |= (int32_t)((int32_t)_buffer[i] << (i*8)); + + return 4; +} + +int rcon_parse_packet ( rcon_packet_t* _packet, char* _buffer, uint32_t _len ) { + if ( _len < 14 ) + return -1; + + int32_t bytecount = 0; + + bytecount += rcon_read_int ( _buffer + bytecount, _len - bytecount, &_packet->length ); + bytecount += rcon_read_int ( _buffer + bytecount, _len - bytecount, &_packet->id ); + bytecount += rcon_read_int ( _buffer + bytecount, _len - bytecount, &_packet->type ); + + int32_t payload_len = _len - bytecount - 2; + _packet->payload_len = payload_len; + _packet->payload = malloc(payload_len); + memcpy ( _packet->payload, _buffer + bytecount, payload_len ); + bytecount += payload_len; + + bytecount += 2; // padding + //TODO check validity + return bytecount; +} + +int rcon_construct_packet ( char* _buffer, uint32_t _len, rcon_packet_t* _packet ) { + if ( _len < RCON_SEND_PKGSIZE ) + return -1; // Payload does not fit. + + int32_t bytecount = 0; + _packet->length = _packet->payload_len + 10; + + bytecount += rcon_write_int ( _buffer + bytecount, _len - bytecount, _packet->length ); + bytecount += rcon_write_int ( _buffer + bytecount, _len - bytecount, _packet->id ); + bytecount += rcon_write_int ( _buffer + bytecount, _len - bytecount, _packet->type ); + + memcpy ( _buffer + bytecount, _packet->payload, _packet->payload_len ); + bytecount += _packet->payload_len; + + memcpy ( _buffer + bytecount, "\0\0", 2); + bytecount += 2; + + return bytecount; +} + +char* rcon_strerror ( int _errno ) { + return _errno > 4 ? rcon_errors[1] : rcon_errors[_errno]; +} diff --git a/src/rcon.h b/src/rcon.h new file mode 100644 index 0000000..474fcdd --- /dev/null +++ b/src/rcon.h @@ -0,0 +1,41 @@ +/* + * src/rcon.h + * (c) 2020 Jonas Gunz + * License: +*/ + +/* + * Length int Length of remainder of packet + * Request ID int Client-generated ID + * Type int 3 for login, 2 to run a command, 0 for a multi-packet response + * Payload byte[] ASCII text + * 2-byte pad byte^2 Two null bytes + * + * sizeof int: 4B + * */ + +#include +#include +#include + +#define RCON_LOGIN 3 +#define RCON_LOLGINFAIL -1 +#define RCON_COMMAND 2 +#define RCON_RESPONSE 0 + +#define RCON_RECV_PKGSIZE 4110 +#define RCON_SEND_PKGSIZE 1460 + +typedef struct rcon_packet_s { + int32_t length; + int32_t id; + int32_t type; + char* payload; + uint32_t payload_len; +} rcon_packet_t; + +int rcon_parse_packet ( rcon_packet_t* _packet, char* _buffer, uint32_t _len ); + +int rcon_construct_packet ( char* _buffer, uint32_t _len, rcon_packet_t* _packet ); + +char* rcon_strerror ( int _errno ); -- cgit v1.2.3