Created
December 9, 2017 11:26
-
-
Save pihril/7aa490915b4cd3b3a3105eb85fa97bc0 to your computer and use it in GitHub Desktop.
rcon.c
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 <stdio.h> | |
#include <stdlib.h> | |
#include <sys/socket.h> | |
#include <sys/types.h> | |
#include <netinet/in.h> | |
#include <arpa/inet.h> | |
#include <errno.h> | |
#include <string.h> | |
#define DEBUG 0 | |
#define SERVERDATA_EXECCOMMAND 2 | |
#define SERVERDATA_AUTH 3 | |
#define SERVERDATA_RESPONSE_VALUE 0 | |
#define SERVERDATA_AUTH_RESPONSE 2 | |
int send_rcon(int sock, int id, int command, char *string1, char *string2) { | |
int size, ret; | |
size = 10+strlen(string1)+strlen(string2); | |
ret = send(sock,&size,sizeof(int),0); | |
if(ret == -1) { | |
perror("send() failed:"); | |
return -1; | |
} | |
ret = send(sock,&id,sizeof(int),0); | |
if(ret == -1) { | |
perror("send() failed:"); | |
return -1; | |
} | |
ret = send(sock,&command,sizeof(int),0); | |
if(ret == -1) { | |
perror("send() failed:"); | |
return -1; | |
} | |
ret = send(sock,string1,strlen(string1)+1,0); | |
if(ret == -1) { | |
perror("send() failed:"); | |
return -1; | |
} | |
ret = send(sock,string2,strlen(string2)+1,0); | |
if(ret == -1) { | |
perror("send() failed:"); | |
return -1; | |
} | |
if(DEBUG) printf("Sent %d bytes\n",size+4); | |
return 0; | |
} | |
int recv_rcon(int sock, int timeout, int *id, int *command, char *string1, | |
char *string2) { | |
struct timeval tv; | |
fd_set readfds; | |
int size; | |
char *ptr; | |
int ret; | |
char buf[8192]; | |
size=0xDEADBEEF; | |
*id=0xDEADBEEF; | |
*command=0xDEADBEEF; | |
string1[0]=0; | |
string2[0]=0; | |
tv.tv_sec = timeout; | |
tv.tv_usec = 0; | |
FD_ZERO(&readfds); | |
FD_SET(sock, &readfds); | |
/* don't care about writefds and exceptfds: */ | |
select(sock+1, &readfds, NULL, NULL, &tv); | |
if (!FD_ISSET(sock, &readfds)) { | |
if(DEBUG) { | |
printf("recv timeout\n"); | |
} | |
return -1; // timeout | |
} | |
if(DEBUG) printf("Got a response\n"); | |
ret = recv(sock, &size, sizeof(int), 0); | |
if(ret == -1) { | |
perror("recv() failed:"); | |
return -1; | |
} | |
if((size<10) || (size>8192)) { | |
printf("Illegal size %d\n",size); | |
exit(-1); | |
} | |
ret = recv(sock, id, sizeof(int),0); | |
if(ret == -1) { | |
perror("recv() failed:"); | |
return -1; | |
} | |
size-=ret; | |
ret = recv(sock, command, sizeof(int),0); | |
if(ret == -1) { | |
perror("recv() failed:"); | |
return -1; | |
} | |
size-=ret; | |
ptr = buf; | |
while(size) { | |
ret = recv(sock, ptr, size, 0); | |
if(ret == -1) { | |
perror("recv() failed:"); | |
return -1; | |
} | |
size -= ret; | |
ptr += ret; | |
} | |
buf[8190] = 0; | |
buf[8191] = 0; | |
strncpy(string1, buf, 4095); | |
string1[4095] = 0; | |
strncpy(string2, buf+strlen(string1)+1, 4095); | |
return 0; | |
} | |
/* This is set to 1 when we've been authorized */ | |
int auth = 0; | |
char string1[4096]; | |
char string2[4096]; | |
int process_response(int sock) { | |
int ret; | |
int id; | |
int command; | |
ret=recv_rcon(sock, 1, &id, &command, string1, string2); | |
if(DEBUG) printf("Received = %d : id=%d, command=%d, s1=%s, s2=%s\n", | |
ret, id, command, string1, string2); | |
if(ret==-1) { | |
return -1; | |
} | |
switch(command) { | |
case SERVERDATA_AUTH_RESPONSE: | |
switch(id) { | |
case 20: | |
auth = 1; | |
break; | |
case -1: | |
printf("Password Refused\n"); | |
return -1; | |
default: | |
printf("Bad Auth Response ID = %d\n",id); | |
exit(-1); | |
}; | |
break; | |
case SERVERDATA_RESPONSE_VALUE: | |
printf("%s",string1); | |
break; | |
default: | |
printf("Unexpected command: %d",command); | |
break; | |
}; | |
} | |
int main(int argc, char **argv) | |
{ | |
struct sockaddr_in a; | |
int sock; | |
int ret, i; | |
char password[512]="YOUR_PASSWORD_HERE"; | |
short port = 27015; | |
char address[512] = "127.0.0.1"; | |
int arg; | |
auth = 0; | |
if(argc<2) | |
{ | |
printf("Syntax: rcon [-P\"rcon_password\"] [-a127.0.0.1] [-p27015] command\n"); | |
return 0; | |
} | |
for(arg = 1;arg<argc;arg++) { | |
if(argv[arg][0] != '-') | |
break; /* done with args */ | |
switch(argv[arg][1]) { | |
case 'a': | |
strncpy(address, argv[arg]+2, 512); | |
break; | |
case 'p': | |
port = atoi(argv[arg]+2); | |
break; | |
case 'P': | |
strncpy(password, argv[arg]+2, 512); | |
break; | |
default: | |
fprintf(stderr, "Unknown option -%c\n",argv[arg][1]); | |
return 0; | |
} | |
} | |
a.sin_family = AF_INET; | |
a.sin_addr.s_addr = inet_addr(address); | |
a.sin_port = htons(port); | |
sock = socket(AF_INET, SOCK_STREAM,0); // TCP socket | |
ret = 0; | |
ret = connect(sock,(struct sockaddr *)&a,sizeof(a)); | |
if(ret == -1) { | |
perror("connect() failed."); | |
return -1; | |
} else { | |
if(DEBUG) printf("Connected to Server\n"); | |
} | |
if(DEBUG) printf("Sending RCON Password\n"); | |
ret=send_rcon(sock, 20, SERVERDATA_AUTH, password, ""); | |
if(ret == -1) { | |
perror("Sending password"); | |
return -1; | |
}; | |
while(auth==0) { | |
if(process_response(sock)==-1) { | |
printf("Couldn't Authenticate\n"); | |
exit(-1); | |
} | |
} | |
if(DEBUG) printf("Password Accepted\n"); | |
/* Now we're authorized, send command */ | |
/* built command */ | |
ret = 0; | |
while(arg < argc) { | |
if(strlen(argv[arg]) + ret < 4096) { | |
strcpy(string1+ret, argv[arg]); | |
ret += strlen(argv[arg]); | |
string1[ret] = ' '; | |
ret++; | |
arg++; | |
} else { | |
fprintf(stderr, "cmd too long to send\n"); | |
return -1; | |
} | |
} | |
// string1[ret] = '\n'; | |
//ret++; | |
ret--; | |
string1[ret]=0; | |
if(DEBUG) printf("Sending Command: \"%s\"\n", string1); | |
ret=send_rcon(sock, 20, SERVERDATA_EXECCOMMAND, string1, ""); | |
if(ret == -1) { | |
perror("cmd send"); | |
return -1; | |
} | |
// process responses until a timeout | |
while(process_response(sock) != -1); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment