aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Jonas Gunz <himself@jonasgunz.de> 2020-09-30 21:02:12 +0200
committerGravatar Jonas Gunz <himself@jonasgunz.de> 2020-09-30 21:02:12 +0200
commit2bdbca1e885af9504d8ec7322e1efd7623b5bd97 (patch)
tree494952e54bc538dafa688b42bfd5c5c2967ca15b
downloadminecraft-rcon-2bdbca1e885af9504d8ec7322e1efd7623b5bd97.tar.gz
initial
-rw-r--r--.gitignore2
-rw-r--r--Makefile39
-rw-r--r--src/main.c83
-rw-r--r--src/rcon.c97
-rw-r--r--src/rcon.h41
5 files changed, 262 insertions, 0 deletions
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 <himself@jonasgunz.de>
+ * License:
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <unistd.h>
+
+#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 <himself@jonasgunz.de>
+ * 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 <himself@jonasgunz.de>
+ * 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 <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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 );