Last active
August 15, 2017 12:19
-
-
Save MultiMote/169265fd74fe94b44941c1b05b296f0d to your computer and use it in GitHub Desktop.
Battleye RCON c test
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// MultiMote. 2017 | |
// just kidding, really | |
// this is for UDP sockets testing, not a real connector | |
// I will rewrite it for QT | |
#include <stdio.h> | |
#include <stdint.h> | |
#include <conio.h> | |
#include <string.h> | |
#include <pthread.h> | |
#include "crc32.h" | |
#include "socket_utils.h" | |
#define SERVER_IP "" | |
#define PORT 2302 | |
#define PASSWORD "" | |
void append_byte(char** dst, char c) { | |
*(*dst) = c; | |
++(*dst); | |
} | |
void append_str(char** dst, char* src) { | |
while(*src != '\0') { | |
append_byte(dst, *src); | |
++src; | |
} | |
} | |
void append_bytes(char** dst, char* src, char* end) { | |
while(src != end) { | |
append_byte(dst, *src); | |
++src; | |
} | |
} | |
enum be_packet_type { | |
BE_PACKET_LOGIN = 0x00, | |
BE_PACKET_COMMAND = 0x01, | |
BE_PACKET_MESSAGE = 0x02, | |
}; | |
enum packet_handle_retval { | |
RV_RESULT_UNKNOWN = 0x00, | |
RV_LOGIN_OK = 0x01, | |
RV_LOGIN_BAD = 0x02, | |
}; | |
char request[1040]; | |
char cmd[1024]; | |
SOCKET s; | |
struct sockaddr_in si_other; | |
int sockaddr_len = sizeof(si_other); | |
char cmd_sequence_number; | |
char* add_header_to_packet(char* cmd_begin, char* cmd_end) { | |
char* preq = request; | |
append_str(&preq, "BE"); | |
unsigned int crc = crc32(cmd_begin, cmd_end); | |
*((uint32_t*)preq) = crc; | |
preq += 4; | |
append_bytes(&preq, cmd_begin, cmd_end); | |
return preq; | |
} | |
int make_packet(enum be_packet_type type, char* data) { | |
char* pcmd = cmd; | |
append_byte(&pcmd, 0xFF); | |
append_byte(&pcmd, type); | |
switch (type) { | |
case BE_PACKET_LOGIN: | |
cmd_sequence_number = 0; | |
printf("Send login\n"); | |
append_str(&pcmd, PASSWORD); | |
break; | |
case BE_PACKET_MESSAGE: | |
printf("Send ack\n"); | |
append_byte(&pcmd, data[0]); | |
break; | |
case BE_PACKET_COMMAND: | |
printf("Send cmd\n"); | |
append_byte(&pcmd, cmd_sequence_number); | |
append_str(&pcmd, data); | |
break; | |
default: | |
break; | |
} | |
return add_header_to_packet(cmd, pcmd) - request; | |
} | |
void send_to_server(char* data, int len) { | |
if (sendto(s, data, len, 0 , (struct sockaddr *) &si_other, sockaddr_len) == -1) { | |
printf("sendto err()"); | |
} | |
printf("Sent\n"); | |
} | |
void make_and_send_packet(enum be_packet_type type, char* data) { | |
int len = make_packet(type, data); | |
send_to_server(request, len); | |
} | |
char msg[1024]; | |
enum packet_handle_retval handle_packet(char* data, int len) { | |
if(data[0] == 'B' && data[1] == 'E') { | |
// crc check | |
unsigned char packet_type = data[7]; | |
printf("Packet type: 0x%02x\n", packet_type); | |
switch (packet_type) { | |
case BE_PACKET_LOGIN: { | |
char login_result = data[8]; | |
printf("Logged in: %s\n", login_result ? "OK" : "BAD"); | |
return (login_result == 0x01) ? RV_LOGIN_OK : RV_LOGIN_BAD; | |
} | |
case BE_PACKET_MESSAGE: { | |
char* pmsg = msg; | |
append_bytes(&pmsg, data + 9, data + len); | |
append_byte(&pmsg, '\0'); | |
printf("MSG: %s\n", msg); | |
make_and_send_packet(BE_PACKET_MESSAGE, data + 8); // ack | |
break; | |
} | |
case BE_PACKET_COMMAND: { // TODO, BORED | |
break; | |
} | |
default: | |
fprintf(stderr, "Unknown packet ID!"); | |
break; | |
} | |
} else { | |
fprintf(stderr, "Not a BE packet!"); | |
} | |
return RV_RESULT_UNKNOWN; | |
} | |
#define RECV_BUF_LEN 2048 | |
char recv_buf[RECV_BUF_LEN]; | |
void *poll_thread(void* param) { | |
int len = 1; | |
while(len > 0) { | |
len = recvfrom(s, recv_buf, RECV_BUF_LEN, 0, (struct sockaddr *) &si_other, &sockaddr_len); | |
if(len == -1) break; | |
printf("recv len=%d\n", len); | |
handle_packet(recv_buf, len); | |
} | |
printf("Recv error\n"); | |
_socket_close(&s); | |
_sockets_cleanup(); | |
} | |
int main(int argc, char const *argv[]) { | |
pthread_t thread_info; | |
_socket_init(&s); | |
if (s == -1) { | |
printf("Socket error\n"); | |
return 0; | |
} | |
struct hostent *hostname = gethostbyname(SERVER_IP); | |
if(hostname) { | |
memcpy(&si_other.sin_addr, hostname->h_addr_list[0], hostname->h_length); | |
} else { | |
si_other.sin_addr.s_addr = inet_addr(SERVER_IP); | |
} | |
si_other.sin_family = AF_INET; | |
si_other.sin_port = htons(PORT); | |
make_and_send_packet(BE_PACKET_LOGIN, NULL); | |
int len = recvfrom(s, recv_buf, RECV_BUF_LEN, 0, (struct sockaddr *) &si_other, &sockaddr_len); | |
if(handle_packet(recv_buf, len) == RV_LOGIN_OK) { | |
printf("Creating thread\n"); | |
pthread_create(&thread_info, 0, poll_thread, NULL); | |
char c; | |
do { | |
c = getchar(); | |
if(c == 'c') { | |
make_and_send_packet(BE_PACKET_COMMAND, ""); // keepalive | |
} else if(c == 'p') { | |
make_and_send_packet(BE_PACKET_COMMAND, "players"); | |
} | |
} while (c != 'q'); | |
} | |
printf("Goodbye\n"); | |
_socket_close(&s); | |
_sockets_cleanup(); | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "crc32.h" | |
unsigned int crc32(char *begin, char *end) { | |
int j; | |
unsigned int byte, crc, mask; | |
static unsigned int table[256]; | |
/* Set up the table, if necessary. */ | |
if (table[1] == 0) { | |
for (byte = 0; byte <= 255; byte++) { | |
crc = byte; | |
for (j = 7; j >= 0; j--) { // Do eight times. | |
mask = -(crc & 1); | |
crc = (crc >> 1) ^ (0xEDB88320 & mask); | |
} | |
table[byte] = crc; | |
} | |
} | |
/* Through with table setup, now calculate the CRC. */ | |
crc = 0xFFFFFFFF; | |
while (begin != end) { | |
byte = *begin; | |
crc = (crc >> 8) ^ table[(crc ^ byte) & 0xFF]; | |
++begin; | |
} | |
return ~crc; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef __CRC32_H | |
#define __CRC32_H | |
//http://www.hackersdelight.org/hdcodetxt/crc.c.txt | |
/* This is derived from crc32b but does table lookup. First the table | |
itself is calculated, if it has not yet been set up. | |
Not counting the table setup (which would probably be a separate | |
function), when compiled to Cyclops with GCC, this function executes in | |
7 + 13n instructions, where n is the number of bytes in the input | |
message. It should be doable in 4 + 9n instructions. In any case, two | |
of the 13 or 9 instrucions are load byte. | |
This is Figure 14-7 in the text. */ | |
unsigned int crc32(char *begin, char *end); | |
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef SOCKET_UTILS_H | |
#define SOCKET_UTILS_H | |
#ifdef _WIN32 | |
#include <windows.h> | |
#define close_socket(x) closesocket(x) | |
//#define SHUT_RDWR SD_BOTH | |
#define SHUT_RDWR 0x02 | |
#else | |
#include<sys/socket.h> | |
#include<arpa/inet.h> //inet_addr | |
#include<unistd.h> //write | |
#define close_socket(x) close(x) | |
#endif | |
int _socket_init(SOCKET *s) { | |
#ifdef _WIN32 | |
WSADATA wsaData; | |
if (WSAStartup(MAKEWORD(2, 2), &wsaData)) { | |
perror("Unable to init WinSocks!"); | |
return 1; | |
} | |
#endif | |
// int socket(int domain, int type, int protocol); | |
*s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); | |
if (*s == -1) { | |
perror("Unable to init Sockets!"); | |
return 2; | |
} | |
return 0; | |
} | |
int _socket_close(SOCKET *s) { | |
return close_socket(*s); | |
} | |
int _socket_shutdown(SOCKET *s) { | |
return shutdown(*s, SHUT_RDWR); | |
} | |
int _socket_is_invalid(SOCKET *s) { | |
#ifdef _WIN32 | |
return *s == INVALID_SOCKET; | |
#else | |
return *s < 0; | |
#endif | |
} | |
void _sockets_cleanup() { | |
#ifdef _WIN32 | |
WSACleanup(); | |
#endif | |
} | |
#endif // SOCKET_UTILS_H |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment