PDA

View Full Version : Sending server commands to the clients



Mitch
21st November 2013, 22:32
I have been trying to sent rcon status to a client. It works, but when you do this your server can't receive and send any packets.
(I also got a problem with converting the port correctly. That is why i am converting a ip+port to net address.)



case 1203:
{
#if COD_VERSION == COD2_1_3
typedef enum {
NA_BOT,
NA_BAD, // an address lookup failed
NA_LOOPBACK,
NA_BROADCAST,
NA_IP,
NA_IPX,
NA_BROADCAST_IPX
} netadrtype_t;

typedef struct {
netadrtype_t type;

char ip[4];
char ipx[10];

unsigned short port;
} netadr_t;

typedef struct {
bool allowoverflow; // if false, do a Com_Error
bool overflowed; // set to true if the buffer size failed (with allowoverflow set)
bool oob; // set to true if the buffer size failed (with allowoverflow set)
char *data;
int maxsize;
int cursize;
int readcount;
int bit; // for bitwise reads and writes
} msg_t;

char *cmd;
int clientNum;
int helper = 0;
helper += stackGetParamString(1, &cmd); // todo: is string?
helper += stackGetParamInt(2, &clientNum);

if (helper < 2)
{
printf_hide("scriptengine> wrongs args for: SV_ConnectionlessPacket(): at least 2 arg\n");
return stackReturnInt(0);
}

char * ip = (char *)malloc(64);
snprintf(ip, 64, "%s", "ip:port");
netadr_t * from;
void (*NET_StringToAdr)( const char *s, netadr_t *a );
(*(int *)&NET_StringToAdr) = 0x0806CD98;
NET_StringToAdr(ip, from);

char *message = (char *)malloc(1024);
message[0] = -1;
message[1] = -1;
message[2] = -1;
message[3] = -1;
message[4] = 0;

strcat (message, cmd);

printf("Message: %s\n", message);

msg_t * msg;
msg->data = message;
msg->maxsize = 131072;
msg->cursize = strlen(msg->data)+1;
msg->readcount = 0;
msg->allowoverflow = false;
msg->overflowed = false;
msg->oob = false;
msg->bit = 0;

netadr_t adr = *from;

void (*SV_ConnectionlessPacket)( netadr_t from, msg_t * msg );
(*(int *)&SV_ConnectionlessPacket) = 0x0809594E;
SV_ConnectionlessPacket(adr, msg);

return stackPushInt(1);
#else
return stackPushInt(0);
#endif
}


My function hook


short ShortSwap (short l)
{
char b1,b2;

b1 = l&255;
b2 = (l>>8)&255;

return (b1<<8) + b2;
}

const char *NET_AdrToString (netadr_t a)
{
static char s[64];

if (a.type == NA_LOOPBACK) {
strcpy(s, "loopback");
} else if (a.type == NA_BOT) {
strcpy(s, "bot");
} else if (a.type == NA_IP) {
sprintf(s, "%d.%d.%d.%d:%d", (unsigned char)a.ip[0], (unsigned char)a.ip[1], (unsigned char)a.ip[2], (unsigned char)a.ip[3], ShortSwap(a.port));
} else {
sprintf(s, "%ix%ix%ix%i.%ix%ix%ix%ix%ix%ix:%hu",
(unsigned char)a.ipx[0], (unsigned char)a.ipx[1], (unsigned char)a.ipx[2], (unsigned char)a.ipx[3], (unsigned char)a.ipx[4], (unsigned char)a.ipx[5], (unsigned char)a.ipx[6], (unsigned char)a.ipx[7], (unsigned char)a.ipx[8], (unsigned char)a.ipx[9],ShortSwap(a.port));
}

return s;
}

void hook_ServerCommand( netadr_t from, msg_t *msg )
{
char * d = msg->data;

const char * (*NET_AdrToString)( netadr_t a );
(*(int *)&NET_AdrToString) = 0x0806B1D4; // this one works better than my own version

printf("From %s\n", NET_AdrToString (from) );
//printf("Max size: %d\n", msg->maxsize);
//printf("Read count: %d\n", msg->readcount);
//printf("Cur size: %d\n", msg->cursize);
//printf("Bit: %d\n", msg->bit);
//printf("Ood: %d\n", msg->oob);
//printf("allowoverflow: %d\n", msg->allowoverflow);
//printf("overflowed: %d\n", msg->overflowed);
strncpy(d, &d[4], msg->cursize);
printf("Data: %s\n", msg->data);
}

cracking_hook_function(0x08097188, (int)hook_ServerCommand); // SVC_RemoteCommand
cracking_hook_function(0x0809594E, (int)hook_ServerCommand); // SV_ConnectionlessPacket

(all the function addresses are for cod2 1.3)

Printing your own message in console doesn't work either. (same result)


char * ip = (char *)malloc(64);
snprintf(ip, 64, "%s", "ip:28960");
printf("IP: %s\n", ip);

char *message = (char *)malloc(1024);
snprintf(message, 1008, "print\n%s", msg);

printf("Message: %s\n", message);

netadr_t * from;
void (*NET_StringToAdr)( const char *s, netadr_t *a );
(*(int *)&NET_StringToAdr) = 0x0806CD98;
NET_StringToAdr(ip, from);

const char * (*NET_AdrToString)( netadr_t a );
(*(int *)&NET_AdrToString) = 0x0806B1D4; // this one works better than my own version

printf("From %s\n", NET_AdrToString (*from) );

void (*NET_OutOfBandPrint)( netsrc_t sock, netadr_t adr, const char *msg );
(*(int *)&NET_OutOfBandPrint) = 0x0806C8CC;
NET_OutOfBandPrint(NS_SERVER, *from, message);

Ni3ls
11th December 2014, 20:19
Sorry for the bump, but why do you want to do that?

IzNoGoD
11th December 2014, 20:40
Might be unrelated: If you put a servercmd in the callback_playercommand BEFORE calling the player playercmd() function, the actual function the player was executing gets overwritten and replaced by the servercommand, which would thus allow for menu-free execclientcmd() :)

Might be worth looking into next :)

Mitch
11th December 2014, 21:32
Sorry for the bump, but why do you want to do that?

To print messages like rcon status to a player's console. (instead of using self iprintln("message") )
But i never could get it working without breaking the server.

Like ! commands with rcon without a password: !rcon status (for admins)


Might be unrelated: If you put a servercmd in the callback_playercommand BEFORE calling the player playercmd() function, the actual function the player was executing gets overwritten and replaced by the servercommand, which would thus allow for menu-free execclientcmd() :)

Might be worth looking into next :)

I will look into it when i have time for it.

Edit:
SV_ExecuteClientCommand
SV_ClientCommand
https://github.com/id-Software/Quake-III-Arena/blob/master/code/server/sv_client.c